Post-Submit Pipeline & Checklist

What happens after a theme is submitted, and the checks to run when a theme shows "Coming soon" or "No Preview" in the shop's theme marketplace.


The pipeline

app 10 (kit)        package  → theme.zip (theme/ + screenshots/)
   ↓ submit
app 07 (SA API)     theme_submissions row  (manifest, screenshots[], logo)
   ↓ approve / publish  → fires 3 side effects:
      1. GitHub repository_dispatch "theme-approved"   → app 03 CI
      2. POST /api/v2/theme-market/sync                → app 01
      3. POST /api/v2/theme-market/by-submission/{id}/materialize-seed
   ↓
app 01              market_themes row (status, seed_theme_id, integration_status, logo, price)
   ↓
app 03 CI           themes.lock.json → scripts/integrate-themes.mjs → generated theme registry
                    → POST /api/v2/theme-market/integration-report  (flips integration_status)
   ↓
app 11 dashboard    marketplace card (Purchase / Coming soon / No Preview)

Key files:

Concern File
Availability flag (available) 01-saas-backend/src/modules/theme-market/theme-market.service.ts (isAvailable)
Submission → market_themes mirror 01-saas-backend/src/modules/theme-market/theme-sync.service.ts (syncNow)
Seed / template shop 01-saas-backend/src/modules/theme-market/theme-seed.service.ts (materializeSeed)
Approve side-effects 07-super-admin-api/src/modules/theme-submission/theme-submission.service.ts (updateThemeStatus)
Screenshot/thumbnail extraction 07-super-admin-api/src/modules/theme-submission/theme-asset-extractor.service.ts
Storefront theme registry (generated) 03-saas-frontend/scripts/integrate-themes.mjs, src/themes/config.ts, manifest.generated.ts, widget-maps.generated.ts
Marketplace card 11-shop-dashboard/src/components/themes/theme-card.tsx

Checklist

1. Before submit (theme kit)

  • theme.config.json declares: json "thumbnail": "./screenshots/thumbnail.png", "screenshots": { "desktop": "./screenshots/desktop.png", "tablet": "./screenshots/tablet.png", "mobile": "./screenshots/mobile.png", "dark": "./screenshots/dark-mode.png" } thumbnail is the marketplace card image. Without it (and without a logo on the submission form) the card renders "No Preview". The other screenshots are review-only today — sync does not copy them.
  • Screenshot files are real images, non-empty (0-byte placeholders are skipped).
  • Custom widget dirs namespaced x-<slug>-* — a mismatch fails the storefront build and the theme stays "Coming soon".
  • npm run validatenpm run buildnpm run package.
  • Confirm dist/theme.zip contains a theme/ dir and a screenshots/ dir.
  • Bump version and add a changelog entry (drives the dashboard "update available" badge).

2. Approve in super admin (app 08/07)

  • Publish/approve the submission. This auto-triggers CI dispatch + app-01 sync + materialize-seed.
  • Confirm the marketplace price: PATCH /api/v2/theme-market/by-submission/:submissionId/price. Sync only seeds price from the developer's proposed price on first insert; afterwards price is super-admin-owned.

3. Verify the app-01 row (this row decides the card state)

SELECT slug, status, integration_status, seed_theme_id, logo, price
FROM market_themes WHERE slug = '<slug>';
Column Required Symptom if wrong
status published Theme not listed at all
seed_theme_id NOT NULL Coming soon (materialize-seed never ran)
integration_status integrated Coming soon (app-03 CI never built/reported)
logo non-empty, contains / and . No Preview card image

available = false (→ "Coming soon", Purchase disabled, purchase API 400s) when seed_theme_id IS NULL, or file_url is set and integration_status != 'integrated'.

4. Storefront integration (app 03) — the step that is easy to miss

Copying the theme folder into src/themes/ by hand does nothing: the theme registry is generated from themes.lock.json, and only the CI report flips integration_status.

cd applications/03-saas-frontend

# 1. refresh the lock from app 01 (approved themes with a package)
curl -H "x-internal-token: $INTERNAL_PROXY_TOKEN" \
     "$API/api/v2/theme-market/integration-lock" -o themes.lock.json

# 2. download + validate + extract each theme, regenerate the registry
node scripts/integrate-themes.mjs

# 3. report the outcome back → flips integration_status to integrated/build_failed
curl -X POST -H "x-internal-token: $INTERNAL_PROXY_TOKEN" \
     -H 'Content-Type: application/json' \
     -d @scripts/integrate-themes-report.json \
     "$API/api/v2/theme-market/integration-report"

Then restart/redeploy app 03. Check src/themes/config.ts — the slug must be in registeredThemes.

Failures are quarantined and listed in scripts/integrate-themes-report.json (failed[].error), e.g.:

  • zip does not contain a theme/ directory
  • widget dirs must be namespaced x-<slug>-*: …

5. Final acceptance (app 11 + storefront)

  • Marketplace card: image shown, Purchase button enabled (not "Coming soon").
  • Preview opens.
  • Purchase → Set Active → storefront renders the theme: home, product page, category, cart, checkout.
  • Theme update (new version): dashboard shows the "update available" badge with the changelog.

Quick triage

Symptom Cause Fix
Coming soon integration_status = pending_build Run step 4 (app-03 integrate + report)
Coming soon seed_theme_id IS NULL POST /api/v2/theme-market/by-submission/:id/materialize-seed
Coming soon after CI integration_status = build_failed Read failed[].error in the report, fix the zip, resubmit
No Preview image market_themes.logo empty Ship screenshots/thumbnail.png (or set a logo on the submission), resubmit, re-approve → sync updates logo
Not listed status = unpublished Publish in super admin, then sync
Wrong price Price is super-admin-owned after first sync PATCH /theme-market/by-submission/:id/price