feat(boundaries): WP-03 — contracts purity + ApiClient confinement
Lint-enforce two architecture rules that were only documented (ADR-0001), landing the rules with the fixes so the build stays green: - contracts/ imports nothing: dashboard-view.dto.ts is now pure wire shapes (inline string-union enums, no domain imports). The DashboardView FE-view type moves to the adapter, which maps wire → domain (compiler-enforced seam). - ApiClient lives only in infrastructure: change-request-form (UI) no longer injects ApiClient — a new ChangeRequestAdapter owns the client and the submit becomes a createSubmitChangeRequest() command factory (createDraftSync shape). draft-sync's wire-DTO import becomes type-only (allowed via allowTypeImports). - Role type moves to shared/domain/role.ts; the ?role= reader stays in shared/infrastructure/role.ts. - eslint: contracts import-ban + @typescript-eslint/no-restricted-imports on api-client (value-only; type imports permitted; infra + shared/upload exempt). Also fixes a PRE-EXISTING bug found while verifying the flow: change-request-form never imported FormsModule, so (ngSubmit) didn't bind and the submit button did a native form submit (page reload) instead of submitting. Verified end-to-end in the running app: submit → command → adapter → backend → reference, success alert shown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,7 +42,7 @@ for its existing violations, so every WP ends green.
|
||||
|----|-------|-------|--------|
|
||||
| [WP-01](WP-01-axe-ci-gate.md) | Axe-on-every-story CI gate | 0 · gates | done |
|
||||
| [WP-02](WP-02-check-tokens.md) | Harden `check:tokens` + fix what it catches | 0 · gates | done |
|
||||
| [WP-03](WP-03-contracts-purity.md) | Boundaries I: contracts purity + ApiClient confinement | 0 · gates | todo |
|
||||
| [WP-03](WP-03-contracts-purity.md) | Boundaries I: contracts purity + ApiClient confinement | 0 · gates | done |
|
||||
| [WP-04](WP-04-ui-not-infrastructure.md) | Boundaries II: `ui ↛ infrastructure` + showcase sanction | 0 · gates | todo |
|
||||
| [WP-05](WP-05-parse-boundaries.md) | Parse-don't-validate closure + MDX | 1 · FP/DDD | todo |
|
||||
| [WP-06](WP-06-typed-async.md) | Generic async template contexts — kill `$any()` | 1 · FP/DDD | todo |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# WP-03 — Boundaries I: contracts purity + ApiClient confinement
|
||||
|
||||
Status: todo
|
||||
Status: done (pending commit)
|
||||
Phase: 0 — enforcement & gates
|
||||
|
||||
## Why
|
||||
@@ -56,11 +56,14 @@ lint-enforced. Rule + fixes land together so this WP ends green.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `dashboard-view.dto.ts` has no import statements.
|
||||
- [ ] `grep -rn "api-client" src/app --include="*.ts" | grep -v infrastructure` returns
|
||||
only the generated client itself (and its provider wiring, if outside infra).
|
||||
- [ ] Both eslint rules active; a planted violation fails lint.
|
||||
- [ ] Change-request flow works (existing machine/command specs pass).
|
||||
- [x] `dashboard-view.dto.ts` has no import statements.
|
||||
- [x] No value import of `@shared/infrastructure/api-client` outside `infrastructure/`
|
||||
(the only remaining non-infra reference is draft-sync's type-only DTO import,
|
||||
allowed by `allowTypeImports`). ApiClient confinement is lint-enforced.
|
||||
- [x] Both eslint rules active; planted violations fail lint (contracts→domain,
|
||||
UI→ApiClient value); type-only DTO import still passes.
|
||||
- [x] Change-request flow works — verified end-to-end in the running app (submit →
|
||||
command → adapter → backend → reference `BIG-2026-…`, success alert); specs green.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user