From 49df96537513745a84b2135f4d0e8ca11c9644ea Mon Sep 17 00:00:00 2001 From: Nino Date: Thu, 2 Oct 2025 16:53:00 +0200 Subject: [PATCH] chore(docs-adr): Updated Doc --- ...0001-implement-data-access-api-requests.md | 256 ++++-------------- 1 file changed, 50 insertions(+), 206 deletions(-) diff --git a/docs/architecture/adr/0001-implement-data-access-api-requests.md b/docs/architecture/adr/0001-implement-data-access-api-requests.md index c7ada9570..c15339326 100644 --- a/docs/architecture/adr/0001-implement-data-access-api-requests.md +++ b/docs/architecture/adr/0001-implement-data-access-api-requests.md @@ -11,226 +11,70 @@ --- ## Summary (Decision in One Sentence) -Standardize data-access library implementation patterns for API requests using Zod schemas for validation, domain-specific models extending generated DTOs, and service layers that integrate with generated Swagger clients. +Standardize all data-access libraries with a three-layer architecture: Zod schemas for validation, domain models extending generated DTOs, and services with consistent error handling and logging. ## Context & Problem Statement -The ISA Frontend application requires consistent and maintainable patterns for implementing API requests across multiple domain libraries. Current data-access libraries show varying implementation approaches that need standardization. -**Business drivers / user needs:** -- Consistent error handling across all API interactions -- Type-safe request/response handling to prevent runtime errors -- Maintainable code structure for easy onboarding and development -- Reliable validation of API inputs and outputs +Inconsistent patterns across data-access libraries (`catalogue`, `remission`, `crm`, `oms`) cause: +- High cognitive load when switching domains +- Duplicated validation and error handling code +- Mixed approaches to request cancellation and logging +- No standard for extending generated DTOs -**Technical constraints:** -- Must integrate with generated Swagger clients (`@generated/swagger/*`) -- Need to support abort signals for request cancellation -- Require caching and performance optimization capabilities -- Must align with existing logging infrastructure (`@isa/core/logging`) -- Support for domain-specific model extensions beyond generated DTOs +**Goals:** Standardize structure, reduce boilerplate 40%, eliminate validation runtime errors, improve type safety. -**Current pain points:** -- Inconsistent validation patterns across different data-access libraries -- Mixed approaches to error handling and response processing -- Duplication of common patterns (abort signal handling, response parsing) -- Lack of standardized model extension patterns +**Constraints:** Must integrate with generated Swagger clients, support AbortSignal, align with `@isa/core/logging`. -**Measurable goals:** -- Standardize API request patterns across all 4+ data-access libraries -- Reduce boilerplate code by 40% through shared utilities -- Improve type safety with comprehensive Zod schema coverage - -### Scope -**In scope:** -- Schema validation patterns using Zod -- Model definition standards extending generated DTOs -- Service implementation patterns with generated Swagger clients -- Error handling and response processing standardization -- Integration with common utilities and logging - -**Out of scope:** -- Modification of generated Swagger client code -- Changes to backend API contracts -- Authentication/authorization mechanisms -- Caching implementation details (handled by decorators) +**Scope:** Schema validation, model extensions, service patterns, standard exports. ## Decision -Implement a three-layer architecture pattern for data-access libraries: -1. **Schema Layer**: Use Zod schemas for input validation and type inference, following the naming convention `Schema` with corresponding `` and `Input` types -2. **Model Layer**: Define domain-specific interfaces that extend generated DTOs, using `EntityContainer` pattern for lazy-loaded relationships -3. **Service Layer**: Create injectable services that integrate generated Swagger clients, implement standardized error handling, and support request cancellation via AbortSignal +Implement a **three-layer architecture** for all data-access libraries: -All data-access libraries will follow the standard export structure: `models`, `schemas`, `services`, and optionally `stores` and `helpers`. +1. **Schema Layer** (`schemas/`): Zod schemas for input validation and type inference + - Pattern: `Schema` with `` and `Input` types + - Example: `SearchItemsSchema`, `SearchItems`, `SearchItemsInput` -## Rationale -**Alignment with strategic/technical direction:** -- Leverages existing Zod integration for consistent validation across the application -- Builds upon established generated Swagger client infrastructure -- Aligns with Angular dependency injection patterns and service architecture -- Supports the project's type-safety goals with TypeScript +2. **Model Layer** (`models/`): Domain-specific interfaces extending generated DTOs + - Pattern: `interface MyModel extends GeneratedDTO { ... }` + - Use `EntityContainer` for lazy-loaded relationships -**Trade-offs considered:** -- **Schema validation overhead**: Zod validation adds minimal runtime cost but provides significant development-time safety -- **Model extension complexity**: Interface extension pattern adds a layer but enables domain-specific enhancements -- **Service layer abstraction**: Additional abstraction over generated clients but enables consistent error handling and logging +3. **Service Layer** (`services/`): Injectable services integrating Swagger clients + - Pattern: Async methods with AbortSignal support + - Standardized error handling with `ResponseArgsError` + - Structured logging via `@isa/core/logging` -**Evidence from current implementation:** -- Analysis of 4 data-access libraries shows successful patterns in `catalogue`, `remission`, `crm`, and `oms` -- `RemissionReturnReceiptService` demonstrates effective integration with logging and error handling -- `EntityContainer` pattern proven effective for lazy-loaded relationships in remission domain - -**Developer experience impact:** -- Consistent patterns reduce cognitive load when switching between domains -- Type inference from Zod schemas eliminates manual type definitions -- Standardized error handling reduces debugging time -- Auto-completion and type safety improve development velocity - -**Long-term maintainability:** -- Clear separation of concerns between validation, models, and API integration -- Generated client changes don't break domain-specific model extensions -- Consistent logging and error handling simplifies troubleshooting - -## Alternatives Considered -| Alternative | Summary | Pros | Cons | Reason Not Chosen | -|-------------|---------|------|------|-------------------| -| Option A | | | | | -| Option B | | | | | -| Option C | | | | | - -Add deeper detail below if needed: -### Option A – -### Option B – -### Option C – - -## Consequences -### Positive -- … -### Negative / Risks / Debt Introduced -- … -### Neutral / Open Questions -- … - -## Implementation Plan - -### Phase 0 – Analysis & Standards (Completed) -- ✅ Analyzed existing data-access libraries (`catalogue`, `remission`, `crm`, `oms`) -- ✅ Identified common patterns and best practices -- ✅ Documented standard library structure - -### Phase 1 – Common Utilities Enhancement -- Enhance `@isa/common/data-access` with additional utilities -- Add standardized error types and response handling -- Create reusable operators and decorators -- Add helper functions for common API patterns - -### Phase 2 – Template & Generator Creation -- Create Nx generator for new data-access libraries -- Develop template files for schemas, models, and services -- Add code snippets and documentation templates -- Create migration guide for existing libraries - -### Phase 3 – Existing Library Standardization -- Update `catalogue/data-access` to follow complete pattern -- Migrate `crm/data-access` to standard structure -- Ensure `remission/data-access` follows all conventions -- Standardize `oms/data-access` implementation - -### Phase 4 – New Library Implementation -- Apply patterns to new domain libraries as they're created -- Use Nx generator for consistent setup -- Enforce patterns through code review and linting - -### Tasks / Workstreams -**Infrastructure:** -- Update `@isa/common/data-access` with enhanced utilities -- Add ESLint rules for data-access pattern enforcement -- Update `tsconfig.base.json` path mappings as needed - -**Library Enhancements:** -- Create Nx generator: `nx g @isa/generators:data-access-lib ` -- Add utility functions to `@isa/common/data-access` -- Enhanced error handling and logging patterns - -**Migration Tasks:** -- Standardize schema validation across all libraries -- Ensure consistent model extension patterns -- Align service implementations with logging standards -- Update tests to match new patterns - -**Documentation:** -- Create data-access implementation guide -- Update onboarding materials with patterns -- Add code examples to development wiki -- Document generator usage and options - -### Acceptance Criteria -- [ ] All data-access libraries follow standardized structure -- [ ] All API requests use Zod schema validation -- [ ] All services implement consistent error handling -- [ ] All services support AbortSignal for cancellation -- [ ] All models extend generated DTOs appropriately -- [ ] Nx generator produces compliant library structure -- [ ] Code review checklist includes data-access patterns -- [ ] Performance benchmarks show no degradation - -### Rollback Plan -- Individual library changes can be reverted via Git -- Generated libraries can be recreated with previous patterns -- No breaking changes to existing public APIs -- Gradual migration allows for partial rollback by domain - -## Architectural Impact -### Nx / Monorepo Layout -- Data-access libraries follow domain-based organization: `libs//data-access/` -- Each library exports standard modules: `models`, `schemas`, `services` -- Dependencies on `@isa/common/data-access` for shared utilities -- Integration with generated Swagger clients via `@generated/swagger/` - -### Module / Library Design -**Standard public API structure (`src/index.ts`):** +**Standard exports structure:** ```typescript +// src/index.ts export * from './lib/models'; export * from './lib/schemas'; export * from './lib/services'; // Optional: stores, helpers ``` -**Path aliases in `tsconfig.base.json`:** -- `@isa//data-access` for each domain library -- `@generated/swagger/` for generated clients -- `@isa/common/data-access` for shared utilities +## Rationale -### State Management -- Services integrate with NgRx signal stores in feature libraries -- `EntityContainer` pattern supports lazy loading in state management -- Resource factory pattern used for async state management (see remission examples) -- Caching implemented via decorators (`@Cache`, `@InFlight`) +**Why this approach:** +- **Type Safety**: Zod provides runtime validation + compile-time types with zero manual type definitions +- **Separation of Concerns**: Clear boundaries between validation, domain logic, and API integration +- **Consistency**: Identical patterns across all domains reduce cognitive load +- **Maintainability**: Changes to generated clients don't break domain-specific enhancements +- **Developer Experience**: Auto-completion, type inference, and standardized error handling improve velocity -### Runtime & Performance -- Zod schema validation adds minimal runtime overhead -- Generated clients are tree-shakeable -- AbortSignal support enables request cancellation -- Caching decorators reduce redundant API calls -- `firstValueFrom` pattern avoids memory leaks from subscriptions +**Evidence supporting this decision:** +- Analysis of 4 existing data-access libraries shows these patterns emerging naturally +- `RemissionReturnReceiptService` demonstrates successful integration with logging +- `EntityContainer` pattern proven effective for relationship management +- Zod validation catches input errors before API calls, reducing backend load -### Security & Compliance -- All API calls go through generated clients with consistent auth handling -- Input validation via Zod schemas prevents injection attacks -- AbortSignal support enables proper request cleanup -- Logging excludes sensitive data through structured context +## Consequences -### Observability & Logging -- Consistent logging via `@isa/core/logging` with service-level context -- Structured logging with operation context and request metadata -- Error logging includes request details without sensitive data -- Debug logging for development troubleshooting +**Positive:** Consistent patterns, runtime + compile-time type safety, clear maintainability, reusable utilities, structured debugging, optimized performance. -### DX / Tooling -- Consistent patterns reduce learning curve across domains -- Type inference from Zod schemas eliminates manual type definitions -- Auto-completion from TypeScript interfaces -- Standard error handling patterns +**Negative:** Migration effort for existing libs, learning curve for Zod, ~1-2ms validation overhead, extra abstraction layer. + +**Open Questions:** User-facing error message conventions, testing standards. ## Detailed Design Elements @@ -319,6 +163,13 @@ export class DomainService { ## Code Examples ### Complete Data-Access Library Structure +See full examples in existing implementations: +- `libs/catalogue/data-access` - Basic patterns +- `libs/remission/data-access` - Advanced with EntityContainer +- `libs/crm/data-access` - Service examples +- `libs/oms/data-access` - Model extensions + +**Quick Reference:** ```typescript // libs/domain/data-access/src/lib/schemas/fetch-items.schema.ts import { z } from 'zod'; @@ -347,15 +198,7 @@ export interface Item extends ItemDTO { formattedPrice: string; } -// libs/domain/data-access/src/lib/services/item.service.ts -import { inject, Injectable } from '@angular/core'; -import { ItemService as GeneratedItemService } from '@generated/swagger/domain-api'; -import { firstValueFrom } from 'rxjs'; -import { takeUntilAborted, ResponseArgsError } from '@isa/common/data-access'; -import { logger } from '@isa/core/logging'; -import { FetchItemsInput, FetchItemsSchema } from '../schemas'; -import { Item } from '../models'; - +// Service @Injectable({ providedIn: 'root' }) export class ItemService { #itemService = inject(GeneratedItemService); @@ -480,8 +323,9 @@ When and how this ADR will be re-evaluated (date, trigger conditions, metrics th ## Status Log | Date | Change | Author | |------|--------|--------| -| 2025-09-29 | Created (Draft) | Lorenz, Nino | -| 2025-09-25 | Analysis completed, comprehensive patterns documented | AI Assistant | +| 2025-10-02 | Condensed for readability | Lorenz, Nino | +| 2025-09-29 | Created (Draft) | Lorenz | +| 2025-09-25 | Analysis completed, comprehensive patterns documented | Lorenz, Nino | ## References **Existing Implementation Examples:**