Architecture Decision Records
Architecture Decision Records (ADRs) document the significant architectural choices made across our projects. Each record captures the context, options considered, the decision, and its consequences.
Why We Write These
When you join a project or review a pull request, you often ask "why is it done this way?" These records answer that question. They capture not just what was decided, but why — including what we considered and rejected.
How to Read an ADR
Each ADR follows the same structure:
- Status —
Proposed(under discussion),Accepted(implemented or being implemented),Superseded(replaced by a newer decision) - Context — The problem or situation that prompted the decision
- Options Considered — Alternatives we evaluated, with reasons for rejection
- Decision — What we chose and how it works
- Consequences — The trade-offs we accepted, both positive and negative
Decision Index
Kendo
| # | Decision | Status | Summary |
|---|---|---|---|
| 1 | Audit Logging System | Accepted | Per-entity audit tables with hash chains for ISO 27001 compliance |
| 6 | Two-Tier Authorization | Accepted | Route-level model permissions + action-level interaction permissions |
| 3 | AI Interaction Logging | Accepted | Three-channel logging for outbound AI calls, MCP tools, and AI runs |
| 8 | Multi-Tenancy | Accepted | DIY database-per-tenant for 3 fixed companies |
| 13 | Adapter-Store Pattern | Accepted | Custom reactive store factory over Pinia for 15+ domain stores |
| 25 | GitHub Integration Split | Accepted | Split GithubService into OAuth handshake + bearer-token-parametrized API client; per-call token argument |
Brick Inventory
| # | Decision | Status | Summary |
|---|---|---|---|
| 4 | Import Atomicity | Accepted | Save-what-you-can with honest reporting for API imports |
Emmie
| # | Decision | Status | Summary |
|---|---|---|---|
| 22 | Schedule End Date Inclusive | Accepted | Schedule.end_date is the last active day; canonical predicates use inclusive <= / >= |
| 23 | Schedule Mutation Chokepoint | Accepted | Single Action owns Schedule date mutation; wrapping normalizer, schema unchanged |
Cross-Project
| # | Decision | Status | Summary |
|---|---|---|---|
| 2 | Cascade Deletion & Soft Deletes | Accepted | Model declares, Action executes, tests verify. No ON DELETE CASCADE. |
| 9 | Unified ResourceData Pattern | Accepted | Custom ResourceData base class replaces Laravel's JsonResource |
| 11 | Action Class Architecture | Accepted | final readonly Actions with single execute() method, explicit DI |
| 12 | FormRequest → DTO Flow | Accepted | Type-safe pipeline from HTTP validation to business logic |
| 14 | Domain-Driven Frontend Structure | Accepted | Vertical slices by business domain, not technical layers |
| 16 | Config Attribute Injection | Accepted | #[Config] attribute for all config access, config() helper prohibited |
| 17 | Page Integration Tests | Accepted | Mount domain pages with real components, mocked services, separate coverage accounting |
| 19 | Explicit Model Hydration | Accepted | Ban $fillable/$guarded, require explicit property assignment in Actions |
| 15 | ADR Governance | Accepted | Single source of truth at adrs.script.nl |
| 18 | ISMS Information System | Accepted | Laravel + Vue ISMS with policies as markdown, operational data in PostgreSQL |
| 20 | Input/Result DTO Split | Accepted | Split DTOs by usage direction at the Action boundary — arch tests enforce |
| 21 | PHPStan Rules Package | Accepted | Canonical war-room PHPStan rules distributed as script-development/phpstan-warroom-rules Composer package |
| 24 | Automated External Provisioning | Accepted | Async + provider-abstracted + retain-on-failure + audit-mandatory + Tier-1 retry + flag-gated for tenant-resource provisioning |