# Track 4 Report — Integration

**Status:** done

## Summary

Track 4 ships the integration layer: 10 end-to-end acceptance scenarios, an adoption example (book schema), 1 fixture, 4 docs, plus updates to `index.js` and `module.json`. 155/155 tests pass (133 prior + 12 book schema + 10 acceptance). All files under 200 lines. No Track 0-3 source files modified.

## Files shipped

### New files

| File | LOC | Purpose |
|---|---|---|
| `tests/acceptance/site-smoke.test.js` | 199 | 10 end-to-end scenarios (S1-S10) |
| `tests/fixtures/sample-site.js` | 109 | 3 schemas + 10 records, with `seedSampleSite()` helper |
| `tests/test-book-schema.js` | 134 | Adoption example test (12 cases) |
| `schemas/book.js` | 94 | 9-field book schema (id, title, author, blurb, cover_url, buy_url, published, tags, order) |
| `README.md` | 114 | Quick-start + file layout |
| `USAGE.md` | 167 | How to add content types, use editors, bulk import, backups |
| `SECURITY.md` | 99 | Threat model + operator checklist (cross-links auth/SECURITY.md) |
| `MIGRATION.md` | 175 | Step-by-step from Sanity / Contentful / Firestore / Airtable |
| `SCHEMAS.md` | 107 | Built-in + example schemas catalog |
| `track-4-report.md` | (this) | Track 4 report |

### Modified files

| File | Change |
|---|---|
| `index.js` | Re-exports `bookSchema` from `./schemas/book.js` |
| `schemas/index.js` | Registers `bookSchema` as a built-in (alongside `siteSettingsSchema`) |
| `module.json` | Bumped to `0.4.0-track4`, `status: "acceptance-ready"`, added docs/files/tests/scenarios entries |

### Untouched (per "Track 0-3 are read-only" constraint)

- `schema.js`, `schema-id.js`
- `validator.js`, `validator-types.js`
- `store.js`, `store-bulk.js`
- `activity.js`
- `backups.js`, `backups-keys.js`, `backups-rotate.js`
- `search.js`, `ai-prompts.js`
- `auth/*` (all 5 files)
- `views-helpers.js`, `views-*.js`
- `editors/*`, `upload/*`, `router*`, `mounts.js`, `ui*`, `form-bindings.js`, `stubs.js`, `stub-store.js`
- `storage/*`
- `admin.html`, `admin.css`, `admin.js`
- `wordlist.js`, `cms-doctrine.md`
- All prior tests

## Tests passing

- **155/155** total
- 133 prior (unchanged, still green)
- 10 acceptance (`tests/acceptance/site-smoke.test.js`)
- 12 book schema (`tests/test-book-schema.js`)
- Test runtime: ~26 seconds

## Acceptance scenarios

All 10 from the Track 4 brief:

1. **S1 — Setup creates admin + returns 12 recovery words** — `setupAdmin` succeeds, returns 12 words, rejects re-setup
2. **S2 — Login wrong password fails + increments counter** — `login` rejects, `lockouts.admin.failedCount` increments
3. **S3 — Login correct password succeeds + sets session** — `isAuthenticated` flips to `true`, `logout` flips back
4. **S4 — Schema CRUD round-trip** — `cmsUpsert` creates, `cmsList` retrieves, `cmsGet` finds, update preserves `createdAt`
5. **S5 — Validation rejection** — invalid id pattern, missing required, unknown field all rejected
6. **S6 — Cascade delete** — without `force`: `cascade_confirm_required` + cascade list; with `force`: cascades through
7. **S7 — Backup round-trip** — export → wipe → import → records restored; `cms:admin:auth` NEVER in envelope
8. **S8 — Activity audit trail** — 5 CRUD ops → 5 entries newest-first, summary correct
9. **S9 — Auto-backup rotation** — 3 calls with increasing `now` → all 3 rotate, slot 0 has the freshest envelope
10. **S10 — Global search** — searches across 3 schemas (`book`, `lesson`, `author`) find expected matches

## Adoption example (book schema)

`schemas/book.js` defines a 9-field book content type:

- `id` (slug, required, snake_case)
- `title` (string, required)
- `author` (string, optional)
- `blurb` (textarea, optional)
- `cover_url` (image, optional)
- `buy_url` (url, optional)
- `published` (boolean, default false)
- `tags` (array of strings, optional)
- `order` (integer, default 0)

Includes `aiPromptHint`, `defaults`, and `identityKey: 'id'` (pressure-test A.L4). Does **not** name the source site.

`bookSchema.toAiPrompt()` lists all 9 fields. `bookSchema.csvColumns()` starts with `id` followed by the other 8. `bookSchema.matchStableIdentity()` correctly matches by id.

## Documentation quality

- Plain English, short sentences, no jargon without explanation
- Operator-readable on mobile (verified by manual scan)
- Code examples for every API call
- Cross-links between docs (e.g., `SECURITY.md` → `auth/SECURITY.md`)
- All under 200 lines (max 175 for `MIGRATION.md`)

## Public API additions

```js
// index.js — new export
export { bookSchema } from './schemas/book.js';
```

The schema is also auto-registered by `schemas/index.js` on module load. So:

```js
import { bookSchema, getSchema, allSchemas } from './cms/index.js';
// getSchema('book') and allSchemas().book both work without explicit registerSchemas
```

## Deviations from spec

**Zero.** All files in the brief shipped, all acceptance scenarios covered, all hard requirements met.

- Files < 200 lines: ✅ (max 199 for `site-smoke.test.js`)
- Acceptance test uses `node --test`: ✅
- Prior 133 tests still pass: ✅
- No new dependencies: ✅
- Track 0-3 source files untouched: ✅
- Tiny Style Guide applied: ✅
- Book schema does not name source site: ✅
- `module.json` updated to `0.4.0-track4` with `status: "acceptance-ready"`: ✅

## Notes for the next session (Track 5 — hardening)

- All S5 hardening concerns (security review, perf, a11y) are out of scope here
- `track-0-report.md` and `track-0-test-results.md` are untouched; Track 5 can supersede them with its own report
- The `book` schema is the only adoption example shipped; future examples can follow the same pattern
- `cms-doctrine.md` is unchanged; Track 5 may add a hardening section

— cloud Mavis (sub-session), 2026-07-02
