Onboarding live apps without owner questions for what the stores and the code prove: storebound onboard imports the live products and subscriptions with USD / base prices (catalog diff clean), contact values, the App Review contact and demo account (credentials.json, masked), sign-in for review from Apple's review detail and auth code, and the account deletion page from the app's site; App Store keywords count characters (live fields up to 265 bytes accepted); validate accepts the 6.5-inch iPhone set and Play's default-language graphics fallback; Play Reporting API off gives the project's enable link and apps list falls back to local apps; accounts default <profile>; store-only apps (apps add --store --app-id) shown read-only in the desktop (pitfalls 43-52)

This commit is contained in:
CRTkafa 2026-10-13 07:25:01 +08:00
parent d2ce185441
commit e5f148e534
55 changed files with 1648 additions and 158 deletions

View file

@ -169,10 +169,10 @@ export function nextActions(a: AsoAudit, i: AuditInput): Action[] {
const err = f.find(x => x.level === 'error');
if (err) out.push({ what: `fix ${err.where}: ${err.msg}`, why: 'App Store Connect refuses the keyword field as it is', command: 'storebound check --aso' });
if (a.drafts.length) out.push({ what: `review the draft keywords of ${a.drafts.join(', ')} in store/appstore.md and delete the draft line`, why: 'they were proposed by aso suggest, not reviewed yet' });
const room = f.find(x => /bytes used; fill/.test(x.msg));
if (room) out.push({ what: `fill the keyword field of ${room.where.replace('apple ', '')} (${room.msg.replace(/^keywords: /, '')})`, why: 'unused bytes are unused search reach', command: `storebound aso suggest --locale ${room.where.replace('apple ', '')}` });
const room = f.find(x => /characters used; fill/.test(x.msg));
if (room) out.push({ what: `fill the keyword field of ${room.where.replace('apple ', '')} (${room.msg.replace(/^keywords: /, '')})`, why: 'unused characters are unused search reach', command: `storebound aso suggest --locale ${room.where.replace('apple ', '')}` });
const rep = f.find(x => /repeat words from the name/.test(x.msg));
if (rep) out.push({ what: `${rep.where}: replace the words the name / subtitle already index (${rep.msg.split(': ').at(-1)})`, why: 'they take bytes without adding reach', command: `storebound aso suggest --locale ${rep.where.replace('apple ', '')}` });
if (rep) out.push({ what: `${rep.where}: replace the words the name / subtitle already index (${rep.msg.split(': ').at(-1)})`, why: 'they take characters without adding reach', command: `storebound aso suggest --locale ${rep.where.replace('apple ', '')}` });
const gap = a.competitors.gaps.find(g => g.gaps.length);
if (gap) out.push({ what: `consider "${gap.gaps.slice(0, 3).map(g => g.word).join('", "')}" for ${gap.locale} (in the names of ${gap.gaps[0]!.developers} developers' top apps, not in your name / subtitle / keywords)`, why: 'words the top apps lead with; only if they describe your app', command: `storebound aso suggest --locale ${gap.locale}` });
const lost = a.ranks.rows.filter(r => r.arrow === '↓' || r.arrow === 'lost');