From f3b98aa8131d50ef7484209dc22e8bf55edd432c Mon Sep 17 00:00:00 2001 From: Tony Ko Date: Mon, 27 Jul 2026 17:52:57 -0400 Subject: [PATCH] Vendor house standards from harness-skills, rename PRD folder Standards (process, writing, nextjs, components, data, testing, performance, accessibility, seo, git) now come from the shared harness-skills library, symlinked at .claude/skills/ and .agents/skills/ (gitignored: the symlink is a local-clone absolute path, not portable). docs/01-standards/ is removed as redundant. docs/02-prd/ is renamed to docs/prd/ to match the skill's default PRD folder convention. --- .gitignore | 4 + AGENTS.md | 32 ++--- README.md | 25 ++-- docs/01-standards/accessibility.md | 9 -- docs/01-standards/components.md | 81 ----------- docs/01-standards/data.md | 10 -- docs/01-standards/git.md | 42 ------ docs/01-standards/nextjs.md | 44 ------ docs/01-standards/performance.md | 10 -- docs/01-standards/process.md | 176 ----------------------- docs/01-standards/seo.md | 8 -- docs/01-standards/testing.md | 11 -- docs/01-standards/writing.md | 54 ------- docs/{02-prd => prd}/01-brief.md | 0 docs/{02-prd => prd}/02-design-system.md | 0 docs/{02-prd => prd}/03-profile.md | 0 docs/{02-prd => prd}/04-compatibility.md | 0 docs/{02-prd => prd}/05-add-friends.md | 0 docs/{02-prd => prd}/06-matching.md | 0 docs/{02-prd => prd}/07-architecture.md | 0 20 files changed, 29 insertions(+), 477 deletions(-) delete mode 100644 docs/01-standards/accessibility.md delete mode 100644 docs/01-standards/components.md delete mode 100644 docs/01-standards/data.md delete mode 100644 docs/01-standards/git.md delete mode 100644 docs/01-standards/nextjs.md delete mode 100644 docs/01-standards/performance.md delete mode 100644 docs/01-standards/process.md delete mode 100644 docs/01-standards/seo.md delete mode 100644 docs/01-standards/testing.md delete mode 100644 docs/01-standards/writing.md rename docs/{02-prd => prd}/01-brief.md (100%) rename docs/{02-prd => prd}/02-design-system.md (100%) rename docs/{02-prd => prd}/03-profile.md (100%) rename docs/{02-prd => prd}/04-compatibility.md (100%) rename docs/{02-prd => prd}/05-add-friends.md (100%) rename docs/{02-prd => prd}/06-matching.md (100%) rename docs/{02-prd => prd}/07-architecture.md (100%) diff --git a/.gitignore b/.gitignore index dd14ff8..9fea69a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,7 @@ next-env.d.ts # os .DS_Store + +# vendored skills (local-machine symlink, not portable) +.claude/skills +.agents/skills diff --git a/AGENTS.md b/AGENTS.md index 3612c3a..ccc95fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,39 +1,31 @@ # AGENTS.md -Guidance for AI coding agents working in this repository: Kindred (working name), a compatibility app where a member fills out a self-questionnaire, connects friends, and reveals how compatible they are with each. Interaction patterns are modeled on [222.place](https://222.place); the product direction and design are our own. What the app is lives in [README.md](README.md); the rules and requirements live in `docs/`. +Guidance for AI coding agents working in this repository: Kindred (working name), a compatibility app where a member fills out a self-questionnaire, connects friends, and reveals how compatible they are with each. Interaction patterns are modeled on [222.place](https://222.place); the product direction and design are our own. What the app is lives in [README.md](README.md); house standards are vendored as skills (`.claude/skills/`, `.agents/skills/`); the rules and requirements live in `docs/`. ## Read first, in order @README.md -@docs/01-standards/process.md -@docs/01-standards/writing.md -@docs/01-standards/nextjs.md -@docs/01-standards/components.md -@docs/01-standards/data.md -@docs/02-prd/01-brief.md -@docs/02-prd/02-design-system.md -@docs/02-prd/06-matching.md -@docs/02-prd/07-architecture.md - -The remaining standards ([testing](docs/01-standards/testing.md), [performance](docs/01-standards/performance.md), [accessibility](docs/01-standards/accessibility.md), [seo](docs/01-standards/seo.md), [git](docs/01-standards/git.md)) and the per-surface PRD docs ([profile](docs/02-prd/03-profile.md), [compatibility](docs/02-prd/04-compatibility.md), [add-friends](docs/02-prd/05-add-friends.md)) are read just in time. +@docs/prd/01-brief.md +@docs/prd/02-design-system.md +@docs/prd/06-matching.md +@docs/prd/07-architecture.md + +The per-surface PRD docs ([profile](docs/prd/03-profile.md), [compatibility](docs/prd/04-compatibility.md), [add-friends](docs/prd/05-add-friends.md)) are read just in time. ## Decision framework -When a choice is not settled by this repo's own code, README, or an obvious default, apply [harness-engineering](https://github.com/tkodev/harness-engineering) as the decision maker: read the target's local truth first, name the one unresolved decision, route to the single relevant thesis, and let this repo's contracts govern over any imported guidance. Do not preload the corpus; follow its links just in time. +See the `decisions` skill for when and how to consult harness-engineering. ## Stack -pnpm 11 (never npm or yarn), Node >= 24, TypeScript strict, Next.js 16 App Router, Tailwind v4 (CSS-first `@theme`, no `tailwind.config`), CVA with `cn()` = `twMerge(clsx(...))`, shadcn/Radix primitives, `lucide-react`, `date-fns`, Vitest. The data layer is **oRPC**: user-specific data (profile, friends, compatibility reveals) flows through typed procedures in `src/server/`, validated with zod; seed data lives in `constants/`. Persistence targets Postgres via `docker compose` ([docs/02-prd/07-architecture.md](docs/02-prd/07-architecture.md)); procedures read seed constants until it lands, and the seed is the data contract. +pnpm 11 (never npm or yarn), Node >= 24, TypeScript strict, Next.js 16 App Router, Tailwind v4 (CSS-first `@theme`, no `tailwind.config`), CVA with `cn()` = `twMerge(clsx(...))`, shadcn/Radix primitives, `lucide-react`, `date-fns`, Vitest. The data layer is **oRPC**: user-specific data (profile, friends, compatibility reveals) flows through typed procedures in `src/server/`, validated with zod; seed data lives in `constants/`. Persistence targets Postgres via `docker compose` ([docs/prd/07-architecture.md](docs/prd/07-architecture.md)); procedures read seed constants until it lands, and the seed is the data contract. ## House rules -These come from `docs/01-standards/` (the tkodev standards); the load-bearing ones: +Component shape, CVA/styling, atomic-design layout, and server-components-by-default are covered by the vendored `components` and `nextjs` skills. Project-specific data-layer rules that aren't generic: -1. **Component shape.** Every component is a single `styles` object of `cva()` calls on top, then `XxxRef` / `XxxProps` types, then the component; named exports only, no default exports. Props destructure, then hooks, then render vars, then jsx composed with `cn()`. -2. **Styling.** CVA for all visual variants, never ad-hoc className conditionals. Semantic tokens only: no raw hex, no palette utilities (`text-zinc-400`), no arbitrary sizes. Layout utilities (`w-full`, margins, grid placement) live at the call site; color, radius, type, borders live in the CVA. -3. **Atomic design.** Components live under `components/` as `atoms/` (buttons, badges), `molecules/` (cards, forms), `organisms/` (dialogs, menus), `templates/` (header, footer, layout, section). shadcn CLI imports land in `atoms/` and are reformatted to the house shape on arrival. -4. **Data discipline.** Dynamic, user-specific data goes through oRPC procedures, typed by `types/`. Static content lives in `constants/`, never inline in components. Keep client state local (`useState`, URL params); no speculative global state. Dates zone through `date-fns-tz`, never bare `new Date()`. -5. **Server components by default.** `'use client'` only where state or browser APIs demand it, and as low in the tree as possible. +1. **oRPC boundary.** Dynamic, user-specific data (profile, friends, compatibility reveals) goes through typed oRPC procedures in `src/server/`, validated with zod, typed by `types/`. Static content lives in `constants/`, never inline in components; the seed data in `constants/` is the data contract until Postgres lands. +2. **Matching model status.** Compatibility scores are still authored seed data — the matching model is designed, not yet computed (see [docs/prd/06-matching.md](docs/prd/06-matching.md)). ## Working discipline diff --git a/README.md b/README.md index 24cae86..90fd99e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A compatibility app for the people already in your life. You fill out a questionnaire about yourself, connect your friends, and reveal how compatible you are with each of them across the dimensions that actually predict a good relationship. Built for adults in their 30s and 40s who want depth over volume: close friendships first, dating where it fits. -**Status: working prototype.** Every surface renders end to end over a typed oRPC layer. Username-only sign-in and profile editing persist to Postgres, with an in-memory fallback so the app runs without Docker. Compatibility scores are still authored seed data (the matching model in [docs/02-prd/06-matching.md](docs/02-prd/06-matching.md) is designed, not yet computed). `Kindred` is a working name. +**Status: working prototype.** Every surface renders end to end over a typed oRPC layer. Username-only sign-in and profile editing persist to Postgres, with an in-memory fallback so the app runs without Docker. Compatibility scores are still authored seed data (the matching model in [docs/prd/06-matching.md](docs/prd/06-matching.md) is designed, not yet computed). `Kindred` is a working name. > The compatibility and questionnaire interaction patterns are modeled on [222.place](https://222.place); the color language and product direction are our own. @@ -28,7 +28,7 @@ A compatibility app for the people already in your life. You fill out a question | Styling | Tailwind v4 (`@theme`), CVA with `cn()`, an editorial serif over Geist | | Testing | Vitest | -The authoritative stack, data-layer, and seed-to-Postgres notes are [docs/02-prd/07-architecture.md](docs/02-prd/07-architecture.md). +The authoritative stack, data-layer, and seed-to-Postgres notes are [docs/prd/07-architecture.md](docs/prd/07-architecture.md). ## Getting started @@ -51,9 +51,10 @@ Without `DATABASE_URL` set (or if the database is unreachable) the app runs agai . ├── AGENTS.md # agent orientation (CLAUDE.md symlinks here) ├── docker-compose.yml # Postgres 16 for the persistence target +├── .claude/skills/ # vendored house-standard skills (symlink) +├── .agents/skills/ # same skills, agent-agnostic path (symlink) ├── docs/ -│ ├── 01-standards/ # house rules by topic (from boilerplate-web) -│ └── 02-prd/ # the numbered product docs, read in order +│ └── prd/ # the numbered product docs, read in order └── src/ ├── app/ # routes: /, /profile, /friends, /friends/[id], /friends/add, /rpc ├── components/ # atoms · molecules · organisms · templates @@ -66,16 +67,16 @@ Without `DATABASE_URL` set (or if the database is unreachable) the app runs agai ## Docs -Docs drive the implementation, read in order. The rules ([docs/01-standards/](docs/01-standards/)) are the house standards; the PRD ([docs/02-prd/](docs/02-prd/)) is the product pipeline. +House standards (component shape, data discipline, Next.js conventions, accessibility, performance, testing, seo, git, writing, process) are vendored as skills, symlinked at `.claude/skills/` and `.agents/skills/`. The PRD ([docs/prd/](docs/prd/)) is the product pipeline: | Doc | Owns | | --- | --- | -| [01-brief](docs/02-prd/01-brief.md) | What Kindred is, the audience, the aesthetic | -| [02-design-system](docs/02-prd/02-design-system.md) | Color, type, and the component inventory | -| [03-profile](docs/02-prd/03-profile.md) | The self-questionnaire surface | -| [04-compatibility](docs/02-prd/04-compatibility.md) | The friends list and reveal | -| [05-add-friends](docs/02-prd/05-add-friends.md) | The add-friends surface (our own, not in the source) | -| [06-matching](docs/02-prd/06-matching.md) | Preliminary compatibility-scoring model | -| [07-architecture](docs/02-prd/07-architecture.md) | Stack, oRPC data layer, seed-to-Postgres path | +| [01-brief](docs/prd/01-brief.md) | What Kindred is, the audience, the aesthetic | +| [02-design-system](docs/prd/02-design-system.md) | Color, type, and the component inventory | +| [03-profile](docs/prd/03-profile.md) | The self-questionnaire surface | +| [04-compatibility](docs/prd/04-compatibility.md) | The friends list and reveal | +| [05-add-friends](docs/prd/05-add-friends.md) | The add-friends surface (our own, not in the source) | +| [06-matching](docs/prd/06-matching.md) | Preliminary compatibility-scoring model | +| [07-architecture](docs/prd/07-architecture.md) | Stack, oRPC data layer, seed-to-Postgres path | For AI-agent orientation see [AGENTS.md](AGENTS.md); `CLAUDE.md` symlinks to it. diff --git a/docs/01-standards/accessibility.md b/docs/01-standards/accessibility.md deleted file mode 100644 index 339bf73..0000000 --- a/docs/01-standards/accessibility.md +++ /dev/null @@ -1,9 +0,0 @@ -# Accessibility - -The floor, not a cleanup pass. - -1. **WCAG 2.0 AA (AODA) is the baseline:** semantic landmarks (`header`/`main`/`footer`/`nav`/`section`), one `h1` per page, disclosures and nav keyboard-operable with correct ARIA, focus trapped in any modal overlay while open, visible `ring` focus states, decorative art `aria-hidden`. -2. **Respect `prefers-reduced-motion`**: ambient and entrance animations pause or reduce; every motion moment has a static equivalent, and nothing is readable only through motion. -3. **Contrast is checked in every theme scope**: AA contrast for text tokens (`muted-foreground` on `background` included) in the base theme and inside any inverse-color section. -4. **Self-starting motion carries a control**: anything that begins moving on its own and runs past a few seconds (a marquee drift, a carousel) pairs with a keyboard-operable pause. A hover pause is not one: it reaches neither keyboard nor touch, and the reduced-motion path only serves the readers who set the preference. -5. **Each landmark of a kind is named**: a page with more than one `nav` labels each (`Primary`, `Footer`, `Menu`), since an unnamed pair is indistinguishable to the reader listing them. The name is passed at the call site, never baked into the component. diff --git a/docs/01-standards/components.md b/docs/01-standards/components.md deleted file mode 100644 index 2c51996..0000000 --- a/docs/01-standards/components.md +++ /dev/null @@ -1,81 +0,0 @@ -# Components - -How components are added, shaped, styled, and organized. This file owns the authoring and styling rules; what components exist and what they look like is the design contract's concern, not this file's. - -## The flow: shadcn first - -1. **Check shadcn before writing anything.** Primitives use shadcn, which uses Radix primitives underneath. Adding a new component starts with a check of the shadcn library: if it exists there, import it with the CLI (`pnpm dlx shadcn@latest add `), then **reformat it to the house shape below and re-theme it with the project's tokens**. -2. **Custom components use the identical shape.** If shadcn doesn't have it (or the design calls for something bespoke), author it from scratch in exactly the same format; the only difference is there's nothing to import. - -## The file shape - -1. **Every component follows this example skeleton:** - - ```tsx - import { forwardRef, type HTMLAttributes } from 'react' - import { cn, cva, VariantProps } from '@/utils/theme' - - const styles = { - root: cva('…', { variants: { … }, defaultVariants: { … } }) - } - - type ExampleRef = HTMLDivElement - type ExampleProps = HTMLAttributes & VariantProps - - const Example = forwardRef((props, ref) => { - // props - const { className, ...rest } = props - - // hooks - - // render vars - - // jsx - return
- }) - Example.displayName = 'Example' - - export { Example } - export type { ExampleProps, ExampleRef } - ``` - - Order within the file: **CVA styles/constants on top → types (`XxxRef`, `XxxProps`) → component.** Order within the function body, each under its comment: **props** destructure → **hooks** → **render vars** → **jsx** (composed with `cn()`). -2. **Named exports only**: the component plus its `Props` and `Ref` types; `displayName` set on `forwardRef` components. No default exports. - -## Styling - -1. **CVA for all visual variants.** Each component defines a local `styles` object of `cva()` calls; never ad-hoc conditional className logic at call sites. -2. **`cn()` for all className composition**: `twMerge(clsx(...))` from `utils/theme.ts`, which also re-exports `cva` and `VariantProps` so components have one import point. -3. **Layout utilities at the call site, visual styles in the CVA.** `w-full`, grid placement, margins come from the parent; color, radius, type, borders live in the component's variants. -4. **Semantic tokens only.** No raw hex, no palette utilities (`text-zinc-400`), no arbitrary color values in JSX. Backgrounds pair with their foregrounds (`bg-primary` → `text-primary-foreground`). -5. **Type comes from the ramps.** Use the heading/expressive/body typography utilities defined by the design tokens: no arbitrary `text-[13px]`. Uppercase is CSS `uppercase`; content is written in normal case. -6. **Tailwind v4 CSS-first.** All theme extension in `themes/theme.css` `@theme`; no `tailwind.config.ts`. -7. **`asChild` + Radix `Slot`** when a component delegates rendering (``); never nest interactive elements. - -## Organization: atomic design - -1. Components live in `components/` in an atomic-design structure: - - `atoms/`: simple components. E.g. a button, a badge, the wordmark. - - `molecules/`: collections of atoms. E.g. a search bar, a date picker, an accordion, a project card. - - `organisms/`: collections of atoms/molecules. E.g. a page block, a dialog, a menu, an overlay. - - `templates/`: layout-focused things: footer, header, layout, main, section. -2. shadcn CLI imports land in `atoms/` (the `components.json` `ui` alias points there) and are reformatted on arrival. - -## Layout shell - -1. **One persistent shell wraps every page**, composed from `templates/`: - - ```text - layout - ├── underlays # site-wide background layers (e.g. custom webgl backgrounds) - ├── header # top bar: identity + nav links - ├── main # page content, sections in flow - ├── footer # bottom bar: copyright, quick links - └── overlays # takeover layers (e.g. loading screen, nav overlay) - ``` - -2. **Pages are stacks of `section` shells.** Every section renders through the `section` template: a full-bleed wrapper with a centered inner container in one of three widths (`lg` / `md` / `sm`, values set by the design tokens), never ad-hoc page-level wrappers. - -## Reusability - -1. **All components are reusable by construction.** Content is passed in via props or children, never defined inside a component. Content is defined in `constants/`, API calls, or pages (the consuming layer) only. A component with a hardcoded heading is a bug. diff --git a/docs/01-standards/data.md b/docs/01-standards/data.md deleted file mode 100644 index 28a3f7c..0000000 --- a/docs/01-standards/data.md +++ /dev/null @@ -1,10 +0,0 @@ -# Data and content - -Where content lives, how it's typed, and how state is managed. - -1. **All content in `constants/`.** No inline copy or data in components; no external content APIs. Copy is grounded in real facts, never invented. -2. **`constants/` is the source of truth.** It owns the site's content outright, typed by `types/`. Where an upstream source seeds it, that source stays a reference for facts not yet captured here; `constants/` still wins. -3. **State discipline.** Keep state local: `useState` and URL params for the ephemeral. No speculative global state. -4. **Dates:** zone through `fromZonedTime(iso, appTimeZone)`, never bare `new Date()`; display-only dates are pre-formatted strings. -5. **Media:** every entry carries real dimensions and real `alt` text; `src` paths are site-absolute under `public/`. -6. **Licensed assets stay put.** Licensed fonts and imagery ship with the site but are never published to other repos or registries. diff --git a/docs/01-standards/git.md b/docs/01-standards/git.md deleted file mode 100644 index 3a701ed..0000000 --- a/docs/01-standards/git.md +++ /dev/null @@ -1,42 +0,0 @@ -# Git - -How change is recorded. - -## Workflow - -1. **Work on the branch the process defines for the task** ([process.md](process.md) §Branches and PRs). Never push directly to `main`. -2. **Create new commits rather than amending.** Never force-push or skip hooks without explicit permission. -3. **Task PRs target their milestone branch; milestone PRs target the latest `main`.** Work outside a milestone stays on a feature branch and PRs only when explicitly asked. - -## Conventional Commits - -1. All commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/): - - ```text - (): - ``` - - - **Allowed types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. - - **Scopes** match the affected area: the surface (`home`), the layer (`templates`, `tokens`, `constants`), or the docs (`prd`, `docs`). Omit when global. - - **Subject:** ≤ 72 characters, lowercase, no trailing period. - - **Body:** explain the *why* when the diff alone doesn't. - - **Breaking changes:** `!` suffix and a `BREAKING CHANGE:` footer for route moves, renames, or behavior changes. - -## Branch naming - -1. Branches follow the same type vocabulary as commits: - - ```text - / - ``` - - - ≤ 40 characters, lowercase, hyphen-separated. - - Milestone and task branches carry their identifiers per - [process.md](process.md) §Branches and PRs: `feat/m02-works`, - `feat/m02-t04-works-ledger`. - - Branches outside a milestone reference the affected area: - `fix/date-zoning`, `docs/initial-plan`. - -## Attribution - -1. **No AI/agent attribution** in commits, PRs, or issues: no `Co-Authored-By: Claude/Codex`, no "Generated with Claude Code" markers, no `claude.ai/code` session links. diff --git a/docs/01-standards/nextjs.md b/docs/01-standards/nextjs.md deleted file mode 100644 index 8e52050..0000000 --- a/docs/01-standards/nextjs.md +++ /dev/null @@ -1,44 +0,0 @@ -# Next.js - -How the framework is used: App Router, rendering, and the built-in primitives. - -## Foundations - -Runtime, language, and what "done" requires. - -1. **pnpm only.** Never npm or yarn. Node ≥ 24. -2. **TypeScript strict.** No `any` escape hatches; domain types live in `types/`. -3. **Exported constants, hooks, types, and utils carry TSDoc.** Every export in `constants/`, `hooks/`, `types/`, and `utils/` opens with a `/** */` block: a one-line summary, plus `@param`/`@returns` for functions where the signature does not already say it, and per-member docs on non-obvious type fields; the doc is the contract a caller reads without opening the body. Components document themselves through their props types, not TSDoc. -4. **A server started for verification is killed when the check ends**: a `pnpm dev` or `pnpm start` run to confirm a change holds the port and outlives the task otherwise, so the next run collides or, worse, verifies against stale output. Long-running servers the human started are theirs to stop. -5. **A verification server runs on its own port and dies by its own pid.** Start it with an explicit `-p` well clear of `3000`, capture the pid (`pnpm start -p 3987 & echo $!`), and kill that pid. Never `pkill -f next-server` or any name match: it matches every Next process on the machine, including the human's dev server, and rule 4 leaves that one theirs to stop. -6. **Tests are [testing.md](testing.md)'s concern.** - -## Concepts - -1. **App Router conventions.** One root layout; pages compose section components inside `
`; the `app/` route tree mirrors the site's information architecture. -2. **Server components by default.** `'use client'` only where state or browser APIs demand it (overlays, accordions, marquees, motion-driven sections), and as low in the tree as possible. -3. **Static generation everywhere.** No runtime content fetching. Dynamic routes prebuild with `generateStaticParams` over their id lists and return `notFound()` for unknown ids. -4. **All images render through `next/image`** with explicit width and height. (Video loops are not images; they render as media elements with their own posters and dimensions.) -5. **Fonts load through `next/font/local`**, exposed as CSS variables and applied on ``. -6. **Metadata via the Metadata API**: a full root export plus per-page overrides (never hand-rolled `` tags). What the metadata contains is [seo.md](seo.md)'s concern. - -## Folder structure - -1. **Application code lives under `src/`**; `public/` stays at the repo root. The canonical layout: - - ```text - . - ├── public/ # static assets (fonts, images, favicons, files) - └── src/ - ├── app/ # App Router routes: layout.tsx, page.tsx, /page.tsx - ├── components/ # atomic design: atoms/ · molecules/ · organisms/ · templates/ - ├── constants/ # typed compile-time content + site config - ├── types/ # domain types - ├── themes/ # CSS token files (theme.css entry, helpers) - ├── fonts/ # next/font/local loader modules - ├── providers/ # context providers wired in the root layout - ├── hooks/ # shared React hooks - └── utils/ # helpers (cn/cva re-exports, dates, strings) - ``` - - Folders are added only when they earn their place: no empty scaffolding for layers a project doesn't use yet. diff --git a/docs/01-standards/performance.md b/docs/01-standards/performance.md deleted file mode 100644 index 2fc7046..0000000 --- a/docs/01-standards/performance.md +++ /dev/null @@ -1,10 +0,0 @@ -# Performance - -Fast is a feature; the presentation layer never gets to make the site feel slow. - -1. **LCP first.** Fast LCP on desktop and mobile; the first screenful renders without layout shift. -2. **Images lazy-load below the fold.** Decorative image layers (texture backgrounds, thumbnail walls) never block LCP. -3. **Vector geometry ships as optimized SVG**: marks, lines, letterforms, not raster. -4. **The presentation layer has a budget.** Entry and loading sequences are capped in duration; motion never blocks interactivity or input. -5. **Motion discipline.** Durations, easings, and variants are defined once and imported: no ad-hoc magic numbers per component. -6. **Font loading causes no flash of invisible text and no layout shift** on swap. diff --git a/docs/01-standards/process.md b/docs/01-standards/process.md deleted file mode 100644 index a81a52f..0000000 --- a/docs/01-standards/process.md +++ /dev/null @@ -1,176 +0,0 @@ -# Process - -How work happens: the sources of truth, how they stay honest with each other, -and how work is planned, parallelized, and reviewed. This doc is the methodology -layer and stays project-agnostic; the PRD and the plan derive -their structure from it. How change is recorded is -[git.md](git.md)'s concern. - -## The working loop - -Front-loaded on distillation and direction before any build: - -> Gather inspiration → distill the essence → set direction → design → plan implementation → deliver. - -The brief and observations stages of the PRD (§The PRD) are the path toward the -design: gathering, distillation, and direction-setting. The **design file is the -designed solution** that path produces, transcribed into the design contract. -Planning the implementation lays out the milestone graph (§Milestones) from the -PRD and the design; delivery runs each milestone through the same cycle -(§The delivery cycle). - -## The PRD - -`docs/02-prd/` is the numbered product pipeline, read in order; each stage derives -from the ones before it: - -| Stage | Owns | -| --- | --- | -| `01-brief.md` | The distilled intent: what it is, who it's for, the aesthetic, references | -| `02-observations.md` | Research and risks, each paired with the direction taken | -| `03-solution.md` | The settled design at concept level: concept, surfaces, systems | -| `04-design.md` | The design-token contract, transcribed from the design file | -| `05-architecture.md` | Stack, information architecture, repo structure, data layer | -| `06-plan.md` | The plan: the milestone graph (kinds, dependencies), cut from the stages above | - -- **Observations follow the priority frame**, the order problems get worked in: - 1. **The Problem**: one or two sentences. - 2. **The Hardest Failure Mode**: what breaks worst; design around it first. - 3. **Key Design Decisions**: the load-bearing choices everything else hangs - off. - 4. **What to Prototype First**: the riskiest slice to validate early; this - names the proving surface. -- **Directions are research, not contract.** An observation's direction lands - only when the design file (and its transcription in the design contract) - adopts it; where they conflict, the design contract wins. - -## Division of truth - -Three authorities, each owning a different kind of truth and each with the -rules that keep it honest: - -- **The repo holds law and state**: the PRD (ending in the plan, - `docs/02-prd/06-plan.md`, the milestone list with live status), the standards, - and the code; versioned, canonical for intent, contract, and work status. Docs and code - change together **in the same change**; a discovery the docs missed (a - token value, a variant, a breakpoint) is written back to the owning doc, - never left in a commit message or comment. Docs carry intent and contract; - function-level detail belongs in the code. Each fact lives in exactly one - owning doc: everywhere else points or summarizes, never restates, and when - two docs disagree the owner wins. The plan's milestone status is work state, - not contract; a fact that matters beyond a milestone moves to the owning doc. -- **Figma holds pixels**: design questions resolve against the Figma nodes, - not guesswork. Use structured design context (metadata/variables/code), not - screenshots, when reading Figma. A component isn't done until it's been - compared against its Figma node at desktop and mobile widths. -- **GitHub holds review**: PRs, machine checks, preview deploys. Nothing - lives only on GitHub; a milestone's status flips in the plan, in the - same PR as the work that completes it. - -When all three still leave a question genuinely ambiguous, ask; don't -improvise the product. - -## The delivery cycle - -Every milestone runs the same three phases. The human steers at the two cheap -points (the plan and the gate); agents and machines carry the middle. - -1. **Plan.** Scope comes from the PRD and the design frames: cut the - milestone into tasks by file ownership, map dependencies, mark trunk vs - leaf, tracked as task branches and PRs. An unknown that blocks the cut - gets a **spike** first: a throwaway experiment answering one question; - spike code is never merged, its answer is written back to the owning doc. - The human approves the cut before execution; steering a plan costs - minutes, steering merged code costs days. -2. **Execute.** Trunk tasks merge serially first; leaf tasks fan out in - parallel worktrees. Every task PR must pass the machine checks and an - agent review before merge (§Review). -3. **Gate.** The human reviews outcomes on the milestone branch's deployed - preview against the design frames at desktop and mobile widths, plus the - milestone's merged task PRs. Outcomes, not diffs; a human reads - code only on escalation. - -## Milestones: the human gates - -A milestone is a reviewable increment behind a human gate, instantiated as an -**entry in the plan** (`docs/02-prd/06-plan.md`) binding it to concrete scope, a -definition of done, and a status; its tasks are cut at its plan step and tracked -as branches and PRs. Milestones form a dependency graph, not a fixed sequence, laid -out in the plan (§The PRD, `06-plan.md`); three kinds set what may run in -parallel: - -| Kind | The work | Parallelism | -| --- | --- | --- | -| **System** | Creates or proves shared conventions: scaffold, tokens, the shell | Serial; nothing may consume unproven conventions | -| **Surface** | Delivers one surface on conventions already proven | Parallel with other surface milestones, as sibling branches with independent gates | -| **Sweep** | One cross-cutting pass over everything: coherence, polish, audits, launch | Serial, after the surfaces it sweeps | - -- **System milestones gate on a specimen.** A system milestone has no surface - to review, so its gate reviews a specimen artifact instead: a design-system - page rendering every token, ramp, and primitive, compared against the design - system file. The specimen stays in the site as a living styleguide route. -- **The readiness rule.** A milestone may open when everything it consumes is - merged and its inputs are settled: design frames in the design file, content - in the data source. An unready surface (undesigned, content missing) is a - waiting node, never a blocker for its siblings. -- **The proving surface.** The first surface milestone is chosen deliberately: - the riskiest or most representative surface, named by the observations - stage, built through every layer end to end. Its gate is what unlocks - surface parallelism; the milestone graph may scope it tighter than a full - surface. -- **The canonical arc.** Foundations (system) → the proving surface → the - remaining surfaces in parallel → polish and launch sweeps. Parallelism is - earned: it begins only once the proving surface's gate passes. -- **Launch is a sweep** with a checklist gate: metadata and SEO verified, - analytics live, performance budgets met, domain cut over. - -## Tasks: the agent work units - -A task is one unit of work an agent can complete unattended, carrying goal, -kind, owned files, dependencies, acceptance criteria, verification commands, and -the Figma node when visual; it lives as a branch and PR, not a persisted doc -entry. - -- **Scope by file ownership.** A task lists the file globs it owns; two - tasks may run in parallel only if their owned sets don't overlap. The same - disjointness applies across sibling milestone branches. -- **Trunk, then fan out.** Work touching shared files (theme, layout shell, - constants, utils) is a *trunk* task, serialized at the start of its - milestone; *leaf* tasks (components, pages) fan out afterwards in parallel - worktrees. -- **Shared discoveries become system work.** When parallel work uncovers a - shared need (a primitive two surfaces want), it lands on `main` as its own - small system task and sibling branches merge `main` forward; never two - parallel copies of the same convention. -- **Check the plan and open branches at task start**: the milestone's scope - and the sibling tasks in flight bound what may run in parallel. -- **Status flips with the work.** A task moves through its branch and PR - (open → in-review → merged) in the same PR as the change it describes; - blocked is a state carried on the PR, not a comment. - -## Branches and PRs - -- One branch per milestone (`feat/m02-works`), cut from `main`. -- One branch per task (`feat/m02-t04-works-ledger`), PR'd into the milestone - branch; the PR flips its task's status in the same diff. -- The milestone branch PRs into `main` at the gate; merge `main` forward into - any milestone branch that runs long. - -## Review - -Three tiers, split by kind, not by priority: - -- **Machines check mechanics.** Lint, types, tests, build, and a green preview - deploy gate every PR; a human never spends attention on what CI can catch. -- **Agents review correctness.** Every task PR, against the standards and - the task's acceptance criteria. -- **Humans review taste.** At plan and gate only (§The delivery cycle): the - qualities no check can score; fidelity to the design, motion feel, whether - the thing is good. - -## The board - -The board is a query, not a service: milestone status lives in the plan and -task status is the state of its open branches and PRs, so `docs/02-prd/06-plan.md` -plus the live PRs are always the board and git history is the audit trail. -Nothing is mirrored to an external tracker. diff --git a/docs/01-standards/seo.md b/docs/01-standards/seo.md deleted file mode 100644 index 825e27a..0000000 --- a/docs/01-standards/seo.md +++ /dev/null @@ -1,8 +0,0 @@ -# SEO - -The site is findable and previews well everywhere it's shared. - -1. **Full metadata at the root**: title, description, Open Graph, Twitter card, targeting the canonical domain, plus favicons and the dark `theme-color`. -2. **Every route has its own title and description.** Dynamic pages derive theirs from their data entry (title, intro as description, first media as the OG image). -3. **Real text in the DOM.** No content locked in images or canvas; heading and landmark structure follows the [accessibility](accessibility.md) baseline. -4. **Overlays and loading states never hide content from crawlers**: page content is server-rendered and present in the initial HTML regardless of lifecycle state. diff --git a/docs/01-standards/testing.md b/docs/01-standards/testing.md deleted file mode 100644 index e945aa5..0000000 --- a/docs/01-standards/testing.md +++ /dev/null @@ -1,11 +0,0 @@ -# Testing - -What gets tested and how. The current strategy: **none**. No tests are -written until a strategy is settled here; coverage is never a goal in itself. - -1. **Don't test everything.** Tests earn their place under the strategy this - doc will define; until then, don't add them speculatively. -2. **The plumbing stays warm.** Vitest stays wired and `pnpm test` stays - green (it passes with no tests), so a strategy can land without - re-plumbing. -3. **When tests exist, they are colocated** with what they test. diff --git a/docs/01-standards/writing.md b/docs/01-standards/writing.md deleted file mode 100644 index a9f7a7e..0000000 --- a/docs/01-standards/writing.md +++ /dev/null @@ -1,54 +0,0 @@ -# Writing - -How project prose reads: docs, the plan, PR and commit bodies. Where facts live is [process.md](process.md) §Division of truth's -concern; this doc owns the sentences. Site copy is out of scope, since its -voice is the design's. - -## Voice - -1. **Declarative, present tense.** State what is and what wins, not what should - ideally happen. No hedging, no marketing filler. -2. **Every sentence is load-bearing.** A sentence earns its place by adding a - fact, a rule, or a reason; otherwise cut it. Conciseness comes from selecting - what to say, not compressing how it's said: full sentences stay, whole - points go. -3. **Rationale rides along.** A rule carries its why in the same sentence, - attached with a colon, semicolon, or parenthetical; never a separate - paragraph of justification. -4. **One line of personality.** A doc's opening line may carry an aphorism; - everything after it is working prose. - -## Structure - -1. **Open with ownership.** A doc's first lines state what it owns and hand - neighboring topics to their owners ("what the metadata contains is seo.md's - concern"), then get to work. No table of contents, no preview of what the - doc is about to say. -2. **Bold-lead rules.** Rule lists are numbered; each item opens with a bold - lead naming the rule, then the detail. -3. **Tables carry enumerable facts** (tokens, stages, routes). Reasoning stays - in the surrounding prose, never in cells. -4. **Headings name what the section owns**, in sentence case, with a colon - gloss only when the bare name is opaque ("Milestones: the human gates"). - -## Economy - -1. **Summarize and point, never restate.** A neighboring doc's fact appears - only as a pointer or a one-line summary; this is the prose form of the - one-owning-doc rule. -2. **Standards name the PRD by role, not by link.** "The design contract's - concern," not a path into `docs/02-prd/`; standards stay standalone and - portable. Standards may link standards; PRD docs link each other freely. -3. **Link once.** A doc or term links at first mention; after that, plain text. - Section references use `§Section`, in-doc and across docs alike. - -## Mechanics - -- Filenames, tokens, commands, and identifiers in `code` format. -- **Bold** for rule leads and load-bearing terms; *italics* for one word of - stress at a time. Asterisk emphasis, never underscores. -- **No em dashes.** Join clauses with a colon, a semicolon, parentheses, or a - new sentence. -- Words over symbols in prose ("and", not "&"). -- **Don't use the agent's built-in memory system.** The repo is the memory: - durable guidance belongs in the owning doc under `docs/`. diff --git a/docs/02-prd/01-brief.md b/docs/prd/01-brief.md similarity index 100% rename from docs/02-prd/01-brief.md rename to docs/prd/01-brief.md diff --git a/docs/02-prd/02-design-system.md b/docs/prd/02-design-system.md similarity index 100% rename from docs/02-prd/02-design-system.md rename to docs/prd/02-design-system.md diff --git a/docs/02-prd/03-profile.md b/docs/prd/03-profile.md similarity index 100% rename from docs/02-prd/03-profile.md rename to docs/prd/03-profile.md diff --git a/docs/02-prd/04-compatibility.md b/docs/prd/04-compatibility.md similarity index 100% rename from docs/02-prd/04-compatibility.md rename to docs/prd/04-compatibility.md diff --git a/docs/02-prd/05-add-friends.md b/docs/prd/05-add-friends.md similarity index 100% rename from docs/02-prd/05-add-friends.md rename to docs/prd/05-add-friends.md diff --git a/docs/02-prd/06-matching.md b/docs/prd/06-matching.md similarity index 100% rename from docs/02-prd/06-matching.md rename to docs/prd/06-matching.md diff --git a/docs/02-prd/07-architecture.md b/docs/prd/07-architecture.md similarity index 100% rename from docs/02-prd/07-architecture.md rename to docs/prd/07-architecture.md