Skip to content

feat(store-screenshots): add App Store / Google Play screenshot workspace (phase 1) - #6463

Closed
sucaifenxiang wants to merge 41 commits into
nexu-io:mainfrom
sucaifenxiang:feature/store-screenshot-phase1
Closed

feat(store-screenshots): add App Store / Google Play screenshot workspace (phase 1)#6463
sucaifenxiang wants to merge 41 commits into
nexu-io:mainfrom
sucaifenxiang:feature/store-screenshot-phase1

Conversation

@sucaifenxiang

Copy link
Copy Markdown
Contributor

Why

Launch Studio needs a focused workspace for producing App Store / Google Play
phone-screenshot listings. Today the flow is manual: designers compose each
frame in a graphics tool, then export and resize per platform. This PR ships
the first phase of a dedicated store-screenshot project type that turns the
product brief, real screenshots, logo, and brand assets into a 4-page minimal
document, then lets the user generate, fine-edit, version, and export the
result — with a fully manual fallback when no AI provider is configured.

What users will see

  • New project creation path with intent: store-screenshot: after creation the
    project initializes a 4-page store document (minimal-center template).
  • A store-screenshot workspace with App Store / Google Play platform tabs,
    per-page cards, fine-edit headline/body fields, changes review dialog,
    version history, and ZIP export.
  • od CLI surface: od project reads the same store-screenshot metadata; the
    daemon exposes /api/projects/:id/store-screenshots (create/read/update,
    assets, generate job, render, export).
  • Manual mode works without a provider; generation is gated on a configured
    BYOK provider and fails closed with a clear message otherwise.

Surface area

  • UI — store-screenshot workspace, platform tabs, editor, review dialog, version history
  • CLI / env var — store-screenshot project metadata flows through od project and daemon routes
  • API / contract — new /api/projects/:id/store-screenshots endpoints and StoreScreenshotDocumentResponse contract
  • Extension pointdesign-templates/store-screenshots template assets
  • i18n keys — store-screenshot strings added with English fallback across locales
  • New top-level dependency — workspace package packages/store-screenshot; app-level deps: fabric, jszip, pngjs, sharp (no root package.json change)

Acceptance status

  • macOS desktop smoke: done
  • Manual (no-provider) path: verified in e2e
  • Real-AI generation path: blocked by provider account quota (see
    specs/current/launch-studio-store-screenshot-acceptance.md 复跑记录 2026-08-05);
    harness and evidence are ready for rerun once quota is restored.

Screenshots

Pending — workspace entry-point screenshots will be attached once the real-AI
path can be exercised end-to-end.

…nshot-phase1

# Conflicts:
#	apps/daemon/src/db.ts
#	apps/daemon/src/server-context.ts
#	apps/web/src/components/ProjectView.tsx
#	apps/web/src/i18n/locales/ar.ts
#	apps/web/src/i18n/locales/de.ts
#	apps/web/src/i18n/locales/es-ES.ts
#	apps/web/src/i18n/locales/fa.ts
#	apps/web/src/i18n/locales/fr.ts
#	apps/web/src/i18n/locales/hu.ts
#	apps/web/src/i18n/locales/id.ts
#	apps/web/src/i18n/locales/it.ts
#	apps/web/src/i18n/locales/ko.ts
#	apps/web/src/i18n/locales/pl.ts
#	apps/web/src/i18n/locales/pt-BR.ts
#	apps/web/src/i18n/locales/ru.ts
#	apps/web/src/i18n/locales/th.ts
#	apps/web/src/i18n/locales/tr.ts
#	apps/web/src/i18n/locales/uk.ts
#	apps/web/src/i18n/locales/zh-TW.ts
#	apps/web/src/state/projects.ts
#	apps/web/tests/state/projects.test.ts
#	pnpm-lock.yaml
@lefarcen

lefarcen commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Thanks @sucaifenxiang — this is a substantial new surface across daemon, web, contracts, templates, and e2e. Since it's opened as a draft, we'll hold off on code review until it's ready for review.

💡 To drive this PR to merge hands-free, paste this to your AI coding agent (Claude Code / Codex / opencode / Cursor …):
Take over nexu-io/open-design#6463 until it merges — read https://raw.githubusercontent.com/nexu-io/looper/main/skills/pr-takeover/SKILL.md and follow it.

@lefarcen
lefarcen requested a review from PerishCode August 5, 2026 10:17
@lefarcen lefarcen added size/XXL PR changes 1500+ lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/feature New feature needs-product-review Feature PR awaiting product sign-off before merge (see roadmap) needs-design-review Awaiting design review (external UI change); cleared by the Odcrew App applying design-approved labels Aug 5, 2026
@sucaifenxiang
sucaifenxiang marked this pull request as ready for review August 5, 2026 14:17
@sucaifenxiang
sucaifenxiang requested a review from a team as a code owner August 5, 2026 14:17
@sucaifenxiang

Copy link
Copy Markdown
Contributor Author

Marked ready for review. The branch is synced onto the latest main (6bb829ab, includes the workspace-team merge and subsequent fixes) with no conflicts; daemon + web typecheck and the focused store-screenshot test files (8 files, 135 tests) pass. Requesting review.

@lefarcen

lefarcen commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Hey @sucaifenxiang, thanks for rebasing this onto the latest main and marking it ready for review.

🧪 This PR changes a real user-facing workflow across project creation, the store-screenshot workspace, daemon routes, and export/generation paths, so it will need a manual QA pass before merge. Please hold off self-merging for now; we'll loop QA in once it's merge-ready and product/design have signed off.

@lefarcen lefarcen added the needs-validation Runtime change detected; needs human or /explore agent validation. label Aug 5, 2026

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This phase-one workspace has blocking gaps in the project authority boundary, the required asset-input flow, and the export renderer. The new focused suites otherwise cover a substantial amount of the API, persistence, CLI, and UI behavior, but the renderer determinism test also fails reproducibly on this head.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

if (
typeof projectId !== 'string'
|| !projectId
|| !ctx.projectStore.getProject(ctx.db, projectId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Route these endpoints through the authoritative project access gate, not a raw row-existence check. requireProject only proves that the id exists in local SQLite; unlike the project data-plane routes, it never calls the injected authorizeProjectRequest/workspace authority seam. As a result, every new read route and every local-request mutation can access a Workspace-bound project without verifying that the asserted member still owns or may mutate it. The web client compounds this by sending none of the workspaceProjectHeaders used by the rest of the project surface. Please inject the shared project authorization dependency here, apply read versus mutation capability checks to all store-screenshot routes, and thread the active Workspace context through the web API calls (with route tests for wrong workspace, revoked membership, and non-owner mutation).

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

<Select
aria-label={t('storeScreenshots.productScreenshot')}
value={page.screenshotAssetId ?? ''}
disabled={locks.has('screenshot') || document.assets.length === 0}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the product-screenshot upload action to the shipped workspace before relying on this selector. Every newly created document starts with assets: [], this control is therefore disabled, and no component in apps/web/src/features/store-screenshots calls the new multipart asset endpoint. That means a UI user cannot satisfy the phase-one acceptance requirement to upload and reference real screenshots (or a logo); the Playwright test hides the gap by uploading through page.request before opening the page. Please expose a file input/drop action backed by the shared API helper, refresh the returned document/version after upload, provide the corresponding logo assignment if logo is in phase-one scope, and change the UI test to perform the upload through the visible entry point.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

? `<rect x="${number(width * 0.1)}" y="${number(height * 0.07)}" width="${number(width * 0.2)}" height="${number(height * 0.035)}" fill="${escapeXml(accent)}" rx="${number(width * 0.0175)}"/>`
: '';

return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">${backgroundSvg}${labelSvg}<text x="${number(headlineX)}" y="${number(height * 0.17)}" fill="${escapeXml(text)}" font-size="${number(headlineSize)}" text-anchor="${headlineAnchor}">${escapeXml(page.headline)}</text>${bodySvg}${screenshot}</svg>`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use one bounded text-layout rule for the editor and exported image. The editor renders headline/body as Fabric IText with an 80% width, but this export emits each value as one unbounded SVG <text> node; the contract also puts no useful length limit on generated or manually entered copy. A headline or body that wraps in fine-edit can therefore run off the exported canvas as a single line, so the reviewed preview does not represent the durable ZIP output. Please implement shared line breaking/line-height/max-line behavior (or an equivalent bounded SVG layout) and add renderer fixtures for long Latin text, CJK text, and explicit newlines that assert the pixels remain within the intended text box and match the editor's layout decisions.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

const derivedPage = deriveStoreScreenshotPage(document, pageId, platform);
const svg = compileStoreScreenshotSvg(derivedPage);
const composites = await assetComposites(document, pageId, platform, options);
const pipeline = sharp(Buffer.from(svg));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make rasterization deterministic in the supported fontless/headless environment before shipping the hash-bearing export contract. On this head, the focused renderer suite fails reproducibly at both renders deterministic ... PNGs cases: two sequential calls for the same document/platform produce different buffers, alongside Fontconfig error: Cannot load default config file. This makes the manifest SHA and ZIP bytes depend on host font discovery and leaves a newly added required test red. Please bundle/register a known font (or convert text through a deterministic owned layout path) before passing the SVG to Sharp, then verify apps/daemon/tests/store-screenshot-renderer.test.ts passes in a clean environment without system fontconfig; keep the byte-equality assertions as the acceptance signal.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen

lefarcen commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for getting this onto the latest main and into review.

@PerishCode's blocking review already covers the actionable gaps on this head, especially the project authority boundary, the missing in-product asset upload flow, and the renderer/export mismatches. Once those threads are addressed, could you also add a short ## Validation section to the PR body with the exact commands/suites you ran? The current Acceptance status is helpful; this just makes the verification step explicit for the review template.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-design-review Awaiting design review (external UI change); cleared by the Odcrew App applying design-approved needs-product-review Feature PR awaiting product sign-off before merge (see roadmap) needs-validation Runtime change detected; needs human or /explore agent validation. risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/XXL PR changes 1500+ lines type/feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants