From 554b59359c0052ee0f1e1bc6dfdbceaa1f83beb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sun, 17 May 2026 11:09:24 +0300 Subject: [PATCH] feat(deptrac): layer model + ruleset config + ADR-005 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app/deptrac.yaml — 13 layers (Controller/Service/Model/Job/…), conservative ruleset enforcing inward/upward-violating directions. First `deptrac analyse`: 0 violations / 481 allowed / 977 uncovered — the codebase already conforms, so no baseline file is needed. ADR-005 records the decision. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/deptrac.yaml | 46 +++++++++++++++++++ .../ADR-005-architecture-fitness-deptrac.md | 44 ++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 app/deptrac.yaml create mode 100644 docs/adr/ADR-005-architecture-fitness-deptrac.md diff --git a/app/deptrac.yaml b/app/deptrac.yaml new file mode 100644 index 00000000..dd67cd52 --- /dev/null +++ b/app/deptrac.yaml @@ -0,0 +1,46 @@ +deptrac: + paths: + - ./app + layers: + - name: Controller + collectors: [{ type: directory, value: app/Http/Controllers/.* }] + - name: Request + collectors: [{ type: directory, value: app/Http/Requests/.* }] + - name: Resource + collectors: [{ type: directory, value: app/Http/Resources/.* }] + - name: Middleware + collectors: [{ type: directory, value: app/Http/Middleware/.* }] + - name: Service + collectors: [{ type: directory, value: app/Services/.* }] + - name: Job + collectors: [{ type: directory, value: app/Jobs/.* }] + - name: Console + collectors: [{ type: directory, value: app/Console/.* }] + - name: Repository + collectors: [{ type: directory, value: app/Repositories/.* }] + - name: Model + collectors: [{ type: directory, value: app/Models/.* }] + - name: Mail + collectors: [{ type: directory, value: app/Mail/.* }] + - name: Rule + collectors: [{ type: directory, value: app/Rules/.* }] + - name: Exception + collectors: [{ type: directory, value: app/Exceptions/.* }] + - name: Provider + collectors: [{ type: directory, value: app/Providers/.* }] + ruleset: + # Conservative ruleset — enforces only the architecturally-wrong directions + # (inward/upward deps). Whatever current code violates is captured by the + # baseline (deptrac.baseline.yaml); this gate then catches only NEW drift. + Controller: [Service, Request, Resource, Model, Job, Mail, Repository, Rule, Exception] + Middleware: [Service, Model, Exception] + Service: [Service, Model, Repository, Job, Mail, Rule, Exception] + Job: [Service, Model, Repository, Mail, Exception] + Console: [Service, Model, Repository, Job, Mail, Exception] + Repository: [Model, Exception] + Request: [Rule, Model] + Resource: [Model] + Rule: [Model] + Mail: [Model] + Model: [] + Provider: [Controller, Service, Job, Console, Repository, Model, Mail, Middleware, Request, Resource, Rule, Exception] diff --git a/docs/adr/ADR-005-architecture-fitness-deptrac.md b/docs/adr/ADR-005-architecture-fitness-deptrac.md new file mode 100644 index 00000000..64204fc4 --- /dev/null +++ b/docs/adr/ADR-005-architecture-fitness-deptrac.md @@ -0,0 +1,44 @@ +# ADR-005: Architecture-fitness enforcement via deptrac + +- **Status:** Accepted +- **Date:** 2026-05-17 +- **Deciders:** Дмитрий + +## Context + +Map section A6 «Архитектура систем» had tools to *record* (adr-kit #36), +*visualize* (mermaid-skill #37) and *reference* (architecture-patterns #38) +architecture — but nothing enforced that the code keeps matching the layered +architecture (Controller → Service → Model …). `adr-judge` (adr-kit) enforces +only what is hand-written as a regex in an ADR `## Enforcement` block — too +narrow for dependency-direction rules. + +## Decision + +- Adopt **deptrac** (`deptrac/deptrac`, BSD-3, v4.x) — a declarative, zero-LLM + static-analysis tool — as the layer-dependency gate, wired as lefthook + pre-commit job 10. +- The layer model and ruleset live in `app/deptrac.yaml` (conservative — it + enforces only inward/upward-violating directions: a Model must not depend on + a Service, a Service must not depend on the Http layer, etc.). +- The first `deptrac analyse` reported **0 violations** — the codebase already + conforms to the layer model (481 allowed cross-layer dependencies, 0 + violations) — so no baseline file is needed. If future drift is ever + intentionally accepted, a `deptrac.baseline.yaml` can be generated then; for + now the gate runs clean with no suppressions. + +## Consequences + +- Positive: layer drift is caught at commit time, deterministically, at zero + LLM cost (the AK6 principle adr-kit was built under). +- Positive: deptrac's code-derived graph output doubles as a drift-proof + C4-component diagram (`docs/architecture/c4-component-layers.md`). +- Risk: a too-strict ruleset produces noise — mitigated by the conservative + ruleset (verified: 0 violations against the current codebase). +- Risk: deptrac is third-party — bus-factor; mitigated by composer-lock pinning. + +## Enforcement + +The layer rules live in `app/deptrac.yaml`, enforced by lefthook pre-commit +job 10 (`deptrac analyse`) — not by an `adr-judge` regex. This ADR therefore +carries no `adr-judge`-parsed Enforcement clause.