Architectural Decision Record (ADR) 003
Document Rule Processing System - Unified Tooling & Monorepo Strategy
Unified Tooling & Monorepo Strategy
Status: Accepted ✅
Context
Building upon the foundation of event-driven logic (ADR001) and the commitment to a unified TypeScript ecosystem (ADR002), the project requires an overarching tooling strategy. This strategy must enforce technological consistency, guarantee dependency reproducibility across environments.
Problem Statement
Without a strict, centralized tooling mandate:
- Dependency Drift: Different parts of the system may operate with incompatible dependency versions, leading to runtime errors that are difficult to trace.
- Inconsistency Risk: The API consumer and the UI producer could violate contract expectations if they rely on different language features or libraries.
- Maintenance Overhead: Managing multiple isolated repositories would increase build times and require redundant setup procedures.
Decision
Tooling & Monorepo Adoption The project will adopt a Monorepo structure managed by a central package.json that defines the unified TypeScript ecosystem. Dependency control will be handled through workspaces and version constraints.
Key Principles of This Decision:
- Unified Contract Enforcement: The
/packages/rules-commondirectory (the shared type layer) is held under strict monorepo governance to ensure high cohesion between API (/api) and UI (/ui). - Version Pinning: The root
package.jsonwill contain the"engines"field, specifying mandatory, minimum versions for Node.js and other tools (e.g., npm). This serves as a strict contract to all developers and CI systems. - Build Integrity: A single, cohesive build process will be managed via the root
package.jsonscripts (npm run build:all), ensuring that component builds are always synchronized with their dependency contracts.
Options Considered
Option 1: Multiple Repositories (De-coupling)
Maintain separate Git repositories for API, UI, and Shared Contracts.
Complete technical isolation; easier to manage large teams working on siloed pieces.
Requires complex versioning (e.g., publishing the rules-common package to a private registry constantly); makes cross-component refactoring extremely difficult and slow.
Option 2: Simple Local Directory Structure (No Central Tooling)
Simply place all source code into separate folders without using workspaces or centralized dependency resolution.
Lowest initial setup barrier.
High risk of "dependency hell"; makes it impossible to enforce the rules-common contract; fails the requirement for a high-integrity, professional system. (Rejected)
Option 3: Monorepo with Centralized Tooling (Selected)
Utilize a single repository root managed by package managers (e.g., Yarn Workspaces or pnpm), enforcing dependency constraints and defining build processes centrally.
Guaranteed type-safety between components; a single source of truth for all contracts; simplified cross-cutting changes (refactoring a shared interface only requires one pull request).
Increased initial complexity in configuration setup (tsconfig.json inheritance, workspace linking).
Consequences and Implementation Requirements
Positive Consequences (The Value Proposition)
- Guaranteed Consistency: A contributor cannot accidentally introduce an incompatibility between the API and UI because the shared contract is managed as a linked dependency within the monorepo, not just as abstract documentation.
- Reproducibility at Scale: The
"engines"field ensures that the project environment itself is version-controlled, significantly reducing onboarding friction for new team members.
Negative Constraints (The Required Effort)
- Initial Complexity: The setup phase requires careful configuration of tsconfig files across all sub-packages to manage inheritance and module resolution correctly.
- Build Overhead: Build/testing pipelines must be designed to handle the monorepo structure (i.e., only rebuild affected packages, not the entire monolithic project).

