fimo 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/astro/components/DateTime.astro +22 -0
- package/assets/astro/components/index.d.ts +1 -0
- package/assets/astro/components/index.js +1 -0
- package/assets/content-templates/shared/types.eta +2 -0
- package/assets/skills/fimo-cli/SKILL.md +8 -6
- package/assets/skills/fimo-cli/references/branches.md +2 -2
- package/assets/skills/fimo-cli/references/content.md +2 -2
- package/assets/skills/fimo-cli/references/deploy.md +17 -9
- package/assets/skills/fimo-cli/references/hosting.md +114 -0
- package/assets/skills/fimo-cli/references/init.md +13 -6
- package/assets/skills/fimo-cli/references/integrations/firecrawl.md +2 -0
- package/assets/skills/fimo-cli/references/locales.md +38 -14
- package/assets/skills/fimo-cli/references/pages.md +70 -0
- package/assets/skills/fimo-cli/references/preview.md +26 -20
- package/assets/skills/fimo-cli/references/webhooks.md +1 -1
- package/assets/skills/fimo-code/SKILL.md +11 -0
- package/assets/skills/fimo-code/assets/react-router-locales/LocaleLayout.tsx +12 -0
- package/assets/skills/fimo-code/assets/react-router-locales/routes.ts +7 -6
- package/assets/skills/fimo-code/references/best-practices/astro.md +47 -0
- package/assets/skills/fimo-code/references/best-practices/next.md +42 -0
- package/assets/skills/fimo-code/references/best-practices/sveltekit.md +17 -0
- package/assets/skills/fimo-code/references/content/richtext.md +5 -0
- package/assets/skills/fimo-code/references/content/schema.md +4 -1
- package/assets/skills/fimo-code/references/frameworks/astro.md +5 -3
- package/assets/skills/fimo-code/references/frameworks/hosting.md +5 -2
- package/assets/skills/fimo-code/references/frameworks/next/app-router.md +6 -0
- package/assets/skills/fimo-code/references/frameworks/next/locales.md +12 -2
- package/assets/skills/fimo-code/references/frameworks/next.md +7 -0
- package/assets/skills/fimo-code/references/frameworks/react-router.md +15 -7
- package/assets/skills/fimo-code/references/frameworks/sveltekit.md +15 -8
- package/assets/skills/fimo-code/references/labels.md +9 -1
- package/assets/skills/fimo-code/references/locales.md +8 -2
- package/assets/skills/fimo-code/references/migrations/react-router-route-ownership.md +93 -0
- package/assets/skills/fimo-code/references/ui.md +21 -2
- package/assets/skills/fimo-migration/SKILL.md +276 -51
- package/assets/skills/fimo-migration/references/content.md +119 -35
- package/assets/skills/fimo-migration/references/decision.md +72 -0
- package/assets/skills/fimo-migration/references/forms.md +38 -6
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +179 -23
- package/assets/skills/fimo-migration/references/import-contract.md +71 -19
- package/assets/skills/fimo-migration/references/manifest.md +11 -161
- package/assets/skills/fimo-migration/references/media.md +33 -1
- package/assets/skills/fimo-migration/references/platforms.md +26 -2
- package/assets/skills/fimo-migration/references/qa.md +167 -13
- package/assets/skills/fimo-migration/references/workers/content-execution.md +39 -0
- package/assets/skills/fimo-migration/references/workers/content-planner.md +64 -0
- package/assets/skills/fimo-migration/references/workers/framework.md +37 -0
- package/assets/skills/fimo-migration/references/workers/validator.md +25 -0
- package/assets/skills/fimo-migration/references/workers.md +82 -0
- package/assets/skills/fimo-migration/references/workflow.md +140 -192
- package/assets/skills/fimo-migration/scripts/apply-decision.mjs +534 -0
- package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +7 -4
- package/assets/skills/fimo-migration/scripts/write-migration-report.mjs +191 -4
- package/assets/skills/fimo-studio/references/ai-chat.md +1 -1
- package/assets/skills/fimo-studio/references/cms.md +25 -7
- package/assets/skills/fimo-studio/references/webhooks.md +1 -1
- package/assets/sveltekit/components/DateTime.svelte +35 -0
- package/assets/sveltekit/components/FimoProvider.svelte +2 -2
- package/assets/sveltekit/components/index.d.ts +1 -0
- package/assets/sveltekit/components/index.js +1 -0
- package/dist/build/next/config.d.ts +4 -1
- package/dist/build/next/config.js +21 -5
- package/dist/build/sveltekit/vite.d.ts +3 -4
- package/dist/build/sveltekit/vite.js +3 -4
- package/dist/build/vite/plugins/runtime-env.d.ts +2 -1
- package/dist/build/vite/plugins/runtime-env.js +14 -10
- package/dist/cli/bundle.json +2 -2
- package/dist/cli/index.js +113 -108
- package/dist/runtime/app/FimoProviders.js +25 -14
- package/dist/runtime/app/prefetch.d.ts +3 -1
- package/dist/runtime/app/prefetch.js +11 -55
- package/dist/runtime/astro/preview.js +7 -9
- package/dist/runtime/content/client/internal.js +1 -0
- package/dist/runtime/i18n/locale.d.ts +6 -3
- package/dist/runtime/i18n/locale.js +16 -41
- package/dist/runtime/next/client-runtime.js +5 -1
- package/dist/runtime/next/client.d.ts +3 -2
- package/dist/runtime/next/client.js +2 -1
- package/dist/runtime/next/labels.d.ts +2 -2
- package/dist/runtime/next/labels.js +2 -2
- package/dist/runtime/next/preview.d.ts +13 -0
- package/dist/runtime/next/preview.js +34 -0
- package/dist/runtime/next/primitives/server.d.ts +2 -0
- package/dist/runtime/next/primitives/server.js +8 -0
- package/dist/runtime/next/provider.d.ts +5 -0
- package/dist/runtime/next/provider.js +17 -3
- package/dist/runtime/next/server-runtime.js +4 -1
- package/dist/runtime/next/server.d.ts +1 -1
- package/dist/runtime/next/server.js +1 -1
- package/dist/runtime/paths/get-fimo-paths.d.ts +6 -5
- package/dist/runtime/paths/get-fimo-paths.js +43 -42
- package/dist/runtime/preview/location.d.ts +19 -2
- package/dist/runtime/preview/location.js +16 -2
- package/dist/runtime/primitives/index.d.ts +1 -0
- package/dist/runtime/primitives/index.js +1 -0
- package/dist/runtime/react/primitives/editable/DateTime.d.ts +4 -0
- package/dist/runtime/react/primitives/editable/DateTime.js +13 -0
- package/dist/runtime/react/primitives/renderers/DateRenderer.d.ts +7 -1
- package/dist/runtime/react/primitives/renderers/DateRenderer.js +11 -8
- package/dist/runtime/react-router/{routes.d.ts → legacy/routes.d.ts} +6 -1
- package/dist/runtime/react-router/{routes.js → legacy/routes.js} +22 -7
- package/dist/runtime/routes/index.d.ts +162 -0
- package/dist/runtime/routes/index.js +335 -0
- package/dist/runtime/routing/AppRoutesProvider.js +4 -3
- package/dist/runtime/seo/resolver.d.ts +5 -0
- package/dist/runtime/seo/resolver.js +10 -42
- package/dist/runtime/shared/fimo-config.types.d.ts +14 -13
- package/dist/runtime/shared/preview-location.d.ts +1 -22
- package/dist/runtime/shared/preview-location.js +5 -93
- package/dist/runtime/sveltekit/preview.d.ts +12 -3
- package/dist/runtime/sveltekit/preview.js +13 -8
- package/dist/runtime/templates.d.ts +19 -0
- package/dist/runtime/templates.js +33 -0
- package/dist/scripts/sync-forms.js +1 -1
- package/dist/scripts/sync-schemas.js +1 -4
- package/dist/scripts/validate-fimo-config.js +5 -1
- package/dist/scripts/validate-page-registry.d.ts +2 -0
- package/dist/scripts/validate-page-registry.js +167 -0
- package/dist/scripts/validate-route-metadata.js +132 -41
- package/package.json +10 -5
- package/templates/astro/.fimo/config.json +13 -5
- package/templates/astro/AGENTS.md +5 -1
- package/templates/astro/astro.config.mjs +7 -0
- package/templates/astro/pnpm-workspace.yaml +0 -3
- package/templates/astro/src/components/ProjectOverview.astro +9 -6
- package/templates/astro/src/layouts/Base.astro +1 -1
- package/templates/astro/src/locales.ts +4 -0
- package/templates/astro/src/pages/[locale]/index.astro +19 -0
- package/templates/astro/src/pages/[locale]/projects/[slug].astro +35 -0
- package/templates/astro/src/pages/[locale]/projects/index.astro +19 -0
- package/templates/astro/src/pages/index.astro +5 -2
- package/templates/astro/src/pages/projects/[slug].astro +4 -2
- package/templates/astro/src/pages/projects/index.astro +5 -2
- package/templates/nextjs/.fimo/config.json +2 -1
- package/templates/nextjs/AGENTS.md +5 -0
- package/templates/nextjs/src/app/(default)/layout.tsx +10 -0
- package/templates/nextjs/src/app/[locale]/layout.tsx +22 -0
- package/templates/nextjs/src/app/[locale]/page.tsx +1 -0
- package/templates/nextjs/src/components/Document.tsx +26 -0
- package/templates/nextjs/src/components/FimoPreviewBridge.tsx +13 -0
- package/templates/nextjs/src/locales.ts +13 -0
- package/templates/react-router/.fimo/config.json +3 -6
- package/templates/react-router/AGENTS.md +4 -0
- package/templates/react-router/package.json +1 -1
- package/templates/react-router/pnpm-workspace.yaml +1 -3
- package/templates/react-router/react-router.config.ts +4 -10
- package/templates/react-router/src/pages/LocaleLayout.tsx +12 -0
- package/templates/react-router/src/root.tsx +2 -4
- package/templates/react-router/src/routes.ts +5 -3
- package/templates/sveltekit/.fimo/config.json +2 -1
- package/templates/sveltekit/AGENTS.md +5 -0
- package/templates/sveltekit/src/app.html +1 -1
- package/templates/sveltekit/src/hooks.server.ts +11 -0
- package/templates/sveltekit/src/locales.ts +8 -0
- package/templates/sveltekit/src/params/locale.ts +5 -0
- package/templates/sveltekit/src/routes/+layout.server.ts +6 -1
- package/templates/sveltekit/src/routes/+layout.svelte +5 -0
- package/assets/skills/fimo-migration/references/inventory/coordinator.md +0 -40
- package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +0 -39
- package/assets/skills/fimo-migration/references/inventory/locales.md +0 -41
- package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +0 -459
- package/templates/nextjs/src/app/layout.tsx +0 -17
- /package/templates/nextjs/src/app/{page.tsx → (default)/page.tsx} +0 -0
- /package/templates/sveltekit/src/routes/{+page.svelte → [[locale=locale]]/+page.svelte} +0 -0
|
@@ -8,6 +8,13 @@ but it is not complete until the relevant Fimo project contains the imported
|
|
|
8
8
|
assets, schemas, entries, and forms, or the gaps are owner-visible unresolved
|
|
9
9
|
items.
|
|
10
10
|
|
|
11
|
+
Every data-plane write in this contract targets the linked project from
|
|
12
|
+
workflow Phase 0. Local artifacts never require the link — `fimo migrate
|
|
13
|
+
import` only prints the import plan (it writes no data) and warns in an
|
|
14
|
+
unlinked directory — running the printed commands is what needs the link.
|
|
15
|
+
When no owner-supplied target exists, the writes stay unresolved owner
|
|
16
|
+
actions; do not fake a link to make them pass.
|
|
17
|
+
|
|
11
18
|
## Media Files
|
|
12
19
|
|
|
13
20
|
Discovery must include:
|
|
@@ -17,13 +24,17 @@ Discovery must include:
|
|
|
17
24
|
- CMS media fields
|
|
18
25
|
- SEO/share images
|
|
19
26
|
- downloadable files linked from pages or entries
|
|
27
|
+
- every schema media field, including empty or unresolved source values
|
|
28
|
+
- image nodes nested anywhere in richtext or Tiptap payloads
|
|
20
29
|
|
|
21
30
|
Import requirements:
|
|
22
31
|
|
|
23
|
-
- every imported asset records a Fimo target asset ID or URL in
|
|
24
|
-
|
|
32
|
+
- every imported asset records a Fimo target asset ID or URL in the worker and
|
|
33
|
+
migration reports
|
|
25
34
|
- every failed asset has an unresolved item with references to the affected
|
|
26
35
|
route or entry
|
|
36
|
+
- every planner media obligation has an uploaded mapping, an explicit
|
|
37
|
+
unresolved/unsupported disposition, or a proven duplicate mapping
|
|
27
38
|
- CMS media fields are rewritten after upload; source URLs are not left in
|
|
28
39
|
editable entry payloads unless explicitly unresolved
|
|
29
40
|
|
|
@@ -46,10 +57,14 @@ Discovery must include:
|
|
|
46
57
|
|
|
47
58
|
Import requirements:
|
|
48
59
|
|
|
49
|
-
- schemas are pushed before
|
|
60
|
+
- schemas are validated and pushed before media or content writes
|
|
61
|
+
- `fimo schemas push` reconciles an ambiguous 504 by reading every requested
|
|
62
|
+
schema back. A complete match counts as committed; when all are absent it
|
|
63
|
+
retries once; mixed, mismatched, or still-absent state stops for review
|
|
64
|
+
instead of replaying another blind write.
|
|
50
65
|
- entries are created or updated in Fimo, not only written as seed JSON
|
|
51
66
|
- source count, generated count, imported count, skipped count, and unresolved
|
|
52
|
-
count are recorded per content type
|
|
67
|
+
count are recorded per content type in the text plan/report
|
|
53
68
|
- references are resolved in a second pass only when stable IDs or confirmed
|
|
54
69
|
mappings exist
|
|
55
70
|
|
|
@@ -72,32 +87,69 @@ Discovery must include:
|
|
|
72
87
|
|
|
73
88
|
Import requirements:
|
|
74
89
|
|
|
75
|
-
-
|
|
76
|
-
to
|
|
77
|
-
- third-party
|
|
78
|
-
|
|
90
|
+
- a form becomes `src/forms/*.json` and is pushed to Fimo only when the Fimo
|
|
91
|
+
form reproduces the source form's user-visible behavior end to end
|
|
92
|
+
- a third-party form whose behavior is not 1:1 reproducible keeps its original
|
|
93
|
+
integration wired, with the required credential environment keys recorded by
|
|
94
|
+
name (never their values) and any missing secret reported as a user
|
|
95
|
+
follow-up
|
|
96
|
+
- unsupported forms are recorded with source action, reason, and owner action
|
|
79
97
|
- the report records form count, Fimo-native count, third-party count, and
|
|
80
98
|
unsupported/unresolved count
|
|
81
99
|
|
|
82
100
|
Acceptance:
|
|
83
101
|
|
|
84
|
-
- every visible source form is represented by a Fimo form,
|
|
85
|
-
unsupported/unresolved item
|
|
102
|
+
- every visible source form is represented by a Fimo form, a preserved
|
|
103
|
+
third-party integration, or an unsupported/unresolved item
|
|
86
104
|
- no page keeps a broken form UI that appears live
|
|
87
105
|
|
|
106
|
+
Historical form submissions do not have a write contract. The current
|
|
107
|
+
form-submissions CLI is read-only, so never claim that old submissions were
|
|
108
|
+
imported. Preserve the source export and record historical submission import as
|
|
109
|
+
unsupported with an owner action until a dedicated import contract exists.
|
|
110
|
+
|
|
111
|
+
## Pagination And Batching
|
|
112
|
+
|
|
113
|
+
The data-plane commands are paginated and capped. Read the limits instead of
|
|
114
|
+
assuming one request covers everything:
|
|
115
|
+
|
|
116
|
+
- `fimo entries list` and `fimo assets list` return 20 items by default and at
|
|
117
|
+
most 100 per request (`--limit`, `--offset`). The response carries `total`
|
|
118
|
+
and `hasMore`; page until `hasMore` is false before treating a listing as
|
|
119
|
+
complete.
|
|
120
|
+
- `fimo entries bulk-create` chunks at 100 entries by default. Migration data
|
|
121
|
+
workers use `--upsert-by slug`; the identity includes locale, the command
|
|
122
|
+
rereads after an ambiguous 504 before retrying absent entries, and its
|
|
123
|
+
receipt aggregates per-chunk created/updated/conflict counts. Use
|
|
124
|
+
`--chunk-size` only when the transport supports a different bounded size
|
|
125
|
+
(maximum 1,000). `bulk-update` and `bulk-delete` remain capped at 1,000.
|
|
126
|
+
- `fimo labels set-many` sends its whole `--file`/`--data` payload in one
|
|
127
|
+
request; keep one payload per worker batch so a retry replays a bounded set.
|
|
128
|
+
|
|
129
|
+
Listing existing Fimo entries or assets serves idempotency, retry, and fan-in
|
|
130
|
+
reconciliation only - confirming what a rerun must update instead of create.
|
|
131
|
+
The source of the content is always the source tree or export, never a listing
|
|
132
|
+
of what already exists in Fimo.
|
|
133
|
+
|
|
88
134
|
## Minimum Import Loop
|
|
89
135
|
|
|
90
136
|
For each migration, agents should run this loop:
|
|
91
137
|
|
|
92
|
-
1.
|
|
93
|
-
2.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
1. Read the text migration plan and the initialized target.
|
|
139
|
+
2. Have the owning workers define complete schemas/forms and write them through
|
|
140
|
+
the normal Fimo contracts.
|
|
141
|
+
3. Validate and push schemas before dependent content writes.
|
|
142
|
+
4. Upload media.
|
|
143
|
+
5. Import entries, then resolve proven references against stable target IDs.
|
|
144
|
+
6. Update singles and apply labels.
|
|
145
|
+
7. Handle form definitions through their separate supported contract; do not
|
|
146
|
+
import historical submissions.
|
|
147
|
+
8. Write target IDs, counts, failures, and unresolved items into worker and
|
|
148
|
+
migration reports.
|
|
149
|
+
|
|
150
|
+
The data-plane dependency order remains `schemas`, `media`,
|
|
151
|
+
`entries/references`, `singles`, and `labels`. It is a simple execution order,
|
|
152
|
+
not a reason to add another orchestrator.
|
|
101
153
|
|
|
102
154
|
If any step cannot be completed, write an unresolved item immediately with the
|
|
103
155
|
source evidence and owner action needed.
|
|
@@ -1,164 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Legacy migration manifest
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
New migrations do not create a canonical `manifest.json`. The coordinator uses
|
|
4
|
+
the readable `.fimo/migration/migration-plan.md` and
|
|
5
|
+
`.fimo/migration/migration-report.md` instead.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Older URL-only migrations may contain `.fimo/migrations/current/manifest.json`.
|
|
8
|
+
Read it as source evidence when useful, but do not copy it into another
|
|
9
|
+
registry or ask workers to keep it synchronized.
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"mode": "url-only|source-backed|hybrid",
|
|
13
|
-
"platform": "webflow|framer|squarespace|wix|wordpress|carrd|custom|unknown",
|
|
14
|
-
"publicUrl": "https://example.com",
|
|
15
|
-
"rootPath": "../source",
|
|
16
|
-
"inventoryPath": ".fimo/migration/inventory.json",
|
|
17
|
-
"sourceLedgers": []
|
|
18
|
-
},
|
|
19
|
-
"artifacts": {
|
|
20
|
-
"code": [],
|
|
21
|
-
"cms": [],
|
|
22
|
-
"media": [],
|
|
23
|
-
"forms": [],
|
|
24
|
-
"screenshots": [],
|
|
25
|
-
"other": []
|
|
26
|
-
},
|
|
27
|
-
"routes": [],
|
|
28
|
-
"contentTypes": [],
|
|
29
|
-
"entries": [],
|
|
30
|
-
"media": [],
|
|
31
|
-
"forms": [],
|
|
32
|
-
"redirects": [],
|
|
33
|
-
"locales": [],
|
|
34
|
-
"seo": [],
|
|
35
|
-
"unsupported": [],
|
|
36
|
-
"unresolved": [],
|
|
37
|
-
"qa": {
|
|
38
|
-
"status": "not-run|passed|failed|passed-with-unresolved",
|
|
39
|
-
"checks": []
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Required Item Fields
|
|
45
|
-
|
|
46
|
-
Every route, content type, entry batch, media asset, form, redirect, locale, SEO
|
|
47
|
-
item, unsupported item, and unresolved item should include:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"id": "stable-human-readable-id",
|
|
52
|
-
"status": "discovered|planned|generated|imported|verified|ignored|unsupported|unresolved",
|
|
53
|
-
"sourceFiles": [],
|
|
54
|
-
"sourceUrls": [],
|
|
55
|
-
"targetFiles": [],
|
|
56
|
-
"confidence": 1,
|
|
57
|
-
"notes": []
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Use honest confidence. Inferred content from crawled pages is lower confidence
|
|
62
|
-
than first-party CSV/XML/JSON exports.
|
|
63
|
-
|
|
64
|
-
## Content Type Item
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
{
|
|
68
|
-
"id": "blog-post",
|
|
69
|
-
"uid": "BlogPost",
|
|
70
|
-
"name": "Blog Posts",
|
|
71
|
-
"status": "planned",
|
|
72
|
-
"sourceFiles": ["exports/blog.csv"],
|
|
73
|
-
"targetFiles": ["src/schemas/BlogPost.json"],
|
|
74
|
-
"sourceCount": 42,
|
|
75
|
-
"plannedCount": 42,
|
|
76
|
-
"importedCount": 0,
|
|
77
|
-
"fields": {
|
|
78
|
-
"title": { "type": "string", "source": "Name" },
|
|
79
|
-
"body": { "type": "richtext", "source": "Post Body" },
|
|
80
|
-
"coverImage": { "type": "media", "source": "Main Image" },
|
|
81
|
-
"publishedAt": { "type": "datetime", "source": "Published On" }
|
|
82
|
-
},
|
|
83
|
-
"references": []
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
> **Do not put reserved names in `fields`.** `id`, `documentId`, `slug`, `locale`,
|
|
88
|
-
> `createdAt`, `updatedAt`, and `__fimo` are built-in entry metadata — declaring them as
|
|
89
|
-
> schema fields makes `fimo schemas push` fail with a 400. Map a source "Slug" column onto
|
|
90
|
-
> the entry's built-in `slug` (inside `data`) at import time, not onto a schema field.
|
|
91
|
-
|
|
92
|
-
## Entry Batch Item
|
|
93
|
-
|
|
94
|
-
```json
|
|
95
|
-
{
|
|
96
|
-
"id": "blog-post-entries",
|
|
97
|
-
"contentType": "BlogPost",
|
|
98
|
-
"status": "generated",
|
|
99
|
-
"sourceFiles": ["exports/blog.csv"],
|
|
100
|
-
"targetFiles": [".fimo/migration/entries/BlogPost.json"],
|
|
101
|
-
"sourceCount": 42,
|
|
102
|
-
"generatedCount": 42,
|
|
103
|
-
"importedCount": 0,
|
|
104
|
-
"skipped": []
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Media Item
|
|
109
|
-
|
|
110
|
-
```json
|
|
111
|
-
{
|
|
112
|
-
"id": "media-hero-jpg",
|
|
113
|
-
"status": "imported",
|
|
114
|
-
"sourceUrl": "https://example.com/hero.jpg",
|
|
115
|
-
"sourcePath": "assets/hero.jpg",
|
|
116
|
-
"targetAssetId": "asset_123",
|
|
117
|
-
"targetUrl": "https://...",
|
|
118
|
-
"sha256": "optional",
|
|
119
|
-
"contentType": "image/jpeg",
|
|
120
|
-
"bytes": 123456,
|
|
121
|
-
"width": 1600,
|
|
122
|
-
"height": 900,
|
|
123
|
-
"alt": "Hero image",
|
|
124
|
-
"referencedBy": ["route:/", "entry:BlogPost/welcome"],
|
|
125
|
-
"uploadError": null
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Form Item
|
|
130
|
-
|
|
131
|
-
```json
|
|
132
|
-
{
|
|
133
|
-
"id": "contact",
|
|
134
|
-
"name": "contact",
|
|
135
|
-
"status": "generated",
|
|
136
|
-
"classification": "fimo-native|third-party|unsupported",
|
|
137
|
-
"sourceFiles": ["contact.html"],
|
|
138
|
-
"targetFiles": ["src/forms/contact.json"],
|
|
139
|
-
"action": "https://formspree.io/...",
|
|
140
|
-
"method": "post",
|
|
141
|
-
"fields": [],
|
|
142
|
-
"unsupportedReason": null
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Unresolved Item
|
|
147
|
-
|
|
148
|
-
```json
|
|
149
|
-
{
|
|
150
|
-
"id": "mailchimp-newsletter-action",
|
|
151
|
-
"area": "forms",
|
|
152
|
-
"severity": "medium",
|
|
153
|
-
"status": "unresolved",
|
|
154
|
-
"message": "Newsletter form posts to Mailchimp and requires integration credentials.",
|
|
155
|
-
"suggestedAction": "Create a Fimo form or configure a Mailchimp integration with the owner."
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Rules
|
|
160
|
-
|
|
161
|
-
- Prefer stable source IDs over generated IDs.
|
|
162
|
-
- Preserve original field names in `source`; use clean Fimo field IDs in schemas.
|
|
163
|
-
- Never delete unresolved items just to make the report cleaner.
|
|
164
|
-
- Update item statuses as work progresses.
|
|
11
|
+
JSON remains appropriate for actual Fimo artifacts: schema files and the
|
|
12
|
+
content payloads passed to data-plane commands. It is not needed to describe
|
|
13
|
+
worker ownership, target paths, decisions, timings, or QA status. Put those in
|
|
14
|
+
plain-text plans, worker reports, and the final migration report.
|
|
@@ -29,6 +29,22 @@ Record what is available:
|
|
|
29
29
|
- sha256 or another stable hash when possible
|
|
30
30
|
- source references and target references
|
|
31
31
|
|
|
32
|
+
## Alt Text Belongs To The Media
|
|
33
|
+
|
|
34
|
+
Alt text is media metadata, not a content field. An image that has alt text in
|
|
35
|
+
the source never justifies a standalone alt field in a collection or content
|
|
36
|
+
schema; the alt travels with the media value.
|
|
37
|
+
|
|
38
|
+
- Preserve the source alt on the media value alongside `source` and `url`, and
|
|
39
|
+
pass it through the asset upload metadata when the CLI exposes it. When the
|
|
40
|
+
upload command cannot carry it, keep it on the media value and record the
|
|
41
|
+
limitation as a note on the media item.
|
|
42
|
+
- Never use the filename as alt text.
|
|
43
|
+
- When the source has no alt, a meaningful generated alt is an explicit
|
|
44
|
+
fallback only: mark it with the media item's `altSource`
|
|
45
|
+
(`references/manifest.md`) so an editor can see which alt text the source did
|
|
46
|
+
not provide.
|
|
47
|
+
|
|
32
48
|
## Dedupe
|
|
33
49
|
|
|
34
50
|
Deduplicate by hash when local bytes are available. If not, deduplicate by
|
|
@@ -45,7 +61,8 @@ failing. Either upload it (and record the Fimo target), or mark it `unresolved`
|
|
|
45
61
|
with an owner action. "Bundled locally, upload later" is not an acceptable
|
|
46
62
|
terminal state for referenced media.
|
|
47
63
|
|
|
48
|
-
After upload,
|
|
64
|
+
After upload, record the Fimo target asset ID/URL in the worker and migration
|
|
65
|
+
reports.
|
|
49
66
|
|
|
50
67
|
When using downloaded files from a Fimo migration pack, copy the recorded
|
|
51
68
|
`localPath` from the media map exactly. Do not reconstruct local filenames from
|
|
@@ -62,6 +79,11 @@ Replace source references in this order:
|
|
|
62
79
|
Schema media should render through Fimo media primitives. Do not hardcode source
|
|
63
80
|
URLs for editable media fields.
|
|
64
81
|
|
|
82
|
+
The library asset and the media value stored in an entry are distinct concerns:
|
|
83
|
+
the asset owns the uploaded bytes and their metadata, and the entry field holds
|
|
84
|
+
the media value `{ source, url, alt }` that points at it. Keep both carrying the
|
|
85
|
+
same alt text, and do not duplicate alt into a second schema field.
|
|
86
|
+
|
|
65
87
|
## Failure Handling
|
|
66
88
|
|
|
67
89
|
If a media asset cannot be downloaded or uploaded:
|
|
@@ -71,3 +93,13 @@ If a media asset cannot be downloaded or uploaded:
|
|
|
71
93
|
- list every page/entry that references it
|
|
72
94
|
- include a suggested action such as re-exporting the asset folder or providing
|
|
73
95
|
credentials
|
|
96
|
+
|
|
97
|
+
## Planner obligations
|
|
98
|
+
|
|
99
|
+
The content planner enumerates every media obligation before fan-out: route and
|
|
100
|
+
SEO media, every schema media field, and every image node nested in richtext or
|
|
101
|
+
Tiptap JSON. Record its source location, consuming route/entry, and intended
|
|
102
|
+
target field or node. Give each obligation a stable identity that includes its
|
|
103
|
+
field or rich-text node path; a shared label or source URL is not unique. The
|
|
104
|
+
asset worker cannot report complete until every obligation has an uploaded or
|
|
105
|
+
duplicate Fimo mapping, or an explicit unresolved/unsupported disposition.
|
|
@@ -50,5 +50,29 @@ Use these notes to decide what is source of truth and what must be rebuilt.
|
|
|
50
50
|
|
|
51
51
|
- Search for structured data before assuming static content: CSV, JSON, MD/MDX,
|
|
52
52
|
frontmatter, CMS SDK calls, route loaders, API fixtures.
|
|
53
|
-
- Identify the current framework
|
|
54
|
-
|
|
53
|
+
- Identify the current framework to understand routing and data. A source
|
|
54
|
+
repository keeps its framework, router, and runtime for the first migration.
|
|
55
|
+
If detection or hosting compatibility stays unclear, stop and ask. Do not
|
|
56
|
+
select Next.js as a fallback; a conversion happens only after the user's
|
|
57
|
+
explicit choice, through the framework conversion worker and gate in
|
|
58
|
+
`references/workers.md`.
|
|
59
|
+
|
|
60
|
+
## Provider-specific hosting
|
|
61
|
+
|
|
62
|
+
- A provider file is evidence, not disposable scaffolding. Inventory its rules
|
|
63
|
+
and classify each one as preserved, replaced, safely unnecessary
|
|
64
|
+
implementation detail, or unresolved.
|
|
65
|
+
- Preserve the file until its externally observable behavior has an accepted,
|
|
66
|
+
verified replacement. Delete it only when redundancy is proven or the user
|
|
67
|
+
explicitly accepts the loss.
|
|
68
|
+
- Cloudflare cache storage, purge, and revalidation code may be safely
|
|
69
|
+
unnecessary when it has no external caller and no accepted freshness
|
|
70
|
+
contract depends on it. Do not copy provider mechanics merely to imitate the
|
|
71
|
+
implementation.
|
|
72
|
+
- Redirects, security headers, route and 404 behavior, Markdown negotiation,
|
|
73
|
+
feeds, sitemap, `llms.txt`, social metadata, and forms are public behavior.
|
|
74
|
+
Preserve them or replace them with an equivalent and verify the result.
|
|
75
|
+
- A React Router/Vite site can remain React Router/Vite even when Cloudflare-only
|
|
76
|
+
hosting features are conditional or unresolved. Hosting uncertainty is not
|
|
77
|
+
permission to convert the application; only the user's explicit choice
|
|
78
|
+
starts a conversion.
|
|
@@ -1,19 +1,117 @@
|
|
|
1
1
|
# Migration QA Gate
|
|
2
2
|
|
|
3
|
-
Run this gate before reporting completion.
|
|
3
|
+
Run this gate before reporting completion. The gate is read-only: it starts
|
|
4
|
+
only after every other worker has returned a terminal report, and it never
|
|
5
|
+
repairs what it finds — failures become bounded repair tasks or unresolved
|
|
6
|
+
items.
|
|
4
7
|
|
|
5
8
|
## Coverage
|
|
6
9
|
|
|
7
10
|
- Every intended source route is implemented, ignored with a reason, or unresolved.
|
|
11
|
+
- The source route surface is preserved: routes were not restructured to
|
|
12
|
+
shrink the migration, and no group of source pages was replaced by a generic
|
|
13
|
+
static shell.
|
|
14
|
+
- Every imported schema, entry, single, and label has a consuming target route
|
|
15
|
+
or component. Content that exists in Fimo but is not rendered by the
|
|
16
|
+
application is unwired, not covered.
|
|
17
|
+
- Every source content item is represented in the target: a content type, a
|
|
18
|
+
field, a block, a reference, a label, or an explicit unresolved item.
|
|
19
|
+
- The editorial model is Fimo-native and not silently flattened. Structured or
|
|
20
|
+
repeatable editorial sections are blocks, rich bodies are richtext, and
|
|
21
|
+
categories, authors, related items, and repeated taxonomies are references -
|
|
22
|
+
not hardcoded strings, raw IDs, or opaque JSON. Every `json` field carries a
|
|
23
|
+
recorded reason that no Fimo-native model fits.
|
|
24
|
+
- Editable shared chrome (header, footer, navigation, site settings) has a
|
|
25
|
+
singleton or other content model an owner can edit, and labels are limited to
|
|
26
|
+
small UI copy and reusable translations.
|
|
27
|
+
- Content type, field, and block names are semantic and editor-facing: no markup
|
|
28
|
+
tags, HTML attributes, locale suffixes, or column indexes.
|
|
29
|
+
- Modeling did not redesign the site: the migrated routes render the same
|
|
30
|
+
content, order, and copy as the source, and the text plan records the
|
|
31
|
+
source-to-Fimo mapping.
|
|
32
|
+
- Media alt text is attached to the media (asset metadata and media value), with
|
|
33
|
+
no standalone alt field in a content schema. Alt is never the filename, and a
|
|
34
|
+
generated fallback is recorded as generated.
|
|
35
|
+
- Every planner `sourceFile`/`sourceKey` maps to its original consumer. Imported
|
|
36
|
+
labels or prose that are only appended elsewhere, including an additive
|
|
37
|
+
“Page content” section, are unwired gaps. Use existing literal-key extraction
|
|
38
|
+
for a bounded read-only comparison when it is sound; otherwise report every
|
|
39
|
+
unmapped key from the planner consumer map. Do not build a generic AST or
|
|
40
|
+
codemod system for this check.
|
|
8
41
|
- Every CMS export file is mapped to a schema, ignored with a reason, or unresolved.
|
|
9
42
|
- Source entry counts match imported counts (entries created in Fimo), excluding
|
|
10
43
|
documented skips/unresolved. Generated seed JSON alone does not satisfy this.
|
|
11
44
|
- Every media item referenced by routes, CMS entries, SEO, or forms is uploaded to
|
|
12
45
|
the Fimo media library (Fimo asset id/URL) or has an unresolved item. A local
|
|
13
46
|
`public/` copy is not an upload mapping.
|
|
14
|
-
- Every
|
|
47
|
+
- Every planner media obligation, including schema media fields and nested
|
|
48
|
+
richtext/Tiptap image nodes, has a mapping or explicit disposition; the asset
|
|
49
|
+
worker's completion claim alone is not evidence.
|
|
50
|
+
- Every visible form has a Fimo replacement, a preserved third-party
|
|
51
|
+
integration, or an unsupported note. A form became Fimo-native only when the
|
|
52
|
+
Fimo form matches the source behavior 1:1.
|
|
53
|
+
- The detected source framework, router, runtime, and configuration are
|
|
54
|
+
preserved. React Router/Vite remains React Router/Vite; any Next.js conversion
|
|
55
|
+
has the user's explicit choice. Unsupported or unclear hosting is unresolved,
|
|
56
|
+
not hidden by a conversion or deleted configuration.
|
|
57
|
+
- In conversion mode, the framework gate passed before content code work: the
|
|
58
|
+
conversion worker's self-checks and the coordinator's independent rerun of
|
|
59
|
+
the build and representative route checks are both recorded. A gate failure
|
|
60
|
+
caps the status at draft-only or leaves the affected routes unresolved; no
|
|
61
|
+
route was replaced by a generic shell or another framework as a fallback.
|
|
62
|
+
- Every preserved third-party integration keeps its original wiring, and the
|
|
63
|
+
credential environment keys it needs are recorded by name. A missing secret
|
|
64
|
+
is an unresolved user follow-up, never silently removed behavior.
|
|
15
65
|
- SEO title, description, canonical URL, share image, slugs, dates, authors,
|
|
16
66
|
categories, tags, redirects, and locales are preserved when present.
|
|
67
|
+
- Existing SEO, OG, and social behavior - including dynamic OG image routes -
|
|
68
|
+
is preserved or explicitly reported as a gap.
|
|
69
|
+
- When the source has no low-risk SEO or social value, safe defaults derived
|
|
70
|
+
from verified page/site data are present or the missing behavior is reported;
|
|
71
|
+
the migration must not invent marketing claims.
|
|
72
|
+
- Redirects and security headers stay in the source framework config when the
|
|
73
|
+
target keeps the source runtime and host, or are translated with a recorded
|
|
74
|
+
note in the text migration report when the target runtime or host requires
|
|
75
|
+
it.
|
|
76
|
+
- Every provider-specific rule is classified as preserved, replaced, safely
|
|
77
|
+
unnecessary implementation detail, or unresolved. A deletion has evidence of
|
|
78
|
+
redundancy or the user's accepted loss.
|
|
79
|
+
- Public behavior is verified independently: blog routes and 404s, Markdown
|
|
80
|
+
negotiation, RSS, sitemap, `llms.txt`, OG/social metadata, redirects,
|
|
81
|
+
security headers, and forms where present. Cloudflare cache storage, purge,
|
|
82
|
+
and revalidation internals need no copy when proven externally irrelevant.
|
|
83
|
+
- Each content/data lane records its source-access class. Local files/exports
|
|
84
|
+
and public APIs were read under their simple access rules; private sources
|
|
85
|
+
used a user export or narrowly scoped server-side credential. Missing access
|
|
86
|
+
is unresolved for that lane, and no content was guessed.
|
|
87
|
+
|
|
88
|
+
For linked Next.js targets, `withFimo` derives `FIMO_CONTENT_API_URL` and
|
|
89
|
+
`NEXT_PUBLIC_FIMO_API_URL` from `.fimo/project.json` during `next dev`,
|
|
90
|
+
`next build`, and `next start`. Both aliases resolve to the same tenant API,
|
|
91
|
+
while non-empty user overrides remain untouched; no committed env file is
|
|
92
|
+
required.
|
|
93
|
+
|
|
94
|
+
## Hosting
|
|
95
|
+
|
|
96
|
+
Owned by the runtime lane; verified here read-only.
|
|
97
|
+
|
|
98
|
+
- The target starts locally: the dev server responds without startup errors.
|
|
99
|
+
- The target is embeddable in Fimo Preview, which frames the app in an iframe
|
|
100
|
+
and drives it over the postMessage preview bridge. Development/preview
|
|
101
|
+
responses carry no unconditional `X-Frame-Options` or CSP `frame-ancestors`
|
|
102
|
+
block; protective headers (nosniff, HSTS, referrer policy) stay. The
|
|
103
|
+
translation goes through `FIMO_PREVIEW_ALLOWED_ORIGINS`; `withFimo` alone
|
|
104
|
+
does not solve headers — it only extends `allowedDevOrigins` during
|
|
105
|
+
`next dev`.
|
|
106
|
+
- The runtime report covers local startup, preview embedding, build, derived
|
|
107
|
+
aliases, header translations, and integration env-key names, with every
|
|
108
|
+
claim backed by evidence.
|
|
109
|
+
- With a browser available, record `browserProof` (rendered route plus console
|
|
110
|
+
state) for startup and embedding. Without one, use deterministic HTTP
|
|
111
|
+
status/header/process/log checks and mark visual proof explicitly
|
|
112
|
+
unavailable in the report.
|
|
113
|
+
- Deployment smoke is explicit owner opt-in; never run deploy or publish as a
|
|
114
|
+
QA step.
|
|
17
115
|
|
|
18
116
|
## Behavior
|
|
19
117
|
|
|
@@ -21,13 +119,49 @@ Run this gate before reporting completion.
|
|
|
21
119
|
- The project builds successfully.
|
|
22
120
|
- Local dev starts without Vite loader/schema/form generation errors.
|
|
23
121
|
- Primary routes render without console/runtime errors.
|
|
122
|
+
- In conversion mode, every route in the conversion worker's route map renders
|
|
123
|
+
locally with the expected status (including 404) and shows its source text
|
|
124
|
+
landmarks, and the target has exactly one app tree.
|
|
24
125
|
- Collection listing/detail pages work with imported data, seed data, or explicit
|
|
25
126
|
empty states.
|
|
127
|
+
- Every content-code batch exercised at least one non-empty imported item
|
|
128
|
+
through each Server-to-Client or plain-JSON boundary it introduced; build
|
|
129
|
+
success over an empty query result does not pass this check.
|
|
26
130
|
- Navigation and footer links point to migrated routes or documented external URLs.
|
|
131
|
+
- Missing integration secrets do not block these checks: build, dev, and route
|
|
132
|
+
render run with the integration inert, and the missing key is a recorded
|
|
133
|
+
follow-up.
|
|
27
134
|
- Unsupported app behavior is not hidden behind broken UI.
|
|
28
135
|
|
|
136
|
+
## Browser smoke (required)
|
|
137
|
+
|
|
138
|
+
Build success and HTTP 200 responses are not sufficient evidence: a page can
|
|
139
|
+
build, return 200, and still render blank labels or an empty collection. Run
|
|
140
|
+
one bounded, scriptable browser pass (Playwright, agent-browser, or
|
|
141
|
+
equivalent):
|
|
142
|
+
|
|
143
|
+
1. Start the app and wait for hydration, not just the HTTP response.
|
|
144
|
+
2. Open a representative set of pages: home, one collection listing, one
|
|
145
|
+
collection detail, one static page.
|
|
146
|
+
3. Exercise one representative interaction (open the nav menu, an accordion,
|
|
147
|
+
or a filter) and assert its visible result.
|
|
148
|
+
4. Assert expected visible text on each opened page and at least one dynamic
|
|
149
|
+
collection item rendered from imported Fimo data.
|
|
150
|
+
5. Assert globally rendered label/button text (header/footer nav, CTAs, cookie
|
|
151
|
+
banner) is non-empty; blank text usually means the component is mounted
|
|
152
|
+
outside the label provider.
|
|
153
|
+
6. Inspect the browser console and server output for runtime errors.
|
|
154
|
+
|
|
155
|
+
Keep it bounded: representative pages and one interaction, not an interactive
|
|
156
|
+
walk of every route or a multi-hour visual audit. The Visual section below
|
|
157
|
+
remains a separate spot check.
|
|
158
|
+
|
|
29
159
|
## Visual
|
|
30
160
|
|
|
161
|
+
Visual checks need a browser. When none is available, run the deterministic
|
|
162
|
+
Hosting checks instead and mark visual proof explicitly unavailable in the
|
|
163
|
+
report; never claim a visual check that did not run.
|
|
164
|
+
|
|
31
165
|
- Compare source and migrated site at desktop and mobile sizes.
|
|
32
166
|
- Prioritize layout, typography, content hierarchy, media, and brand tokens.
|
|
33
167
|
- Remove generated placeholder copy from visible UI.
|
|
@@ -42,8 +176,11 @@ Record:
|
|
|
42
176
|
- media uploaded/failed
|
|
43
177
|
- forms pushed
|
|
44
178
|
- redirects/locales imported or unresolved
|
|
179
|
+
- the exact CLI used for the run, recorded in the report's Source section (see
|
|
180
|
+
"CLI provenance" in `SKILL.md`)
|
|
45
181
|
|
|
46
|
-
Counts
|
|
182
|
+
Counts belong in `.fimo/migration/migration-report.md` and the relevant worker
|
|
183
|
+
reports. Do not create a JSON QA registry just to store them.
|
|
47
184
|
|
|
48
185
|
Media, entries, and forms are blocking checks. Entries generated as seed JSON but
|
|
49
186
|
not created in Fimo, and media bundled under `public/` but not uploaded to the
|
|
@@ -66,15 +203,25 @@ complete | complete-with-unresolved | draft-only
|
|
|
66
203
|
|
|
67
204
|
## Source
|
|
68
205
|
|
|
206
|
+
## Coverage by dimension
|
|
207
|
+
|
|
69
208
|
## Routes
|
|
70
209
|
|
|
71
|
-
##
|
|
210
|
+
## Content
|
|
72
211
|
|
|
73
212
|
## Media
|
|
74
213
|
|
|
75
214
|
## Forms
|
|
76
215
|
|
|
77
|
-
## SEO
|
|
216
|
+
## SEO and OG
|
|
217
|
+
|
|
218
|
+
## Redirects and Headers
|
|
219
|
+
|
|
220
|
+
## Integrations
|
|
221
|
+
|
|
222
|
+
## Hosting
|
|
223
|
+
|
|
224
|
+
## Timing
|
|
78
225
|
|
|
79
226
|
## Checks
|
|
80
227
|
|
|
@@ -83,15 +230,22 @@ complete | complete-with-unresolved | draft-only
|
|
|
83
230
|
## Next Actions
|
|
84
231
|
```
|
|
85
232
|
|
|
233
|
+
`Coverage by dimension` is one row per migration surface (routes, content,
|
|
234
|
+
forms, SEO/OG, redirects/headers, integrations, hosting, media, labels, and
|
|
235
|
+
locales) with `gate`,
|
|
236
|
+
`discovered`, `migrated`, `verified`, `unresolved`, `unsupported`,
|
|
237
|
+
`denominator`, and `coverage`. Never collapse it into a single score: full route
|
|
238
|
+
coverage must not average away a missing entry or an unuploaded asset. Timing is
|
|
239
|
+
a separate section copied from the worker reports, so it never dilutes coverage.
|
|
240
|
+
|
|
241
|
+
Cache freshness is a report check only when the source or user made freshness an
|
|
242
|
+
accepted observable requirement; do not fail a migration for omitted provider
|
|
243
|
+
cache mechanics alone.
|
|
244
|
+
|
|
86
245
|
Use `complete` only when all required checks pass. Use
|
|
87
246
|
`complete-with-unresolved` when the migrated site is usable and all gaps are
|
|
88
247
|
owner-visible. Use `draft-only` when import or verification has not happened.
|
|
89
248
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
node <this-skill>/scripts/write-migration-report.mjs <project-root>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
If it fails, read the generated report and either complete the missing work or
|
|
97
|
-
add precise unresolved items with owner-friendly suggested actions.
|
|
249
|
+
Write the report directly as text. A later evaluator may calculate the table
|
|
250
|
+
from it, but the migration does not need a manifest or report-generation
|
|
251
|
+
registry to run.
|