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.jsondeclares:json "thumbnail": "./screenshots/thumbnail.png", "screenshots": { "desktop": "./screenshots/desktop.png", "tablet": "./screenshots/tablet.png", "mobile": "./screenshots/mobile.png", "dark": "./screenshots/dark-mode.png" }thumbnailis 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 validate→npm run build→npm run package.- Confirm
dist/theme.zipcontains atheme/dir and ascreenshots/dir. - Bump
versionand add achangelogentry (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/ directorywidget 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 |