docs(claude): rewrite agent context for Veect

Project overview and Read First now describe the Veect control plane
(hosted design-to-code SaaS, ADR-027/028/029, docs/product/ as the
authoritative spec bundle, glossary Veect-domain vocabulary). The
versioning bullet reflects the root-only release-please policy, the
Quick Start conformance-rule miscount reads sixteen, and the Read First
qualifiers acknowledge events/realtime/audit cores are scaffolded.

Also retargets .claude/hooks/prompt-context.sh's Releases pointer from
the retired hybrid per-package scheme to the root-only policy and prunes
its deleted-feature tag examples (story 02 follow-up flag).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
2026-07-12 20:48:00 +02:00
parent e1a267d559
commit d7534b9926
2 changed files with 25 additions and 13 deletions

View File

@@ -41,7 +41,7 @@ if echo "$prompt" | grep -qE 'commit|message|changelog|conventional'; then
inject+=('Conventional Commits (non-negotiable): <type>(<scope>): <imperative subject> (≤72 chars). Types: feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert. Use `!` for breaking changes. Body explains WHY if non-obvious. Examples: feat(auth): hash password before persisting; refactor(docs)!: consolidate scaffolding into guides. See CLAUDE.md Key Conventions.')
fi
if echo "$prompt" | grep -qE 'release|version|bump|semver|tag\b'; then
inject+=('Releases: ADR-021 + docs/guides/releasing.md. Hybrid versioning — root template (template-v...) + 5 feature packages (auth-v..., blog-v..., etc.) version independently from 0.1.0. release-please reads Conventional Commits and opens a rolling release PR on every push to main; merging cuts per-package tags. Bump targeting is by commit-path, not (scope). Pre-1.0 policy: feat: -> patch, feat!: -> minor.')
inject+=('Releases: ADR-021 + docs/guides/releasing.md. Root-only versioning (the ADR-027 retrofit superseded the hybrid scheme) — release-please tracks a single root product version from 0.1.0 with plain v* tags. It reads Conventional Commits and opens a rolling release PR on every push to main; merging cuts the tag (v0.2.0) + GitHub release. Every commit path bumps the root; no per-package versions. Pre-1.0 policy: feat: -> patch, feat!: -> minor.')
fi
if echo "$prompt" | grep -qE 'refactor|deepening|shallow|architecture|seam|adapter|interface design|design it twice'; then
inject+=('Architecture refactors: invoke the improve-codebase-architecture skill (.claude/skills/improve-codebase-architecture/SKILL.md). Vocabulary: module (= feature by default in this repo) / interface / seam / adapter / depth / leverage / locality. Process: Explore -> Present numbered candidates -> Grilling loop. Hard constraints: respect ADRs 001-021 (factory-function shape, per-feature DI, manifest-first, generator-first, boundary tags, vendor isolation). Companion files: DEEPENING.md (dependency categories), INTERFACE-DESIGN.md (parallel sub-agent design pattern), LANGUAGE.md (vocab + this-repo identifier mapping).')

View File

@@ -1,4 +1,4 @@
# Clean Architecture Monorepo Template
# Veect — Control-Plane Monorepo
## Quick Start
@@ -8,7 +8,7 @@ pnpm dev # Start all dev servers
pnpm build # Build all packages
pnpm test # Run all tests
pnpm typecheck # TypeScript across all packages
pnpm lint # ESLint (incl. 15 conformance/* rules)
pnpm lint # ESLint (incl. 16 conformance/* rules)
pnpm conformance # Cross-feature event closure
pnpm fallow # Whole-codebase: dead exports, dupes, complexity
pnpm fallow:audit # AI-change audit (run before commits)
@@ -44,21 +44,33 @@ See `docs/guides/tdd-workflow.md` for the full cycle.
## Project Overview
Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`) owns its Clean Architecture layers. Must-have core packages (`core-shared`, `core-cms`, `core-api`) provide foundation; five optional core packages (`core-realtime`, `core-events`, `core-trpc`, `core-ui`, `core-audit`) scaffold on demand via `pnpm turbo gen core-package <name>` (see `docs/architecture/template-tiers.md`). Two tooling packages (`core-eslint`, `core-typescript`) provide shared configs. Workspace boundaries are enforced by ESLint (lint-time) and Turborepo (build-graph time). Supports Next.js and TanStack Start as frontend frameworks, Payload CMS for content management, and comprehensive agent-optimized documentation.
**Veect** (pronounced VEEKT) is a hosted design-to-code SaaS: it connects to a team's code repository, discovers the repo's real components and design tokens, lets a designer compose screens on a canvas constrained to that system, and publishes real TSX as an ordinary pull request. The authoritative product spec bundle lives in `docs/product/`read `docs/product/README.md` first; it defines which document wins when two disagree. Where the bundle conflicts with the repo's ADRs, the ADRs win:
- **ADR-027** — Veect v1 is a hosted cloud SaaS split into a **control plane** (this monorepo: auth, tenancy, workspace/project metadata, design-doc persistence, AI proxying, runner orchestration) and **workspace runners** (**cloud runner**: one isolated container per workspace; **local runner**: a CLI the developer runs against a local checkout), joined by a single **runner protocol**.
- **ADR-028** — the **iframe canvas**: the board renders real repo components through runner-served iframes (preview adapter + injected agent script over postMessage). NodeRenderer survives only in the **Playground** (the no-repo sandbox).
- **ADR-029** — **DesignDoc v1** (`design.veect.json`) is the canonical committed schema; the editor is rebuilt under template conventions. **Checkpoint** (codegen → parity check → atomic commit on the project branch) and **publish** (push branch + PR link) are the two git verbs.
Veect-domain vocabulary (control plane, workspace, project, runner, registry, iframe canvas, Playground, checkpoint, publish, …) is canonical in `docs/glossary.md` § "Veect product domain" — it wins over the product docs where they disagree.
**Repo shape:** Turborepo + pnpm monorepo organized by vertical features. One feature package so far (`auth`) owns its Clean Architecture layers; the Veect control-plane features (workspaces, projects, discovery, design-doc, editor, …) follow the same shape. Must-have core packages (`core-shared`, `core-cms`, `core-api`) provide foundation; eight optional cores are scaffolded and present (`core-trpc`, `core-ui`, `core-events`, `core-realtime`, `core-audit`, `core-analytics`, `core-consent`, `core-dsr`); new ones scaffold via `pnpm turbo gen core-package <name>` (see `docs/architecture/template-tiers.md`). Three tooling packages (`core-eslint`, `core-typescript`, `core-testing`) provide shared configs and test utilities. Three apps: `apps/web-next` (Next.js — the hosted editor shell + landing page), `apps/cms` (Payload admin), `apps/storybook`. Control-plane persistence is Payload CMS + Postgres (ADR-027). Workspace boundaries are enforced by ESLint (lint-time) and Turborepo (build-graph time).
## Read First
- `docs/glossary.md`**Canonical vocabulary** for the monorepo. Resolves "what does X mean here?" for every cross-cutting term (feature, use case, manifest, conformance, slice, dispatch, etc.). Shared between humans and agents.
- `docs/glossary.md`**Canonical vocabulary** for the monorepo, including the "Veect product domain" section (control plane, runner, runner protocol, iframe canvas, Playground, checkpoint, publish, …). Resolves "what does X mean here?" for every cross-cutting term. Shared between humans and agents.
- `docs/product/README.md` — Entry point to the authoritative product spec bundle in `docs/product/` (tech spec, design spec, UI gap spec, PRD, strategy docs) and the authority table for when documents disagree — as amended by ADR-027/028/029
- `docs/decisions/adr-027-hosted-saas-and-runner-split.md` — hosted SaaS topology: control plane / workspace runners / runner protocol
- `docs/decisions/adr-028-iframe-canvas.md` — the one-runtime invariant on the board; canvas protocol; Playground boundary
- `docs/decisions/adr-029-designdoc-v1-and-editor-rebuild.md` — DesignDoc v1 committed schema; editor rebuilt under template conventions
- `AGENTS.md` — Package map, boundary rules, per-package conventions
- `docs/architecture/overview.md` — High-level architecture and package responsibilities
- `docs/architecture/vertical-feature-spec.md` — Design spec with rationale and decision log
- `docs/guides/scaffolding-a-feature.md``turbo gen feature` reference (fast path; prefer this over the manual walkthrough)
- `docs/guides/adding-a-feature.md` — End-to-end new feature walkthrough (manual path; for cases the generator's scope doesn't cover)
- `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs; _requires `gen core-package events`_)
- `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers (_requires `gen core-package realtime`_)
- `docs/guides/audit-and-compliance.md` — DPA-compliant audit logging cookbook (_requires `gen core-package audit`_)
- `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs; `core-events` is scaffolded in this repo)
- `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers (`core-realtime` is scaffolded in this repo)
- `docs/guides/audit-and-compliance.md` — DPA-compliant audit logging cookbook (`core-audit` is scaffolded in this repo)
- `docs/guides/coverage.md` — 4-layer coverage cookbook (L0 vitest thresholds, L1 `pnpm coverage:diff`, L2 aggregate, L3 mutation; ADR-020)
- `docs/guides/releasing.md` — release-please workflow: how Conventional Commits become tagged versions + per-package CHANGELOGs (ADR-021)
- `docs/guides/releasing.md` — release-please workflow: how Conventional Commits become the single root product version + `CHANGELOG.md`, tagged `v*` (ADR-021, root-only since the ADR-027 retrofit)
- `docs/architecture/template-tiers.md` — must-have vs optional packages and how to scaffold the optionals
- `docs/guides/building-feature-ui.md` — Feature UI components, hooks, data fetching (tRPC + React Query), SSR prefetch/hydration, seed data, DI wiring
- `docs/guides/compliance-overview.md` — hub for operator compliance obligations: GDPR, cookie consent, DSR, and pre-launch checklist
@@ -94,8 +106,8 @@ See `docs/guides/coverage.md` for the cookbook and ADR-020 for the full rational
## Key Conventions
- **Conventional Commits (non-negotiable)** Every commit message MUST follow the [Conventional Commits](https://www.conventionalcommits.org/) spec: `<type>(<scope>): <imperative subject>` (≤72 chars). Types: `feat | fix | docs | style | refactor | test | chore | perf | ci | build | revert`. Use `!` after type/scope for breaking changes. Body explains WHY if non-obvious. Examples: `feat(auth): hash password before persisting`, `test(blog): assert article not found error`, `refactor(docs)!: consolidate scaffolding into guides`. The sandcastle implementer + reviewer prompts both enforce this; agents authoring commits autonomously MUST honor it. Commits become versions + changelog entries automatically via release-please (ADR-021 / `docs/guides/releasing.md`).
- **Versioning is hybrid (ADR-021)** Root template (`template-vertical`) + 1 feature package (`@repo/auth`) each version independently from `0.1.0`. release-please reads Conventional Commits since the last tag and opens a rolling release PR on every merge to main; merging it cuts per-package tags (`template-v0.2.0`, `auth-v0.1.1`, etc.) + GitHub releases. **Bump targeting is by commit path** files under `packages/<feature>/**` bump that feature; cross-cutting paths (`docs/`, `scripts/`, `.github/`, root configs) bump the root. Pre-1.0 policy: `feat:` patch, `feat!:` minor.
- **Conventional Commits (non-negotiable)** Every commit message MUST follow the [Conventional Commits](https://www.conventionalcommits.org/) spec: `<type>(<scope>): <imperative subject>` (≤72 chars). Types: `feat | fix | docs | style | refactor | test | chore | perf | ci | build | revert`. Use `!` after type/scope for breaking changes. Body explains WHY if non-obvious. Examples: `feat(auth): hash password before persisting`, `test(auth): assert invalid credentials error`, `refactor(docs)!: consolidate scaffolding into guides`. The sandcastle implementer + reviewer prompts both enforce this; agents authoring commits autonomously MUST honor it. Commits become versions + changelog entries automatically via release-please (ADR-021 / `docs/guides/releasing.md`).
- **Versioning is root-only (ADR-021, amended by the ADR-027 retrofit)** Veect is a hosted SaaS deploying continuously, so release-please tracks a **single root product version** from `0.1.0` with plain `v*` tags (`include-component-in-tag: false`). It reads Conventional Commits since the last tag and opens a rolling release PR on every merge to main; merging it cuts the tag (`v0.2.0`) + GitHub release + root `CHANGELOG.md`. Every commit path bumps the root there are no per-package versions or tags. Pre-1.0 policy: `feat:` patch, `feat!:` minor.
- **Relative imports in `src/`** Source files use relative paths (`../repositories/...`), not `@/` alias
- **`@/` alias in tests** Test files (`*.test.ts`) use `@/` to import from `src/`
- **`vitest.config.ts`** Every package must define `resolve.alias: { "@": path.resolve(__dirname, "./src") }`
@@ -117,7 +129,7 @@ See `docs/guides/coverage.md` for the cookbook and ADR-020 for the full rational
- **Spans + capture composed at DI bind time** Use cases + controllers are wrapped at DI bind time in this order (outermost innermost): `withSpan → withCapture → withAudit → withAnalytics → withConsent → factory(deps)`. Apply `withAudit` when the manifest declares `audits`, `withAnalytics` when it declares `analyticsEvents`, `withConsent` when it declares `requiresConsent`. `withSpan` is always outermost so an errored span's timing reflects the capture-and-rethrow. Repository methods are different they call `this.tracer.startSpan(...)` and `this.logger.captureException(...)` inline per method because they own per-call attributes
- **Capture at throw sites only, with double-report guard** Repos capture infra errors inline; use cases + controllers capture via `withCapture` at bind time; `defineErrorMiddleware` never captures. Each error gets a non-enumerable `__sentryReported` flag the first time it's captured; `withCapture`, `OtelLogger`, and `RecordingLogger` all bail if the flag is set, so a bubbled error surfaces exactly once with the inner-most layer's tags (helper at `core-shared/instrumentation/reported-flag.ts`)
- **PII handling is non-negotiable** `sendDefaultPii: false` everywhere (CI grep gate); replay default-masks all text/inputs/media (allowlist starts empty); `setUser({ id })` only no email/username; server-side PII scrubbing happens at the OTel processor layer (`PiiScrubSpanProcessor` + `PiiScrubLogRecordProcessor`) before any exporter sees the data (ADR-017 §7)
- **Two apps, two Sentry projects** `WEB_NEXT_SENTRY_DSN`, `CMS_SENTRY_DSN`. The browser DSN uses the `NEXT_PUBLIC_` prefix (web-next)
- **Two Sentry projects** `WEB_NEXT_SENTRY_DSN`, `CMS_SENTRY_DSN` (storybook is not instrumented). The browser DSN uses the `NEXT_PUBLIC_` prefix (web-next)
- **Instrumentation binding is orthogonal to repo binding** `bindAll()`'s Rule 0 (DSN OTel+Sentry vs Noop) is independent of `USE_DEV_SEED` / `NODE_ENV`. Run `pnpm dev` with `WEB_NEXT_SENTRY_DSN` set to test the integration locally
- **Cross-feature events go through `IEventBus` (E0)** In-feature reactions are direct use-case calls, not bus publishes. The bus is for _crossing_ feature boundaries (e.g. an `auth` signed-up event consumed by another feature)
- **Event contracts are public; handlers are private (E1)** Publisher's `events/<x>.event.ts` is exported from the feature root barrel. Consumer's `events/handlers/on-<publisher>-<event>.handler.ts` is never re-exported (ESLint-enforced via `core-eslint/rules/no-handler-reexport`)
@@ -131,7 +143,7 @@ See `docs/guides/coverage.md` for the cookbook and ADR-020 for the full rational
- **Reader cycles are a design error (Q3)** If Feature A reads from Feature B and vice versa, the boundaries are wrong. Break via: (a) UI composition at app layer, (b) event for one direction, (c) merge the features
- **Readers wrap existing use cases, not repositories** The reader is a thin facade; if the domain logic doesn't exist as a use case yet, create the use case first (manifest-first). No `MockReader` needed same class works in dev-seed because the use cases beneath it are backed by mock repos
- **Manifest `reads` field** Use cases that query another feature's reader declare `reads: ["<feature>"]` in `feature.manifest.ts`. Verified by `assertFeatureConformance` at boot and `no-undeclared-reader` ESLint rule
- **Binders return readers; `bindAll()` threads them** `bindProductionAuth(ctx)` returns `{ reader: IAuthReader }`. `bindAll()` passes it: `bindProductionBlog(ctx, { authReader: authResult.reader })`. Ordering in `bindAll()` is explicit owning feature first, consumers after
- **Binders return readers; `bindAll()` threads them** `bindProductionAuth(ctx)` returns `{ reader: IAuthReader }`. `bindAll()` passes it: `bindProductionX(ctx, { authReader: authResult.reader })`. Ordering in `bindAll()` is explicit owning feature first, consumers after
- **Manifest-first ordering** for any new use case, the workflow is **(1) manifest entry** **(2) contracts** (`xInputSchema`, `xOutputSchema`, `IXUseCase`) **(3) tests (red)** **(4) implementation (green)**. The generator emits the manifest + a self-asserting `bind-production.ts` so new features are conformance-compliant by default
- **Self-asserting `bindProductionX(ctx)`** every feature's bind-production calls `assertFeatureConformance(container, manifest, symbols, ctx)` at its tail. `pnpm dev` refuses to boot on drift
- **`pnpm conformance`** cross-feature event-closure and reader-closure check; fails CI on orphan consumers or unresolvable `reads` entries