Commit Graph

262 Commits

Author SHA1 Message Date
8f34daca36 docs(dev-seed): canonical doc updates + refactor-log entry
- CLAUDE.md Key Conventions: 'App bootstrap' rule rewritten as 'Three
  binding modes per feature' — describes USE_DEV_SEED + NODE_ENV
  resolution order and the new ./di/bind-dev-seed export.
- AGENTS.md (root): exports list now mentions ./ui + ./di/bind-dev-seed;
  Per-feature public-API surface table gains a row; Apps section shows
  the bindAll() dispatcher with three-rule logic.
- docs/architecture/vertical-feature-spec.md §6: file shape now
  includes bind-dev-seed.ts, bind-dev-seed.test.ts, __seeds__/dev.ts;
  package.json exports list updated to include ./di/bind-dev-seed.
- docs/architecture/data-flow-explainer.html: anatomy tree gains
  __seeds__/ row; LAYERS.di description updated with new binders +
  cross-link to di-explainer.html; new LAYERS.seeds entry; public-
  surface card expanded to six subpaths.
- docs/superpowers/refactor-logs/2026-05-06-input-output-unification.md
  §7: new 'Post-Plan-9: dev-seed binders' entry summarizing the rollout
  (commits, per-feature additions, app wiring, tests, turbo, docs).
- bind-production.test.ts: dispatcher tests use vi.stubEnv (typesafe
  way to test process.env in TypeScript 5+ with @types/node read-only
  process.env types). 4 dispatcher tests + 2 bindAllProduction tests
  = 7 tests total.
2026-05-06 19:49:58 +02:00
6bf19f35c5 feat(app): bindAll() now checks NODE_ENV in addition to USE_DEV_SEED
Three-rule resolution order in bindAll() (first match wins):

  1. USE_DEV_SEED === 'true'   → bindAllDevSeed (explicit override)
  2. NODE_ENV    === 'production' → bindAllProduction
  3. otherwise                  → bindAllDevSeed (developer default)

Rationale: 'pnpm dev' should boot the app without requiring Payload to
be running locally — dev seed is the more useful default for non-
production environments. Production servers explicitly set
NODE_ENV=production and get the real binding. The USE_DEV_SEED override
remains the escape hatch (force seed in any NODE_ENV — e.g. staging
preview, design review).

bind-production.test.ts grows from 3 tests to 8 — covers the dispatcher
matrix:
- USE_DEV_SEED='true' wins even when NODE_ENV='production'
- NODE_ENV='production' (no override) → production
- NODE_ENV='development' → dev seed (default)
- NODE_ENV unset → dev seed (default)
- USE_DEV_SEED='false' treated as not-set (only the literal 'true' triggers)
- Pre-existing 'binds all five repos' test now also asserts bindProductionMedia

di-explainer.html conditions table + mode flag strings updated to match
the new three-rule logic.
2026-05-06 19:32:00 +02:00
61dde18b53 chore(turbo): declare USE_DEV_SEED in globalEnv
Earlier commit 74b88f7 attempted this but the Edit failed silently
without a prior Read. ESLint's turbo/no-undeclared-env-vars rule was
still flagging the warning.
2026-05-06 19:21:24 +02:00
74b88f74da fix(turbo+docs): declare USE_DEV_SEED in turbo globalEnv; correct DI explainer
ESLint flagged that USE_DEV_SEED was read in apps/web-next without being
declared in root turbo.json globalEnv — added it.

DI explainer's conditions table previously listed 'Production server
(NODE_ENV=production)' as a scenario, but bindAll() only checks
USE_DEV_SEED — NODE_ENV is not read anywhere in source. Fixed the table
and the prod-mode flag string to match what the code actually does.
2026-05-06 19:21:00 +02:00
68e934c0a5 feat(app): wire bindAll() + bindAllDevSeed() dispatcher; add DI explainer page
apps/web-next/src/server/bind-production.ts now exports three functions:
- bindAllProduction() — production-only binders
- bindAllDevSeed() — dev-seed-only binders (NEW, calls all 5 features)
- bindAll() — dispatcher that branches on USE_DEV_SEED env var

All page/route callers (page.tsx, about/page.tsx, blog/[slug]/page.tsx,
api/trpc/[trpc]/route.ts) updated from bindAllProduction → bindAll so the
env flag actually has effect.

docs/architecture/di-explainer.html (NEW): standalone interactive page
explaining the di/ folder file-by-file, the loading sequence (8 stages),
the three binding kinds (.to / .toDynamicValue / .toConstantValue), an
interactive three-mode picker showing how the same blogContainer state
differs across default/dev-seed/production, a conditions table, and a
final card on how tests bypass DI entirely. Sister page to
data-flow-explainer.html.

Refactor log entry + canonical doc updates follow in subsequent commits.
2026-05-06 19:10:29 +02:00
10479c4d55 feat(features): add bind-dev-seed binders for auth/marketing-pages/navigation/media
Mirrors the canonical blog pattern landed earlier on this branch.

Per feature:
- src/__seeds__/dev.ts — lazy buildDev<Entities>() function using the
  feature's existing factory for sensible defaults
- src/di/bind-dev-seed.ts — bindDevSeed<Feature>() async function that
  rebinds the repo symbol(s) to a populated MockXRepository via
  .toConstantValue
- src/di/bind-dev-seed.test.ts — 3+ tests per feature (populates,
  reachable by id/slug, idempotent)
- package.json — adds ./di/bind-dev-seed subpath export

Tests + use cases continue to construct mocks directly; the seed never
runs from a *.test.ts path. App boot wiring (USE_DEV_SEED env branch)
follows in a separate commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 19:04:33 +02:00
e6560bc9cb feat(blog): add bind-dev-seed binder + dev seed
Sets the canonical pattern for all 5 features. Three new files:

- src/__seeds__/dev.ts — buildDevArticles() function returning 3
  realistic articles (welcome, vertical-feature-architecture,
  wip-post) built from articleFactory with id/slug/title/status
  overrides only.
- src/di/bind-dev-seed.ts — bindDevSeedBlog() async function that
  unbinds IArticlesRepository, constructs MockArticlesRepository,
  seeds it via buildDevArticles(), and rebinds via .toConstantValue.
- src/di/bind-dev-seed.test.ts — 3 tests: populated repo, welcome
  article reachable by slug, idempotent (callable twice).

package.json adds the ./di/bind-dev-seed subpath export, parallel to
./di/bind-production.

Tests + use cases continue to construct MockArticlesRepository
directly — they never go through bindDevSeedBlog. The seed only attaches
when called explicitly at app boot.
2026-05-06 19:00:31 +02:00
449a4aedf5 docs(arch): rewrite §04 framing — drop 'mock is the surprising one'
User pushback: 'I already need mock data for dev and for testing at
runtime' — i.e., the dual role of the mock is obvious, not surprising.
Earlier framing was condescending.

Reframe around 'runtime reach':
- Section blurb leads with 'three artifacts at different distances
  from runtime'
- Three-roles card intro: same neighborhood, different reach. Mock is
  reached by runtime; contract + factory only by tests.
- 'The mock has two jobs' → 'The mock is reached from two directions
  — both legitimate, neither is the test version'.
- Contract framing now leads with its real purpose: it tests the mock
  alongside the real impl so you can trust the mock as a runtime
  artifact.
2026-05-06 18:46:23 +02:00
ea17e6f998 docs(arch): expand §04 with mock vs contract vs factory distinction
User asked: 'arent mocks also related to testing?' — yes, but the mock
plays two roles where the contract and factory play one each. §04 now
opens with that framing.

What's new:
- Section title bumped to 'Mocks, contracts & factories'
- New three-roles diagram at the top of §04 visualizing the chain:
  IArticlesRepository → MockArticlesRepository + ArticlesRepository
  → articlesRepositoryContract → articleFactory
- Two ordered lists explaining the mock's dual job (DI default binding
  + direct test fake) and the contract/factory's single test-only roles
- Three new expandable code examples:
  · the mock as DI binding (real BlogModule code)
  · the mock as direct test fake (use-case test, no container)
  · the contract running against both impls (proof-of-parity)
- New CSS for .three-roles-diagram, .role-* boxes, .role-arrow with
  vertical connector lines, .role-jobs lists with counter-leading
  decimal numbering

The existing Contracts and Factories cards stay in place below — they
provide the deeper detail on each individual artifact.
2026-05-06 18:42:06 +02:00
1b7e5eac50 docs(arch): add interactive data-flow explainer page
Single-file HTML at docs/architecture/data-flow-explainer.html.
Self-contained — Google Fonts (Fraunces + JetBrains Mono) is the only
external resource; all interactivity is vanilla JS, all diagrams are
inline SVG/CSS.

Five sections:
  01. Feature anatomy — clickable folder tree, layer detail card swaps
      to explain entities / application / infrastructure / interface-
      adapters / di / integrations / ui / __factories__ / __contracts__
      / public surface.
  02. Request flow — step-through pipeline (12 stages, including the
      success/error fork) with prev/next/play and a feature picker
      (auth, blog, marketing-pages, navigation, media). Each feature
      swaps real code snippets, the procedures.ts error map, and the
      use-case/controller pattern.
  03. Dependency injection — interactive DI canvas with default/prod
      toggle so the user sees the same symbol resolving to mock vs
      real Payload-backed impl. Real module.ts and bind-production.ts
      code blocks below.
  04. Contracts and factories — expandable sections with the actual
      defineContractSuite + defineFactory code from packages/blog.
  05. Verdict — short answer (yes), tradeoffs, badge row.

Editorial aesthetic: cream paper, deep ink, oxblood accent, Fraunces
display + JetBrains Mono code. Subtle paper noise + ruled-line bg.
No CDN scripts beyond fonts.
2026-05-06 17:57:57 +02:00
881b468638 docs(refactor-logs): tick all doc-update checklist items in Plan 8 + Plan 9 logs
Combined post-Plan-9 doc-update pass complete:

Plan 8 checklist (14 items): all ticked.
- CLAUDE.md, AGENTS.md root, adding-a-feature, tdd-workflow, testing-
  strategy, vertical-feature-spec, overview, dependency-flow, ADR-012,
  per-feature AGENTS ×5, core-testing AGENTS, auth AGENTS, media AGENTS,
  Plan 7 plan/spec annotation.

Plan 9 checklist (13 items, 1 already ticked): all ticked.
- CLAUDE.md, AGENTS.md root, adding-a-feature, tdd-workflow, testing-
  strategy (already ticked previously), vertical-feature-spec, overview,
  dependency-flow, ADR-012 cross-ref, ADR-013, per-feature AGENTS,
  core-testing AGENTS, core-shared AGENTS, Plan 8 plan/spec annotation.

Final validation:
- pnpm typecheck: 14/14 packages green
- pnpm lint: 15/15 packages green
- pnpm test: 360 tests across 15 suites, all passing
- pnpm turbo boundaries: 366 files checked, no issues
2026-05-06 16:53:17 +02:00
95613ed126 docs(spec): vertical-feature-spec §9.4 — list ./ui + ./di/bind-production in exports
Doc-pass agent flagged §9.4 still listed only '.', './cms', './api' as
the allowed public surface. ./ui was added in Plan 9 and
./di/bind-production in Plan 5; both belong in the canonical list.
2026-05-06 16:50:54 +02:00
d1d792c72d docs(spec): vertical-feature-spec.md — Plan 8 + Plan 9 file shape and testing updates
§6 Feature package internal shape: now shows the post-Plan-9 layout
(entities/models, entities/errors, .repository.{mock.ts, ts,
interface.ts} naming, integrations/api/procedures.ts, ui/index.ts,
package.json ./ui subpath). Request flow box updated to show
xProcedure + xInputSchema + presenter + middleware lanes.

§10 Test placement + tooling: §10.3 now shows direct factory injection
for use-case + controller tests (the post-Plan-9 default). Router tests
retain container rebinding because tRPC resolves controllers via DI.
New §10.6 'Test obligations per layer' table maps R10, R24, R25, R26,
R27, R28 to their required layer.

§10.4 updated to reflect 360 tests across 26 packages; cross-links to
Plan 8 + Plan 9 refactor log Summary sections.

§11 doc note: ADR-012 + ADR-013 added as §11.6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:49:28 +02:00
ce294b3041 docs(guide): tdd-workflow.md — Plan 9 mocking + R25/R26/R27/R28 patterns
§1 worked example rewritten to direct factory injection (no container
rebinding). §4 mocking decision tree updated. New §sections for R25
output-validation tests, R26 router error-mapping tests, R27/R28
presenter-shape tests. §9 contract-suite paths use the post-Plan-8
.mock.ts suffix.

Refactor log doc-update checklist: tdd-workflow.md ticked.
2026-05-06 16:48:39 +02:00
edc98f8f9a docs(agents): per-feature + core-testing AGENTS.md for Plan 8 + Plan 9 conventions
Each per-feature AGENTS.md now reflects the post-Plan-9 layout:
entity/error paths, public-API split (./ui), use-case schemas, presenter
pattern, feature-scoped tRPC error map, and feature-specific
errors-to-codes table.

core-testing/AGENTS.md gains a Plan 9 test-patterns section documenting
R25 (output validation), R26 (router error mapping), R27/R28
(presenter shape) test obligations.

auth: documents real PayloadUsersRepository + AuthenticationService and
the deferred session methods.
media: documents the full Clean Architecture scaffold introduced in
Plan 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 16:47:56 +02:00
732fa63f69 docs(refactor-log): tick testing-strategy.md in Plan 9 doc-update checklist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:47:39 +02:00
e0a592baa7 docs(guide): testing-strategy.md — direct factory injection + R25/R26/R27/R28 obligations
Direct factory injection is now the default mocking pattern (Plan 8).
Container rebinding is reserved for router-level tests.
rebindRepository helpers removed — use cases and controllers are factory
functions; tests construct mocks and pass them in.

New 'Test obligations per layer (Plan 9)' table maps each layer to its
required test types: R10 (controller input), R25 (use-case output
validation), R26 (router error mapping), R27/R28 (presenter view shape).

Refactor log doc-update checklist: testing-strategy.md ticked.
2026-05-06 16:47:30 +02:00
9c9d01b9f6 docs(agents): root AGENTS.md updated for Plan 8 + Plan 9 conventions
Per-Package Conventions now reflect post-Plan-9 reality:
- Source-file relative-import example uses entities/models/<x> path
- New subsections for use-case schemas (R1–R5), controller presenter
  (R7–R12), feature-scoped tRPC error mapping (R13–R17), and the
  per-feature public-API split (R18–R21)
- bindProduction* + repository class examples align with the post-Plan-8
  naming (no Payload prefix, dropped .js extensions in import samples)

Refactor log doc-update checklist: AGENTS.md (root) item ticked.
2026-05-06 16:45:29 +02:00
ef2b8e300e docs(plan-9): doc-pass slice 1 — CLAUDE.md, core-shared AGENTS, architecture, plan-8 annotations
First slice of the combined Plan 8 + Plan 9 doc-update pass:
- CLAUDE.md Key Conventions: append schema-in-use-case, presenter,
  controller unknown input, feature-scoped tRPC error mapping, public
  surface split (./ui)
- packages/core-shared/AGENTS.md: document defineErrorMiddleware export
  + t re-export from trpc/init
- docs/superpowers/plans/2026-05-05-plan-8-*.md and matching spec:
  one-line note that some controller/router patterns shifted in Plan 9;
  link to the Plan 9 refactor log
- docs/architecture/overview.md: data-flow box now shows xProcedure +
  xInputSchema + xOutputSchema.parse + presenter + middleware lanes;
  three explanatory paragraphs added (schemas, presenter, error mapping)
- docs/architecture/dependency-flow.md: app-side ./ui subpath note,
  allowed/disallowed examples updated for Plan 9 paths

Remaining doc-pass items (root AGENTS.md, per-feature AGENTS.md ×5,
core-testing AGENTS.md, adding-a-feature.md, tdd-workflow.md,
testing-strategy.md, vertical-feature-spec.md) follow in subsequent
commits — to be dispatched in parallel.
2026-05-06 16:43:13 +02:00
3dc843ca4b docs(refactor-log): reconcile commit count + test delta inconsistencies
Final reviewer flagged two changelog inaccuracies:
- Summary said 14 commits; actual is 15 (88db39b..HEAD).
- §7 Task 8 said +144 tests; correct delta is +35 (325 → 360, +11%).
  The +144 figure was a typo from the implementer's draft.

Both reconciled. Plan 9 ships.
2026-05-06 16:15:50 +02:00
36548942d4 docs(adr): ADR-013 input/output unification + Plan 9 changelog summary
Records the Plan 9 architectural decision (schemas in use-case file,
runtime output validation, presenter pattern, feature-scoped error
middleware, ./ui subpath split). ADR-012 gets a one-line cross-
reference to the new ADR. Refactor log gets a Summary section with
commit table and conformance checklist.

Plan 9 complete. The deferred doc-update pass (CLAUDE.md / AGENTS.md /
guides) — combined with the still-pending Plan 8 items — is the next
follow-up.

Refactor log: Summary, doc-update checklist
Spec: R29, R30
2026-05-06 16:10:27 +02:00
2df137c70c chore(plan-9): final verification + changelog summary
Straggler fixes: web-next and web-tanstack app callers did not pass {}
to queryOptions()/caller calls after Plan 9 added .input(z.object({}).strict())
to siteSettings and header procedures. All 360 tests pass, full typecheck
green across 14 packages. Refactor log §7 updated with verification summary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:07:36 +02:00
2b67964213 refactor(media): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getMedia, listMedia); deleteMedia
  has input schema only (void output, R12 — no presenter).
- Controllers: unknown input + identity presenter on getMedia/listMedia;
  Promise<void> on deleteMedia.
- New integrations/api/procedures.ts with mediaProcedure
  ([InputParseError → BAD_REQUEST], [MediaNotFoundError → NOT_FOUND]).
- Router uses mediaProcedure + .input(xInputSchema).
- src/index.ts exports schemas + types; src/ui/index.ts placeholder
  (media has no queries today); package.json adds ./ui subpath.
- R25 + R26 tests added.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:41:08 +02:00
aff0ce092d docs(refactor-log): record R6 fix-up under §7 2026-05-06 15:33:53 +02:00
9663c82624 fix(errors): set this.name in every domain error constructor (R6)
Spec reviewer caught a systemic gap during Task 6 (navigation) review:
Plan 8 left every feature's domain error class with a constructor that
didn't set this.name = '<ClassName>'. Plan 9 spec R6 requires it.

Fixed across all 10 error files:
- auth: AuthenticationError, UnauthenticatedError, UnauthorizedError, InputParseError
- blog: ArticleNotFoundError, InputParseError
- marketing-pages: PageNotFoundError, InputParseError
- navigation: HeaderNotFoundError, InputParseError
- media: MediaNotFoundError, InputParseError

Functionally a no-op — defineErrorMiddleware uses instanceof, not name —
but ensures correct serialization, stack traces, and JSON inspection.

Refactor log: §7
Spec: R6
2026-05-06 15:33:28 +02:00
27c79e6e1f refactor(navigation): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- getHeader use case: input z.object({}).strict() (R5); output =
  headerSchema parsed at runtime.
- getHeader controller: unknown input + identity presenter.
- New integrations/api/procedures.ts with navigationProcedure
  ([InputParseError → BAD_REQUEST], [HeaderNotFoundError → NOT_FOUND]).
- Router uses navigationProcedure + .input(getHeaderInputSchema).
- src/index.ts: remove headerQuery; export schemas + IUseCase/Controller
  aliases.
- src/ui/index.ts (NEW); package.json adds ./ui subpath.
- R25 + R26 tests added.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26
2026-05-06 15:23:30 +02:00
f4adf315af refactor(marketing-pages): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getPageBySlug, getSiteSettings).
  Site-settings input is z.object({}).strict() per R5 (uniform input).
- Controllers: unknown input + identity presenter; void output not
  applicable (both use cases return data).
- New integrations/api/procedures.ts with marketingPagesProcedure
  ([InputParseError → BAD_REQUEST], [PageNotFoundError → NOT_FOUND]).
- Router uses marketingPagesProcedure + .input(xInputSchema).
- src/index.ts: remove pageBySlugQuery/siteSettingsQuery; export
  schemas + types + IUseCase/IController aliases.
- src/ui/index.ts (NEW); package.json adds ./ui subpath.
- R25 output-validation tests + R26 router error-mapping test.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26
2026-05-06 15:15:02 +02:00
614c9014ad style(blog): add section dividers + drop redundant presenter comment
Code-quality reviewer flagged stylistic divergence from auth's pattern:
- All 3 blog use cases now have // ── Input ──... / ── Output ──... /
  ── Use case ──... section dividers (consistent with auth Task 3 + plan
  template §4.1).
- Removed inline comment in get-articles controller's presenter that
  appeared in only 1 of 3 controllers; identity presenters are
  self-explanatory.
2026-05-06 15:10:16 +02:00
86070b236a refactor(blog): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getArticles, createArticle,
  getArticleBySlug). Output validated via outputSchema.parse before
  return. status field uses articleStatusSchema (was loose `string`).
- Controllers: receive `unknown`; safeParse with use-case schema;
  identity presenter (R11) on every controller.
- New integrations/api/procedures.ts with blogProcedure
  ([InputParseError → BAD_REQUEST], [ArticleNotFoundError → NOT_FOUND]).
- Router uses blogProcedure + .input(xInputSchema) for all 3 procedures.
- src/index.ts: remove articleBySlugQuery/listArticlesQuery re-exports;
  export schemas + types + IUseCase/IController aliases.
- src/ui/index.ts (NEW): query builders moved here; package.json adds
  ./ui subpath.
- New tests: R25 output-validation per use case; R26 router error-
  mapping (NOT_FOUND on missing slug, BAD_REQUEST on schema fail).

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:04:53 +02:00
70c7b7dfe7 test(auth): tighten R25 + sign-in controller assertions per code review
Code-quality reviewer flagged:
- R25 'malformed output' tests used .rejects.toThrow(/parse|invalid/i)
  which could match unrelated errors. Replaced with
  .rejects.toBeInstanceOf(ZodError) for both sign-in and sign-up.
- sign-in controller test asserted result.name only as truthy; the
  parallel sign-up test was already precise (toBe('session')). Tightened
  to match.

61 tests still passing for @repo/auth.
2026-05-06 13:03:37 +02:00
5b61674fe9 docs(refactor-log): populate §6.3 with auth presenter-shape test note
Spec reviewer noted §6.3 was missed during Task 3 commit. The presenter
tests exist in code (sign-in / sign-up controller tests assert cookie
shape, not full use-case output); the changelog just didn't record it.
Pure docs change.
2026-05-06 13:01:39 +02:00
2bbec70a4e refactor(auth): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (signIn, signUp); input-only for
  signOut (void output). Use case body validates output via
  outputSchema.parse before returning.
- Controllers: receive `unknown`; safeParse with the use-case schema;
  presenter (returning cookie) for signIn/signUp; void return for
  signOut.
- New integrations/api/procedures.ts with authProcedure built via
  defineErrorMiddleware([[InputParseError,"BAD_REQUEST"],
  [AuthenticationError,"UNAUTHORIZED"], [UnauthenticatedError,
  "UNAUTHORIZED"], [UnauthorizedError,"FORBIDDEN"]]).
- Router uses authProcedure + .input(xInputSchema) for every procedure.
- src/index.ts exports schemas + types + IUseCase/IController aliases.
- package.json gains ./ui subpath; src/ui/index.ts placeholder
  (auth has no query builders today).
- New tests: R25 output-validation per use case (signIn, signUp);
  R26 router error-mapping (UNAUTHORIZED on missing user,
  BAD_REQUEST on schema fail).

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18, R19, R22–R26
2026-05-06 12:58:10 +02:00
aac37fd9af docs(core-shared): correct defineErrorMiddleware jsdoc to match implementation
Code-quality reviewer flagged a stale 'try/catch' phrase in the jsdoc
that didn't match the actual result.ok inspection pattern. Updated
description to accurately describe how tRPC v11 middleware sees errors
(returned result, not thrown exception) and how the middleware
discriminates and rethrows.

Pure docstring change — no behavioral or signature impact.
2026-05-06 11:54:51 +02:00
e25b1f7a1c feat(core-shared): add defineErrorMiddleware factory + export t
Factory takes [[ErrorCtor, TRPC_CODE], ...] tuples and returns a tRPC
middleware that translates matching domain errors to TRPCError. Discrim-
inates by instanceof; preserves original error as cause; unmapped
errors propagate (tRPC then wraps them as INTERNAL_SERVER_ERROR with
the original error as .cause — middleware does not interfere).

core-shared never enumerates feature errors — each feature passes its
own constructors in via integrations/api/procedures.ts (Tasks 3-7).

Also exports the `t` instance from trpc/init.ts so feature procedure
files can do t.procedure.use(...).

Also fixes tsconfig.json: rootDir set to "." and @/* path alias added
so test files using @/ resolve correctly under tsc --noEmit.

Refactor log: §1, §2, §4
Spec: R13–R17
2026-05-06 11:43:45 +02:00
61baaae99a docs(refactor-log): scaffold Plan 9 input/output unification changelog
Empty section template plus the doc-update checklist that the
post-Plan-9 follow-up pass will work through (combined with the still-
pending Plan 8 items so docs are written once).

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md §10, R30.
2026-05-06 11:00:47 +02:00
88db39b3a3 docs(plan): Plan 9 — input/output unification implementation plan
9 tasks, TDD throughout, one commit per task:

1. Refactor changelog scaffold
2. core-shared/trpc/define-error-middleware.ts factory + tests
3. auth migration (3 use cases — schemas + presenter + procedures.ts + router + ./ui + tests)
4. blog migration (3 use cases)
5. marketing-pages migration (2 use cases)
6. navigation migration (1 use case)
7. media migration (3 use cases)
8. Final verification + boundary sweep
9. ADR-013 + final changelog summary

Every step has concrete code; no placeholders. Self-review shows full
spec coverage (R1–R30) with each rule mapped to one or more tasks.

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:29:28 +02:00
4b6b61ab4c docs(spec): Plan 9 — input/output unification + presenter pattern + feature-scoped error mapping + public-surface cleanup
Codifies a single source of truth for use-case input/output contracts:

- Every use case exports xInputSchema/XInput and xOutputSchema/XOutput
  from its own file; controllers and tRPC procedures import the same
  schema. Use case body runtime-validates output via .parse before
  returning.
- Controllers gain a co-located top-level `function presenter`
  (Lazar-style) that reshapes entity output to view DTO; controller
  return type = ReturnType<typeof presenter>.
- Domain error → TRPCError mapping moves to per-feature
  integrations/api/procedures.ts via a defineErrorMiddleware factory
  in core-shared/trpc/. core-shared never enumerates feature errors.
- Per-feature public-API surface cleaned: feature root = contracts
  only (types, errors, schemas, IUseCase aliases, router type); new
  ./ui subpath holds query builders / components.

30 numbered rules using RFC-2119 MUST/SHOULD language so every
enforceable decision is citable from CLAUDE.md and per-feature AGENTS.md
during the post-Plan-9 doc-update pass. Includes file-shape templates,
migration order (~9 commits), doc-update mapping per rule, and an
ADR-013 mandate.

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:17:50 +02:00
bffc6a96b3 docs(plan-8): partial Lazar doc-update pass (CLAUDE.md, overview.md, ADR-012, Plan 7 annotations)
First slice of the Plan 8 deferred doc-update checklist:
- CLAUDE.md Key Conventions: factory-function use cases/controllers,
  entities/models/<x>.ts paths, .toDynamicValue DI bindings, direct
  injection in tests
- docs/architecture/overview.md data-flow box updated to factory style
  (controller resolved via container.get<IXController>; use case factory
  takes deps as args)
- docs/decisions/adr-012-lazar-conformance.md created — records the
  conformance decision and four intentional divergences
- docs/superpowers/plans/2026-05-05-plan-7-tdd-foundation.md and the
  matching spec annotated with a "pre-Plan-8 layout" note pointing at
  the refactor log

Remaining Plan 8 doc-update items (root AGENTS.md, per-feature AGENTS.md,
adding-a-feature.md, tdd-workflow.md, testing-strategy.md,
vertical-feature-spec.md §6/§10, core-testing AGENTS.md) intentionally
paused — Plan 9 (input/output unification) will change overlapping
content, so resuming after Plan 9 lands avoids double-churn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:17:35 +02:00
ee070c39b0 chore(refactor-log): complete Plan 8 changelog summary + Task 10 verification
All conformance checks pass per spec §12 acceptance criteria. Summary
section populated with 9 task commits, file count breakdown, and
verification results. Doc-update checklist (deferred) remains untouched
— ready for follow-up doc pass.

Test count: 244 → 325 (+81). All features now structurally conformant
with Lazar Nikolov Clean Architecture pattern (with intentional
divergences documented in spec §4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 00:30:43 +02:00
8a36d803b3 feat(media): full Clean Architecture scaffold
Media is now a complete vertical-feature package mirroring auth/blog
structure: entities (models + errors), application (repositories +
use-cases), infrastructure (real Payload-backed + mock siblings),
interface-adapters (per-use-case controllers), DI (symbols + module +
container + bind-production), integrations/api (mediaRouter), factory,
contract suite, and feature integration tests.

Wired into:
- packages/core-api/src/root.ts (added `media: mediaRouter`)
- apps/web-next/src/server/bind-production.ts (calls bindProductionMedia)
- tsconfig.base.json (added @repo/media/api and ./di/bind-production aliases)

56 new tests in @repo/media (13 test files); core-api router test updated
to assert media. procedures. All 26 turbo tasks green.

Refactor log: §2, §4.1, §4.2, §5.1, §6.1
Spec: §6.5

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:29:05 +02:00
69623b995d refactor(navigation): factory-style use case + controller
- Use case (get-header) → factory function with IGetHeaderUseCase alias
- Controller renamed header.controller.ts → get-header.controller.ts (verb-noun); converted to factory function with IGetHeaderController alias
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controller via container
- Use case + controller tests refactored to direct factory injection (no container rebinding)
- container.test.ts verifies IGetHeaderUseCase + IGetHeaderController symbols

Refactor log: §1, §4.1, §4.2, §5.1
Spec: §6.4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:19:15 +02:00
353a41b244 refactor(marketing-pages): factory-style use cases + per-use-case controllers
- Use cases (get-page-by-slug, get-site-settings) → factory functions with I*UseCase aliases
- Controllers split: pages.controller.ts → 2 single-responsibility files
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controllers via container

Refactor log: §2, §3, §4.1, §4.2, §5.1
Spec: §6.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:14:27 +02:00
700d311052 refactor(blog): factory-style use cases + per-use-case controllers + getArticleBySlug
- Use cases (create-article, get-articles, get-article-by-slug NEW) → factory functions
- Controllers split: articles.controller.ts → 3 single-responsibility files
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controllers via container

Refactor log: §2, §3, §4.1, §4.2, §5.1
Spec: §6.2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:08:15 +02:00
780d5cb83b refactor(auth): factory-style use cases + controllers + real Payload impls
- Use cases (sign-in, sign-up, sign-out) → factory functions with I*UseCase aliases
- Controllers → factory functions with I*Controller aliases
- DI symbols + module updated with .toDynamicValue() bindings for factories
- New: real UsersRepository (Payload-backed, SanitizedConfig, contract-tested)
- New: real AuthenticationService (node:crypto hashing/UUIDs; createSession/
  validateSession/invalidateSession deferred — see refactor log §7)
- bindProductionAuth swaps both mocks for real impls (was a no-op before)
- Tests refactored to construct mocks and inject directly (no container rebinding)
- Feature test constructs full chain via direct factory injection

Refactor log: §2, §4.1, §4.2, §5.1, §5.2, §6.1, §7
Spec: §6.1, §7

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:01:11 +02:00
aa325f91cc refactor(features): rename mock/payload/interface files per Lazar pattern
Convention now: <name>.repository.{ts,mock.ts,interface.ts}.
Renames .mock prefix to .mock suffix; drops .payload prefix from real
impls (canonical name = real impl); dot-separates the .repository
qualifier in interface filenames. Class names follow suit:
PayloadXRepository → XRepository; Mock* unchanged.

Refactor log: §1, §3
Spec: §9.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 23:50:01 +02:00
a4c4ca6b6e refactor(features): split entities into models/ + errors/ subdirs
All 5 features (auth, blog, marketing-pages, navigation; media has no
entities yet) now follow Lazar's pattern:
- entities/<x>.ts → entities/models/<x>.ts
- entities/errors.ts → entities/errors/<domain>.ts + errors/common.ts

Updates all import paths across factories, contracts, tests, use cases,
controllers, repositories, integrations, and src/index.ts exports.

navigation divergence: had no errors.ts; errors/header.ts +
errors/common.ts added as new forward-looking stubs.

Refactor log: docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md
Spec: §5, §9.3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 23:34:32 +02:00
16ca82d7cf docs(refactor-log): scaffold Lazar conformance refactor changelog
Empty section template plus the full doc-update checklist that the
follow-up pass will work through after the refactor is merged. Captures
the substitution map (paths, naming, patterns) so the doc updater can
apply changes mechanically.

Spec: docs/superpowers/specs/2026-05-05-lazar-pattern-conformance-design.md §10

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:12:05 +02:00
57ec36e87b docs(plan): Plan 8 — Lazar pattern conformance (10 tasks, refactor-log first)
Ten TDD'd tasks executing the Lazar Nikolov Clean Architecture pattern
across all 5 features. Task 1 scaffolds the refactor changelog (sole
artifact for the deferred doc-update pass). Tasks 2-3 are foundation
(entities split, file renames). Tasks 4-7 refactor each existing feature
to factory-function pattern. Task 8 scaffolds media as a full Clean
Architecture feature. Task 9 aligns factory/contract imports. Task 10
final verification.

External docs (CLAUDE.md, AGENTS.md, adding-a-feature.md, tdd-workflow.md,
ADR-012) explicitly NOT touched during the refactor — captured as a
checklist in the refactor changelog for a single batched doc-update pass
afterwards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:09:35 +02:00
9e289eb9a8 docs(spec): Lazar Nikolov pattern conformance — design
Brings every feature into structural conformance with the reference
nextjs-clean-architecture repo: factory-function use cases and
controllers, entities/{models,errors}/ split, .mock.ts file suffix,
per-use-case controller files, real PayloadUsersRepository and
PayloadAuthenticationService for auth, full Clean Architecture
scaffold for media. Documents intentional divergences (per-feature DI,
inversify retained, colocated tests). All external doc updates
deferred to a follow-up pass driven by the refactor changelog.

Spec: docs/superpowers/specs/2026-05-05-lazar-pattern-conformance-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:05:22 +02:00
9415eb1c5a test: enforce per-directory coverage thresholds
entities + use-cases + controllers must hit 100% (95% branches).
Project-wide baseline remains 80/75/80/80. Tightening these directories
reflects the architectural intent: these are the pure-logic layers and
should be exhaustively tested.

Added @vitest/coverage-v8@^3 to core-typescript, auth, blog,
marketing-pages, and navigation devDependencies.

Excluded from coverage (legitimately untestable):
- src/di/bind-production.ts — InversifyJS startup bootstrap
- src/application/repositories/** — pure TypeScript interfaces
- src/application/services/** — pure TypeScript interfaces (auth)
- src/integrations/cms/** — declarative Payload CMS config
- src/entities/cookie.ts — pure type aliases (auth)
- src/ui/** — React Query helpers, integration-tested in apps

Tests added (6 new files / 1 extended):
- auth/src/entities/errors.test.ts — UnauthenticatedError, UnauthorizedError,
  AuthenticationError, InputParseError constructors
- blog/src/entities/errors.test.ts — ArticleNotFoundError (default + custom
  message), InputParseError
- marketing-pages/src/entities/errors.test.ts — PageNotFoundError, InputParseError
- marketing-pages/src/entities/site-settings.test.ts — siteSettingsSchema
  (valid, no description, empty name rejection)
- navigation/src/entities/header.test.ts — headerItemSchema and headerSchema
  validation paths
- navigation/src/.../payload-header.repository.test.ts — logo relation-object,
  scalar-id, null, and null-item-field branches for full branch coverage

Spec: §6.9
2026-05-05 19:51:34 +02:00