13 Commits

Author SHA1 Message Date
b96cce5d74 feat: hybrid versioning + automated CHANGELOG via release-please
Closes the user's ask: versioning + a changelog generated on merging
to main, building on the just-mandated Conventional Commits substrate
(CLAUDE.md Key Conventions).

Architecture: ADR-021. Cookbook: docs/guides/releasing.md.

Initial state — six tracked packages at v0.1.0:
  - .                          -> template-vertical  (tag: template-v...)
  - packages/auth              -> @repo/auth         (tag: auth-v...)
  - packages/blog              -> @repo/blog         (tag: blog-v...)
  - packages/media             -> @repo/media        (tag: media-v...)
  - packages/marketing-pages   -> @repo/marketing-pages (tag: marketing-pages-v...)
  - packages/navigation        -> @repo/navigation   (tag: navigation-v...)

Core packages, tooling, and apps are NOT independently versioned
(ADR-021 rationale: core bumps cascade; apps aren't consumables;
surfacing them would create noise without information).

Configuration:
  - release-please-config.json   - 6 tracked packages, hybrid scope,
                                   pre-1.0 conservative bump policy
                                   (feat: -> patch, feat!: -> minor),
                                   conventional-commit type mapping
  - .release-please-manifest.json - baseline 0.1.0 for all 6 packages
  - .github/workflows/release-please.yml - googleapis/release-please-
                                   action@v4 on push to main,
                                   concurrency-gated, write
                                   permissions for the rolling PR

Workflow: on every push to main, release-please scans commits since
the last release tag PER PACKAGE (using commit-path, not the
conventional-commit scope), updates a single rolling release PR with
version bumps + per-package CHANGELOG entries. Merging that PR cuts
per-package tags + GitHub releases.

CHANGELOG files seeded at v0.1.0 baseline:
  - CHANGELOG.md (root)
  - packages/<feature>/CHANGELOG.md (5 features)
Subsequent versions are appended by release-please from commit
history. Do not edit manually.

Visibility surfaces updated (every agent entry point):
  - CLAUDE.md Read First + new "Versioning is hybrid" Key Conventions
    bullet (with bump policy summary)
  - AGENTS.md preamble - new "Releases:" callout alongside Commits
  - docs/glossary.md - new Releasing section with 8 terms (Conventional
    Commits, release-please, Hybrid versioning, Tag prefix, Rolling
    release PR, Bump targeting, Pre-1.0 bump policy, Release-As trailer,
    CHANGELOG.md)
  - docs/README.md - guides tree updated with releasing.md
  - .claude/hooks/session-start.sh - one-line release reminder
  - .claude/hooks/prompt-context.sh - new keyword group for
    release/version/bump/semver/tag prompts

Package.json version bumps:
  - root: name "template" -> "template-vertical", version "0.1.0"
  - packages/auth, blog, media, marketing-pages, navigation: "0.0.0" -> "0.1.0"

Root rename rationale: release-please tags use the package-name + the
component prefix; "template-vertical" matches the repo identity (and
the user's question preview).

First release-please PR after this lands will sweep all subsequent
post-baseline commits into 0.1.1 / 0.2.0 bumps as appropriate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:17:16 +02:00
a9f27f0d7e refactor: remove core-events from main (scaffoldable via gen core-package events)
- Delete packages/core-events/ (15 files)
- Strip @repo/core-events from all 5 feature package.json + apps/web-next/package.json
- Strip @repo/core-events from apps/web-next/next.config.mjs transpilePackages
- Strip E1 + J no-restricted-syntax blocks from core-eslint/base.js (anchor remains)
- Update bind-production.ts: drop bus construction + IEventBus import; rename
  resolveEventsAndJobsProduction → resolveJobsProduction (queue only),
  resolveEventsAndJobsDevSeed → resolveJobsDevSeed (queue only);
  ctx no longer has bus field; BindProductionContext generic arg narrowed
- Update bind-production.test.ts: assert ctx.bus is undefined, drop
  PayloadJobsEventBus/InMemoryEventBus instanceof checks
- Update sign-up-welcome-email.test.ts: assert mailer stays empty without bus
- Inline userSignedUpEvent in auth (drop defineEvent import from core-events)
- Drop InMemoryEventBus fallback from auth/di/module.ts

Feature binders' bus?.subscribe/publish calls remain as no-ops. Scaffold
@repo/core-events back via: pnpm turbo gen core-package events

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 14:00:35 +02:00
57b2ff5191 refactor: remove core-realtime from main (scaffoldable via gen core-package realtime) 2026-05-09 13:45:52 +02:00
7e1d2d5c4b feat(auth): bind binders accept (realtime, realtimeRegistry) params
Extend bindProductionAuth and bindDevSeedAuth to 7-arg signatures.
Fix RecordingRealtimeBroadcaster scope type to structurally match ChannelScope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 22:41:04 +02:00
04899de98c test(web-next): e2e cross-feature sign-up→welcome-email flow
End-to-end proof-of-life. bindAllDevSeed wires InMemoryEventBus +
InMemoryJobQueue across all features. signUpController publishes
auth.user.signed-up; marketing-pages' handler enqueues
marketing-pages.send-welcome-email; the in-memory queue dispatches
the wrapped job which records on RecordingMailerService.

Adds ./di/container, ./di/symbols, ./services/mailer, and
./services/recording-mailer to auth + marketing-pages exports so
the e2e test can resolve from the per-feature containers without
deep-importing.
2026-05-08 16:37:37 +02:00
b0bd4c0bb3 feat(auth): bind binders accept (bus, queue) params 2026-05-08 15:16:16 +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
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
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
bf6affd404 feat(core-typescript): split vitest base into node + jsdom flavors
Adds vitest.base.node and vitest.base.jsdom with safety defaults
(clearMocks, restoreMocks, mockReset, unstubGlobals, sequence.shuffle)
and coverage thresholds (80/75/80/80). Migrates all feature configs
to the new base. Existing baseVitestConfig kept as backwards-compat
re-export of nodeVitestConfig.

Spec: §6.2
2026-05-05 14:04:19 +02:00
0972645ebb refactor: rename eslint-config + typescript-config to core-eslint + core-typescript
Aligns tooling packages with the core-* naming convention used by all
other foundation packages (core-shared, core-cms, core-api, core-trpc,
core-ui). Updates ~50 files: package.json names, devDependencies,
tsconfig extends, eslint.config imports, vitest.config imports, AGENTS.md
references, and the boundaries plugin patterns to match the new paths.

The tooling-specific patterns in boundaries/elements are now ordered BEFORE
the broader core-* pattern to ensure correct first-match-wins behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 10:37:07 +02:00
ef42abb3e1 feat(auth): add bindProductionAuth(config) helper (no-op pending payload-users repo) 2026-05-05 08:50:08 +02:00
54dc9d33d5 feat(auth): scaffold empty package with feature tag + path aliases 2026-05-05 00:37:13 +02:00