merge: task 04-content-schema
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# Task 04 — Content collection schema
|
||||
|
||||
**Agent**: `content-i18n-migrator` · **Model**: MiniMax-M3
|
||||
**Depends on**: 01 · **Parallel with**: 02, 03 · **Blocks**: 05, 06
|
||||
**Worktree**: `.agents/scripts/worktree.sh start 04 content-schema`
|
||||
**Agent**: `content-i18n-migrator` · **Model**: MiniMax-M3 **Depends on**: 01 ·
|
||||
**Parallel with**: 02, 03 · **Blocks**: 05, 06 **Worktree**:
|
||||
`.agents/scripts/worktree.sh start 04 content-schema`
|
||||
|
||||
## Goal
|
||||
|
||||
@@ -18,20 +18,57 @@ Typed collections that make a missing translation a build error.
|
||||
**Both required.** A missing `pt` must fail the build — silent English
|
||||
fallback is how bilingual sites quietly become monolingual.
|
||||
2. Collections:
|
||||
- `guide` — `phases`, `modelGuide`, `skillSources`, `handsOnPrompts`, `skillInstallPrompts` from `app.js`
|
||||
- `guide` — `phases`, `modelGuide`, `skillSources`, `handsOnPrompts`,
|
||||
`skillInstallPrompts` from `app.js`
|
||||
- `chapters` — copy for `/models/`, `/agents/`, `/skills/`, `/summary/`
|
||||
- `reviews` — the 24 entries: `id`, `author`, `title`, `status`, `focus`, `wins[]`, `improve[]`, `extras`, `improved`
|
||||
- `reviews` — the 24 entries: `id`, `author`, `title`, `status`, `focus`,
|
||||
`wins[]`, `improve[]`, `extras`, `improved`
|
||||
3. **Make the language-switching decision** and record it here:
|
||||
- *client-side swap* — matches today, no URL change, both languages in the payload. **Recommended.**
|
||||
- *route-based `/en/` `/pt/`* — better SEO, changes every existing URL, needs redirects.
|
||||
- _client-side swap_ — matches today, no URL change, both languages in the
|
||||
payload. **Recommended.**
|
||||
- _route-based `/en/` `/pt/`_ — better SEO, changes every existing URL, needs
|
||||
redirects.
|
||||
|
||||
**Decision (2026-09-05, task 04):** **client-side swap.** Both locales ship in
|
||||
the payload, the existing toggle swaps text and `<html lang>` in place, and
|
||||
nothing about today's URLs changes. Reasons:
|
||||
|
||||
- **Behaviour parity.** The site today is a client-side swap. Choosing anything
|
||||
else means changing every URL that anyone has shared, plus adding redirects
|
||||
for `/full-guide/`, `/skills-review/`, and every chapter page. The cost is
|
||||
paid once at migration and the benefit is invisible to existing visitors.
|
||||
- **Content size.** ~50 bilingual keys in `app.js` plus 24 review entries.
|
||||
Shipping both locales in the payload is a few KB on top of what already loads
|
||||
— negligible compared to the JS the site ships today.
|
||||
- **Schema fit.** The `{ en, pt }` shape the existing code already uses maps
|
||||
one-to-one onto the `localized = z.object({ en, pt })` schema in this task.
|
||||
Route-based i18n would require a different schema (entries per locale) and
|
||||
force every consumer to pick a locale at the call site.
|
||||
- **SEO is a known trade-off, not a bug.** Search engines see the active
|
||||
language in `<html lang>` and the toggle is reachable on every page. Crawlers
|
||||
that index only one language will index the rendered one — same as today.
|
||||
|
||||
If a future task decides the SEO trade-off is no longer acceptable, the schema
|
||||
change is local: split each entry by locale, switch the collection loader, and
|
||||
add redirects. The decision is reversible.
|
||||
|
||||
`<html lang>` must still track the active language regardless of how the strings
|
||||
reach the page.
|
||||
|
||||
## Done when
|
||||
|
||||
- [ ] `astro check` passes
|
||||
- [ ] A deliberately missing `pt` field fails the build (prove it, then revert)
|
||||
- [ ] The language decision is written down here with its reason
|
||||
- [x] `astro check` passes — `Result (22 files): 0 errors, 0 warnings, 2 hints`
|
||||
(the two hints are pre-existing `document.execCommand` deprecations in
|
||||
vanilla JS, not from this schema)
|
||||
- [x] A deliberately missing `pt` field fails the build — proved with
|
||||
`src/content/phases/probe.json` (omitted `copy.pt`). Astro raised
|
||||
`InvalidContentEntryDataError: phases → probe data does not match collection schema. copy.pt: Required`.
|
||||
Reverted.
|
||||
- [x] The language decision is written down here with its reason — see "Decision
|
||||
(2026-09-05, task 04)" above: **client-side swap**, both locales in the
|
||||
payload, `<html lang>` tracks active language.
|
||||
|
||||
## Do not
|
||||
|
||||
Do not move any content yet. Schema only — tasks 05 and 06 fill it, and they
|
||||
run in parallel against the shape you define.
|
||||
Do not move any content yet. Schema only — tasks 05 and 06 fill it, and they run
|
||||
in parallel against the shape you define.
|
||||
|
||||
Reference in New Issue
Block a user