|
| 1 | +# Bike Tracking Application — Decision Record |
| 2 | + |
| 3 | +This document preserves the amendment history and decision rationale for the [Bike Tracking Constitution](./constitution.md). Refer to this file when understanding why specific architectural choices were made and how the project governance has evolved. |
| 4 | + |
| 5 | +## Key Decision Rationales |
| 6 | + |
| 7 | +### Why Specification-Driven Development (SDD)? |
| 8 | + |
| 9 | +The Bike Tracking project uses SpecKit to enforce Specification-Driven Development. Each feature is captured in a specification document before coding begins. Benefits: |
| 10 | + |
| 11 | +- **Clarity**: Spec approval removes ambiguity before implementation |
| 12 | +- **Testing discipline**: Test plan approved upfront; tests written idempotently |
| 13 | +- **Accountability**: User signs off on specifications and acceptance criteria |
| 14 | +- **Traceability**: Each commit references a spec; easy to understand why code exists |
| 15 | +- **Quality gates**: Code review verifies architecture alignment with constitution |
| 16 | + |
| 17 | +### Why Event Sourcing + CQRS? |
| 18 | + |
| 19 | +Bike Tracking tracks rides, expenses, and savings over time. Event Sourcing enables: |
| 20 | + |
| 21 | +- **Complete audit trail**: Every change (record ride, edit distance, recalculate savings) stored as immutable event |
| 22 | +- **Temporal queries**: "Show me rides in March 2024" via event filters |
| 23 | +- **Replay & debugging**: Event replay reconstructs state at any point in time |
| 24 | +- **CQRS separation**: Write path (append events) faster than read path (query projections) |
| 25 | +- **Future analytics**: Events preserve data for future analyses (e.g., weather correlations, motivation patterns) |
| 26 | + |
| 27 | +Trade-offs: Added complexity (separate event/projection tables, eventual consistency, schema versioning). Justified for a financial/historical application. |
| 28 | + |
| 29 | +### Why F# for Domain Layer? |
| 30 | + |
| 31 | +F# enforces functional programming discipline at compile time, reducing bug categories: |
| 32 | + |
| 33 | +- **Discriminated unions**: Model "ride recorded" vs "ride deleted" as separate types; compiler prevents invalid state transitions |
| 34 | +- **Pattern matching**: Exhaustive event handling; compiler warns if new event type not handled |
| 35 | +- **Immutability by default**: All data structures immutable unless explicitly marked mutable (rare) |
| 36 | +- **Reduced null references**: F# option types (`Some`/`None`) replace nullable C# (no "null reference exception" fears) |
| 37 | +- **ROP (Railway Oriented Programming)**: Error handling via `Result<'T, 'E>` instead of exceptions; control flow explicit |
| 38 | + |
| 39 | +Trade-offs: Team requires F# training; C#/F# interop requires value converters. Effort pays off in reduced production bugs (discriminated unions catch invalid states at compile time). |
| 40 | + |
| 41 | +### Why Aspire Orchestration? |
| 42 | + |
| 43 | +Microsoft Aspire enables: |
| 44 | + |
| 45 | +- **Local-to-cloud parity**: Develop locally with Docker containers; same Bicep IaC deploys to Azure |
| 46 | +- **Service discovery**: Services find each other automatically in Aspire dashboard (no hardcoded URLs) |
| 47 | +- **Secrets management**: Azure Key Vault connection tested locally; same vault used in Azure |
| 48 | +- **Team onboarding**: `dotnet run` spins up full stack (API, frontend, DB, functions) with one command |
| 49 | +- **Health checks**: Dashboard shows service health in real-time |
| 50 | + |
| 51 | +Trade-offs: Docker/Podman required; slight learning curve. Simplifies DevOps and debugging pipelines. |
| 52 | + |
| 53 | +### Why Three-Layer Validation? |
| 54 | + |
| 55 | +Data integrity is non-negotiable for financial data (savings calculations): |
| 56 | + |
| 57 | +1. **Client-side (Blazor)**: Immediate feedback; better UX responsiveness |
| 58 | +2. **Server-side (API)**: Prevents bypass attacks; enforces business rules |
| 59 | +3. **Database layer**: Last-line defense; constraints prevent corrupted data from entering event store |
| 60 | + |
| 61 | +If any layer is missing, data corruption risk rises. All three required. |
| 62 | + |
| 63 | +### Why Fluent UI Blazor (latest version)? |
| 64 | + |
| 65 | +Fluent UI provides: |
| 66 | +- **Design tokens**: Centralized color, spacing, typography; enforces brand consistency |
| 67 | +- **Accessibility**: Built-in WCAG 2.1 AA compliance; keyboard navigation, screen reader support |
| 68 | +- **Responsive components**: Mobile-first design; components adapt to breakpoints |
| 69 | +- **Microsoft ecosystem**: Native C# integration; no JavaScript bridging complexity |
| 70 | + |
| 71 | +Trade-offs: Tied to Blazor version; updates require testing. Lock version to v4.13.x and higher as new versions are released for stability but also keeping up to date. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## Future Potential Amendments |
| 76 | + |
| 77 | +These topics are under consideration for future constitution amendments (not yet ratified): |
| 78 | + |
| 79 | +### Option 1: Projection Lag SLO |
| 80 | +**Trigger**: If business needs tighter saga/process manager orchestration |
| 81 | +**Change**: Reduce "eventual consistency within 5 seconds" to "within 1 second" for critical projections |
| 82 | +**Impact**: May require moving from Change Event Streaming to in-process event handlers; architectural complexity or Azure Cosomos DB |
| 83 | +**Decision pending performance measurement in production** |
| 84 | + |
| 85 | +### Option 2: API Versioning Strategy |
| 86 | +**Trigger**: When breaking Minimal API changes are required (e.g., new command format) |
| 87 | +**Change**: Add API versioning principle via URL paths (/v1/, /v2/) or headers |
| 88 | +**Impact**: Multiple code paths to maintain; dual testing of old+new APIs |
| 89 | +**Decision pending first breaking change scenario** |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +**Last Review**: 2026-03-03 |
| 94 | +**Next Review**: 2026-04-03 |
0 commit comments