docs(architecture): correct package lists and feature-to-feature boundary
Align the architecture docs with the current repo: - Boundary matrix: feature may depend on core, feature, tooling — a feature may import another feature's public exports. overview.md, dependency-flow.md, and vertical-feature-spec.md all said the stale `feature -> core, tooling`. - Optional-core lists completed with core-analytics, core-consent, core-dsr; tooling list completed with core-testing. - Package count corrected to the accurate 19-package breakdown. - BindContext table gained analytics, consentFactory, rateLimit. Deeper drift (the HTML explainers, vertical-feature-spec §5/§9.5/§11) is tracked in the local .tmp/ working note, not yet addressed.
This commit is contained in:
@@ -23,11 +23,17 @@
|
||||
|
||||
Boundary rules (enforced by ESLint + Turborepo boundaries):
|
||||
app → app, core, core-composition, feature, tooling
|
||||
feature → core, tooling
|
||||
feature → core, feature, tooling
|
||||
core → core, core-composition, tooling
|
||||
core-composition → core, core-composition, feature, tooling
|
||||
tooling → tooling
|
||||
|
||||
feature → feature: a feature may import another feature's PUBLIC exports
|
||||
(its @repo/<feature> contract barrel — types, errors, schemas, event
|
||||
contracts). It must NOT reach another feature's internals, and
|
||||
cross-feature behaviour still flows through IEventBus — never a direct
|
||||
use-case call.
|
||||
|
||||
Composition exceptions:
|
||||
core-api → @repo/<feature>/api (subpath only)
|
||||
core-cms → @repo/<feature>/cms (subpath only)
|
||||
@@ -51,6 +57,7 @@ import { articleBySlugQuery } from "@repo/blog/ui"; // queries
|
||||
|
||||
// in packages/blog
|
||||
import { slugifyIfMissing } from "@repo/core-shared/payload";
|
||||
import { userSignedUpEvent } from "@repo/auth"; // ✓ another feature's public contract
|
||||
|
||||
// in packages/core-api
|
||||
import { blogRouter } from "@repo/blog/api"; // composition exception
|
||||
@@ -63,8 +70,8 @@ import { articles } from "@repo/blog/cms"; // composition exception
|
||||
Disallowed:
|
||||
|
||||
```ts
|
||||
// in packages/blog (cross-feature)
|
||||
import { Article } from "@repo/marketing-pages"; // ❌ feature → feature
|
||||
// in packages/blog (reaching another feature's internals)
|
||||
import { signInUseCase } from "@repo/auth/src/application/use-cases/sign-in.use-case"; // ❌ not a public export
|
||||
|
||||
// in packages/blog (deep import past public exports)
|
||||
import { articles } from "@repo/blog/src/integrations/cms/collections/articles"; // ❌ no-private
|
||||
@@ -158,6 +165,9 @@ apps/web-next/src/server/bind-production.ts (bindAll)
|
||||
| `realtime` | `RealtimeBroadcasterProtocol?` | optional | `IRealtimeBroadcaster` at the aggregator |
|
||||
| `realtimeRegistry` | `RealtimeRegistryProtocol?` | optional | `IRealtimeHandlerRegistry` at the aggregator |
|
||||
| `auditLog` | `AuditLogProtocol?` | optional | `IAuditLog` at the aggregator; pre-wrapped in `TraceIdEnrichingAuditLog` so callers don't supply `correlationId` (ADR-018) |
|
||||
| `analytics` | `AnalyticsProtocol?` | optional | `IAnalytics` product-analytics channel at the aggregator (ADR-024) |
|
||||
| `consentFactory` | `ConsentFactoryProtocol?` | optional | builds a per-subject consent checker; present when `core-consent` is wired (ADR-025) |
|
||||
| `rateLimit` | `IRateLimit?` | optional | per-use-case rate-limit budgets; present when rate limiting is wired (ADR-025) |
|
||||
|
||||
Feature binders destructure `ctx` and use optional fields with `?.` or cast to the full interface when the feature unconditionally requires them (e.g. `bus as IEventBus` when a use case always needs the event bus).
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ packages/
|
||||
core-realtime/ Socket.IO server + broadcaster + handler registry (ADR-016)
|
||||
core-events/ In-memory + Payload-backed event bus + job queue (ADR-015)
|
||||
core-audit/ DPA-compliant audit logging — sinks, hook factories, eraseSubject (ADR-018)
|
||||
core-analytics/ Product analytics capture channel (ADR-024)
|
||||
core-consent/ Consent records + cookie-consent banner (ADR-025)
|
||||
core-dsr/ Data-subject-rights — export, delete, rectify, restrict (ADR-025)
|
||||
|
||||
# Business capabilities
|
||||
auth/ Users + sign-in/sign-up/sign-out + session/cookie domain
|
||||
@@ -28,8 +31,9 @@ packages/
|
||||
navigation/ Header global + menu items
|
||||
|
||||
# Tooling
|
||||
core-eslint/ Shared ESLint flat config + boundary rules
|
||||
core-eslint/ Shared ESLint flat config + conformance rules + boundary rules
|
||||
core-typescript/ Shared tsconfig + vitest base
|
||||
core-testing/ Factories, contract suites, recording test doubles
|
||||
```
|
||||
|
||||
See `docs/architecture/template-tiers.md` for the must-have/optional split and the scaffold commands.
|
||||
@@ -91,7 +95,7 @@ each feature passes its own constructors in.
|
||||
## Three enforcement layers
|
||||
|
||||
1. **`package.json` deps** — only declare allowed deps
|
||||
2. **`exports` map** — each package exposes a small public surface (`.`, `./cms`, `./api`, `./di/bind-production`)
|
||||
2. **`exports` map** — each feature exposes a small public surface (`.`, `./ui`, `./cms`, `./api`, `./di/bind-production`, `./di/bind-dev-seed`)
|
||||
3. **Two parallel automated checks**:
|
||||
- **ESLint `eslint-plugin-boundaries`** (lint-time) — enforces boundary rules at linting
|
||||
- **Turborepo `boundaries`** (build-graph time) — validates entire workspace dependency graph, including transitive reaches
|
||||
@@ -104,9 +108,9 @@ The workspace is organized into five mutually exclusive tags:
|
||||
|
||||
- **app** (4 packages): `apps/cms`, `apps/web-next`, `apps/web-tanstack`, `apps/storybook`
|
||||
- **core-composition** (2 must-have): `packages/core-api`, `packages/core-cms`. Plus `packages/core-trpc` when scaffolded via `pnpm turbo gen core-package trpc` (optional).
|
||||
- **core** (1 must-have): `packages/core-shared`. Plus `packages/core-ui`, `packages/core-realtime`, `packages/core-events`, `packages/core-audit` when scaffolded via `pnpm turbo gen core-package <name>` (optional).
|
||||
- **core** (1 must-have): `packages/core-shared`. Plus `core-ui`, `core-realtime`, `core-events`, `core-audit`, `core-analytics`, `core-consent`, `core-dsr` when scaffolded via `pnpm turbo gen core-package <name>` (optional).
|
||||
- **feature** (5 packages): `packages/auth`, `packages/blog`, `packages/media`, `packages/marketing-pages`, `packages/navigation`
|
||||
- **tooling** (2 packages): `packages/core-eslint`, `packages/core-typescript`
|
||||
- **tooling** (3 packages): `packages/core-eslint`, `packages/core-typescript`, `packages/core-testing`
|
||||
|
||||
See `docs/architecture/template-tiers.md` for the must-have/optional split and the scaffold commands.
|
||||
|
||||
@@ -117,9 +121,11 @@ See `docs/architecture/template-tiers.md` for the must-have/optional split and t
|
||||
| app | app, core, core-composition, feature, tooling |
|
||||
| core-composition | core, core-composition, feature, tooling |
|
||||
| core | core, core-composition, tooling |
|
||||
| feature | core, tooling |
|
||||
| feature | core, feature, tooling |
|
||||
| tooling | tooling |
|
||||
|
||||
A feature may import another feature's **public exports** — its `@repo/<feature>` contract barrel (types, errors, schemas, event contracts). It must not reach another feature's internals (the `exports` map seals those), and cross-feature _behaviour_ still flows through `IEventBus` — a feature never imports and invokes another feature's use cases directly.
|
||||
|
||||
**Composition exceptions:**
|
||||
|
||||
- `core-api` may import from `@repo/<feature>/api` subpath exports only
|
||||
|
||||
@@ -23,6 +23,8 @@ Plus all 5 feature packages: auth, blog, marketing-pages, navigation, media.
|
||||
| core-ui | `pnpm turbo gen core-package ui` | (none) | (none) |
|
||||
| core-audit | `pnpm turbo gen core-package audit` | ADR-018 | docs/guides/audit-and-compliance.md |
|
||||
| core-analytics | `pnpm turbo gen core-package analytics` | ADR-024 | docs/guides/analytics.md |
|
||||
| core-consent | `pnpm turbo gen core-package consent` | ADR-025 | docs/guides/consent.md |
|
||||
| core-dsr | `pnpm turbo gen core-package dsr` | ADR-025 | docs/guides/dsr.md |
|
||||
|
||||
## Why optional
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ repo/
|
||||
pnpm-workspace.yaml tsconfig.base.json turbo.json
|
||||
```
|
||||
|
||||
**Package count:** 3 apps + 5 core + 5 feature + 2 tooling = **15 packages** (was 12).
|
||||
**Package count:** the `packages/` workspace holds **19 packages** — 3 must-have cores (`core-shared`, `core-cms`, `core-api`), 8 optional cores scaffolded on demand (`core-ui`, `core-events`, `core-realtime`, `core-trpc`, `core-audit`, `core-analytics`, `core-consent`, `core-dsr`), 3 tooling packages (`core-eslint`, `core-typescript`, `core-testing`), and 5 feature packages — plus 4 apps. A minimal project that scaffolds none of the optional cores ships 11 packages.
|
||||
|
||||
---
|
||||
|
||||
@@ -444,9 +444,11 @@ Note: `core-trpc` is `core-composition` (not plain `core`) because it transitive
|
||||
| app | app, core, core-composition, feature, tooling |
|
||||
| core-composition | core, core-composition, feature, tooling |
|
||||
| core | core, core-composition, tooling |
|
||||
| feature | core, tooling |
|
||||
| feature | core, feature, tooling |
|
||||
| tooling | tooling |
|
||||
|
||||
A feature may import another feature's **public exports** — its `@repo/<feature>` contract barrel (types, errors, schemas, event contracts). It must not reach another feature's internals, and cross-feature _behaviour_ still flows through `IEventBus`, never a direct use-case call.
|
||||
|
||||
### 9.3 Composition exceptions
|
||||
|
||||
- `core-cms` may import `@repo/<feature>/cms` subpath exports only.
|
||||
|
||||
Reference in New Issue
Block a user