06 — Build and Slice Loop
Implement features in real vertical slices (UI→API→DB→tests→deploy) starting with the homepage; no placeholders, no stubs.
Vertical-slice principle
Every iteration ships ONE feature end-to-end through every layer (UI → API → DB → tests → deploy). Never half a feature across two passes.
Homepage FIRST (every project, no exceptions)
- First slice is always the homepage hero + nav + footer
- Real H1, real meta tags, real OG card, real JSON-LD
- Deploy before adding any other route — establishes design system, auth layer, analytics tier, deploy pipeline
- Per
rules/website-build-doctrine.mdPhase 0 / Phase 1
Anti-placeholder (NON-NEGOTIABLE)
- ❌ Lorem ipsum
- ❌ TODO / FIXME / TBD in shipped user-visible strings (source-comment TODOs OK per
rules/todos-are-roadmap.md) - ❌ Gray placeholder boxes / silhouettes
- ❌ "Coming soon" without firm date
- ❌ Stub images / generic SVGs
- ❌ "John Doe" / "Jane Doe" / "company.com" / "example.com"
- ❌ Bracket placeholders
[Insert Name]/[Your Title] - ❌ Single-character "x" / "?" labels
Per rules/copy-writing.md § Production-review copy gate. Build validator greps dist/ for these patterns.
Slice contract (every slice ships ALL of these)
- Types + Zod schemas at boundaries (
rules/zod-everywhere.md) - Contract-first API (typed request/response)
- Loading + empty + error + success states (4-state system per
10-experience-and-design-system) - Accessibility (axe 0 violations + WCAG 2.2 AA per
_kernel/standards.md#wcag22) - 6-breakpoint responsive (per
_kernel/standards.md#breakpoints) - Observability (Sentry breadcrumb + PostHog event + Workers Trace span)
- Tests (Vitest unit + Playwright E2E from homepage outward per
rules/e2e-tdd-organization.md) - Feature flag where rollout risk exists (
rules/feature-flags.md) - Tenant isolation (
org_idon every row + every query, 404 on mismatch) - Docs (JSDoc on exports + module README)
File organization
Worker (Hono)
src/worker/
├── index.ts # entry — Sentry wrapper, route mounts, onError, notFound
├── db/
│ ├── schema.ts # Drizzle source of truth
│ └── index.ts # getDb helper
├── routes/<feature>.ts # Hono sub-app per feature
├── lib/<feature>.ts # business logic
├── middleware/ # auth, tenant, rate-limit
└── types.ts # Env + Variables
Frontend (React + Vite)
src/web/
├── main.tsx # entry — router, providers
├── pages/<Page>.tsx # one per route
├── components/
│ ├── ui/ # shadcn primitives
│ ├── <feature>/ # feature-specific components
│ └── shared/ # Header, Footer, ErrorBoundary
├── lib/ # api client, auth context, hooks
└── styles.css # Tailwind + design tokens
Shared
src/shared/
├── plans.ts # pricing tiers
├── design-styles.ts # design tokens shared web + worker
└── pageLayout.ts # shared layout helpers
Tests
e2e/
├── FEATURES.md # row-per-feature matrix (CI gate)
├── _fixtures/ # page objects
├── _helpers/ # snapshot, axe, breadcrumbs, visual
├── <feature>/
│ ├── happy-path.spec.ts
│ ├── edge-cases.spec.ts
│ ├── a11y.spec.ts
│ └── visual.spec.ts
└── _smoke/ # cross-feature smoke
Build loop (per slice)
- Write failing test (Playwright TDD-RED first per
rules/e2e-tdd-organization.md) - Author migration (
drizzle/0NNN_<feature>.sql) + updatedb/schema.ts - Apply locally (
npm run db:apply:local) - Implement (route, lib, page, components)
- Typecheck (
npm run typecheckclean) - Unit tests (
npm testgreen) - Run dev (
npm run dev) — exercise in browser - Deploy (
npm run deploy) - Prod E2E (
npm run e2e:prodagainst PROD_URL) - Verify console (zero errors, zero CSP violations, zero failed resources)
- AI vision QA (6bp screenshots → vision rubric ≥9/10)
- Commit + push (conventional commits per
rules/main-only-branch.md) - Update
e2e/FEATURES.md+ CHANGELOG
Real content sourcing
- Copy: brand voice per
09-brand-and-content-system; never AI-default phrasing - Images: real photos > AI-generated brand-aligned > zero (skill 12)
- Data: real API / Workers AI / D1 query > mocked
- Testimonials: real attribution > none (never fabricated)
- Stats: cited per
rules/citations.md
When to stop adding sections
Per rules/website-build-doctrine.md Phase 2: keep adding until next would dilute. Stop when "next hurts," never "we have enough."