@breadstone/archipel-mcp 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +32 -13
  2. package/data/guides/ai-text-generation.md +16 -24
  3. package/data/guides/cryptography-and-otp.md +2 -2
  4. package/data/guides/database-setup.md +4 -3
  5. package/data/guides/email-templates.md +52 -42
  6. package/data/guides/getting-started.md +6 -6
  7. package/data/guides/resource-management.md +9 -9
  8. package/data/packages/platform-authentication/api/Interface.IMfaSubjectUpdate.md +1 -1
  9. package/data/packages/platform-authentication/api/index.md +1 -1
  10. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_PROVIDER_OPTIONS.md +1 -1
  11. package/data/packages/platform-blob-storage/api/Variable.AZURE_BLOB_PROVIDER_OPTIONS.md +1 -1
  12. package/data/packages/platform-blob-storage/api/Variable.BLOB_PROVIDER.md +1 -1
  13. package/data/packages/platform-blob-storage/api/Variable.VERCEL_BLOB_PROVIDER_OPTIONS.md +1 -1
  14. package/data/packages/platform-caching/api/Class.RedisLayeredCache.md +3 -3
  15. package/data/packages/platform-core/api/Class.ErrorTemplateService.md +1 -1
  16. package/data/packages/platform-core/api/Class.HostService.md +1 -1
  17. package/data/packages/platform-core/api/Variable.ID_GENERATOR_TOKEN.md +1 -1
  18. package/data/packages/platform-core/api/index.md +0 -27
  19. package/data/packages/platform-core/index.md +7 -4
  20. package/data/packages/platform-cryptography/api/Class.BcryptService.md +4 -4
  21. package/data/packages/platform-cryptography/api/Class.OtpService.md +6 -6
  22. package/data/packages/platform-cryptography/api/Variable.BCRYPT_OPTIONS.md +2 -2
  23. package/data/packages/platform-cryptography/api/Variable.MAX_BCRYPT_PASSWORD_BYTES.md +1 -1
  24. package/data/packages/platform-cryptography/api/Variable.MIN_BCRYPT_ROUNDS.md +1 -1
  25. package/data/packages/platform-cryptography/api/Variable.OTP_OPTIONS.md +2 -2
  26. package/data/packages/platform-cryptography/api/Variable.OTP_SERVICE_TOKEN.md +2 -2
  27. package/data/packages/platform-cryptography/api/Variable.TOTP_EPOCH_TOLERANCE.md +1 -1
  28. package/data/packages/platform-cryptography/api/index.md +3 -3
  29. package/data/packages/platform-documents/api/Class.BaseDocumentRenderer.md +32 -1
  30. package/data/packages/platform-documents/api/Class.DocumentEngine.md +4 -4
  31. package/data/packages/platform-documents/api/Class.DocumentModule.md +2 -2
  32. package/data/packages/platform-documents/api/Class.DocxDocumentRenderer2.md +333 -0
  33. package/data/packages/platform-documents/api/Class.PdfDocumentRenderer.md +355 -0
  34. package/data/packages/platform-documents/api/Interface.IDocumentModuleOptions.md +31 -5
  35. package/data/packages/platform-documents/api/Variable.DOCUMENT_MODULE_OPTIONS.md +1 -1
  36. package/data/packages/platform-documents/api/Variable.DOCUMENT_PARSER_TOKEN.md +1 -1
  37. package/data/packages/platform-documents/api/Variable.DOCUMENT_RENDERER_TOKEN.md +1 -1
  38. package/data/packages/platform-documents/api/Variable.IMAGE_PROCESSOR_TOKEN.md +1 -1
  39. package/data/packages/platform-documents/api/index.md +2 -0
  40. package/data/packages/platform-esigning/api/Class.EsigningClientPort.md +1 -1
  41. package/data/packages/platform-health/index.md +128 -0
  42. package/data/packages/platform-mailing/api/Class.DeliveryStrategyBase.md +0 -1
  43. package/data/packages/platform-mailing/api/Class.MailModule.md +1 -1
  44. package/data/packages/platform-mailing/api/Class.MailVerificationService.md +1 -1
  45. package/data/packages/platform-mailing/api/Class.TemplateFetchStrategyBase.md +0 -5
  46. package/data/packages/platform-mailing/api/Variable.SMTP_CONFIG_ENTRIES.md +14 -0
  47. package/data/packages/platform-mailing/api/Variable.SMTP_HOST.md +14 -0
  48. package/data/packages/platform-mailing/api/Variable.SMTP_PASSWORD.md +14 -0
  49. package/data/packages/platform-mailing/api/Variable.SMTP_PORT.md +14 -0
  50. package/data/packages/platform-mailing/api/Variable.SMTP_SECURE.md +14 -0
  51. package/data/packages/platform-mailing/api/Variable.SMTP_USER.md +14 -0
  52. package/data/packages/platform-mailing/api/index.md +7 -4
  53. package/data/packages/platform-mapping/index.md +121 -0
  54. package/data/packages/platform-mcp/api/Variable.MCP_MODULE_OPTIONS.md +1 -1
  55. package/data/packages/platform-openapi/api/Class.SwaggerMultiDocumentService.md +4 -4
  56. package/data/packages/platform-resources/index.md +135 -0
  57. package/data/packages/platform-telemetry/api/Class.OtelSdkHolder.md +1 -1
  58. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_ENABLED.md +1 -1
  59. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_FACADE.md +1 -1
  60. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_OPTIONS.md +1 -1
  61. package/{src/knowledge/configPattern.js → data/patterns/config-pattern.md} +46 -49
  62. package/{src/knowledge/dtoPattern.js → data/patterns/dto-pattern.md} +58 -61
  63. package/{src/knowledge/errorHandlingPattern.js → data/patterns/error-handling-pattern.md} +35 -38
  64. package/{src/knowledge/guardPattern.js → data/patterns/guard-pattern.md} +35 -38
  65. package/{src/knowledge/mappingPattern.js → data/patterns/mapping-pattern.md} +43 -144
  66. package/data/patterns/module-pattern.md +182 -0
  67. package/data/patterns/query-pattern.md +137 -0
  68. package/data/patterns/repository-pattern.md +208 -0
  69. package/{src/knowledge/testingPattern.js → data/patterns/testing-pattern.md} +37 -40
  70. package/package.json +2 -2
  71. package/src/PatternsLoader.d.ts +12 -0
  72. package/src/PatternsLoader.js +65 -0
  73. package/src/generators/mappingPatternGenerator.d.ts +5 -0
  74. package/src/generators/mappingPatternGenerator.js +107 -0
  75. package/src/generators/modulePatternGenerator.d.ts +5 -0
  76. package/src/generators/modulePatternGenerator.js +107 -0
  77. package/src/generators/queryPatternGenerator.d.ts +4 -0
  78. package/src/generators/queryPatternGenerator.js +83 -0
  79. package/src/generators/repositoryPatternGenerator.d.ts +5 -0
  80. package/src/generators/repositoryPatternGenerator.js +165 -0
  81. package/src/main.js +15 -9
  82. package/src/models/IPatternDoc.d.ts +15 -0
  83. package/src/models/IPatternDoc.js +3 -0
  84. package/src/tools/registerGetConfigPatternTool.d.ts +2 -1
  85. package/src/tools/registerGetConfigPatternTool.js +5 -4
  86. package/src/tools/registerGetDtoPatternTool.d.ts +2 -1
  87. package/src/tools/registerGetDtoPatternTool.js +5 -4
  88. package/src/tools/registerGetErrorHandlingPatternTool.d.ts +2 -1
  89. package/src/tools/registerGetErrorHandlingPatternTool.js +5 -4
  90. package/src/tools/registerGetGuardPatternTool.d.ts +2 -1
  91. package/src/tools/registerGetGuardPatternTool.js +5 -4
  92. package/src/tools/registerGetMappingPatternTool.d.ts +2 -1
  93. package/src/tools/registerGetMappingPatternTool.js +6 -5
  94. package/src/tools/registerGetModulePatternTool.d.ts +2 -1
  95. package/src/tools/registerGetModulePatternTool.js +6 -5
  96. package/src/tools/registerGetQueryPatternTool.d.ts +2 -1
  97. package/src/tools/registerGetQueryPatternTool.js +6 -5
  98. package/src/tools/registerGetRepositoryPatternTool.d.ts +2 -1
  99. package/src/tools/registerGetRepositoryPatternTool.js +6 -5
  100. package/src/tools/registerGetTestingPatternTool.d.ts +2 -1
  101. package/src/tools/registerGetTestingPatternTool.js +5 -4
  102. package/data/packages/platform-core/api/Class.BlobResourceStrategy.md +0 -195
  103. package/data/packages/platform-core/api/Class.EmbeddedResourceStrategy.md +0 -215
  104. package/data/packages/platform-core/api/Class.FileResourceStrategy.md +0 -192
  105. package/data/packages/platform-core/api/Class.HealthModule.md +0 -42
  106. package/data/packages/platform-core/api/Class.HealthOrchestrator.md +0 -64
  107. package/data/packages/platform-core/api/Class.MappingBuilder.md +0 -110
  108. package/data/packages/platform-core/api/Class.MappingModule.md +0 -46
  109. package/data/packages/platform-core/api/Class.MappingNotRegisteredError.md +0 -56
  110. package/data/packages/platform-core/api/Class.MappingProfileBase.md +0 -52
  111. package/data/packages/platform-core/api/Class.MappingService.md +0 -284
  112. package/data/packages/platform-core/api/Class.ResourceManager.md +0 -565
  113. package/data/packages/platform-core/api/Class.ResourceModule.md +0 -46
  114. package/data/packages/platform-core/api/Class.TypeMappingNotRegisteredError.md +0 -57
  115. package/data/packages/platform-core/api/Function.createMappingKey.md +0 -39
  116. package/data/packages/platform-core/api/Interface.IBlobResourceStrategyConfig.md +0 -28
  117. package/data/packages/platform-core/api/Interface.IBlobServiceAdapter.md +0 -40
  118. package/data/packages/platform-core/api/Interface.IFileResourceStrategyConfig.md +0 -72
  119. package/data/packages/platform-core/api/Interface.IHealthCheckResult.md +0 -46
  120. package/data/packages/platform-core/api/Interface.IHealthIndicator.md +0 -41
  121. package/data/packages/platform-core/api/Interface.IMappingBuilder.md +0 -76
  122. package/data/packages/platform-core/api/Interface.IMappingKey.md +0 -58
  123. package/data/packages/platform-core/api/Interface.IMappingProfile.md +0 -32
  124. package/data/packages/platform-core/api/Interface.IResourceManagerConfig.md +0 -89
  125. package/data/packages/platform-core/api/Interface.IResourceMetadata.md +0 -94
  126. package/data/packages/platform-core/api/Interface.IResourceResult.md +0 -34
  127. package/data/packages/platform-core/api/Interface.IResourceStrategy.md +0 -134
  128. package/data/packages/platform-core/api/Variable.HEALTH_INDICATORS_TOKEN.md +0 -14
  129. package/data/packages/platform-mailing/api/Class.BlobTemplateFetchStrategy.md +0 -60
  130. package/data/packages/platform-mailing/api/Class.FileTemplateFetchStrategy.md +0 -58
  131. package/data/packages/platform-mailing/api/Class.LogDeliveryStrategy.md +0 -71
  132. package/src/knowledge/configPattern.d.ts +0 -5
  133. package/src/knowledge/dtoPattern.d.ts +0 -5
  134. package/src/knowledge/errorHandlingPattern.d.ts +0 -5
  135. package/src/knowledge/guardPattern.d.ts +0 -5
  136. package/src/knowledge/mappingPattern.d.ts +0 -6
  137. package/src/knowledge/modulePattern.d.ts +0 -6
  138. package/src/knowledge/modulePattern.js +0 -283
  139. package/src/knowledge/queryPattern.d.ts +0 -6
  140. package/src/knowledge/queryPattern.js +0 -215
  141. package/src/knowledge/repositoryPattern.d.ts +0 -6
  142. package/src/knowledge/repositoryPattern.js +0 -367
  143. package/src/knowledge/testingPattern.d.ts +0 -5
@@ -0,0 +1,182 @@
1
+ ---
2
+ title: Dynamic Module Pattern
3
+ description: NestJS dynamic modules with register(), port/adapter dependency inversion, and ConfigModule integration.
4
+ order: 6
5
+ ---
6
+
7
+ # Archipel Dynamic Module Pattern
8
+
9
+ ## Overview
10
+
11
+ Archipel platform libraries use **NestJS dynamic modules** with a `register()` factory
12
+ method and **port/adapter dependency inversion**. Each library defines abstract port
13
+ classes. The consuming application provides concrete implementations at registration time.
14
+
15
+ This pattern keeps platform libraries free of product-specific logic while allowing
16
+ full customization through dependency injection.
17
+
18
+ ## Pattern Structure
19
+
20
+ ### 1. Abstract Port (Contract)
21
+
22
+ ```typescript
23
+ // contracts/FeatureAccessPort.ts
24
+
25
+ export abstract class FeatureAccessPort {
26
+
27
+ public abstract checkAccess(userId: string, featureKey: string): Promise<IFeatureAccessResult>;
28
+
29
+ public abstract recordUsage(userId: string, featureKey: string): Promise<void>;
30
+
31
+ }
32
+ ```
33
+
34
+ Ports are **abstract classes** (not interfaces) so they can serve as NestJS injection tokens.
35
+
36
+ ### 2. Options Interface
37
+
38
+ ```typescript
39
+ // interfaces/IPaymentModuleOptions.ts
40
+
41
+ export interface IPaymentModuleOptions {
42
+ /**
43
+ * Concrete implementation of the FeatureAccessPort.
44
+ */
45
+ featureAccess?: Type<FeatureAccessPort>;
46
+
47
+ /**
48
+ * When true the module is registered globally.
49
+ */
50
+ isGlobal?: boolean;
51
+ }
52
+ ```
53
+
54
+ ### 3. Dynamic Module with register()
55
+
56
+ ```typescript
57
+ // PaymentModule.ts
58
+ import { ConfigModule } from '@breadstone/archipel-platform-core';
59
+ import { type DynamicModule, Module, type Type } from '@nestjs/common';
60
+
61
+ @Module({})
62
+ export class PaymentModule {
63
+
64
+ public static register(options?: IPaymentModuleOptions): DynamicModule {
65
+ const providers = [StripeClient, FeatureGuard, FeatureUsageInterceptor];
66
+
67
+ if (options?.featureAccess) {
68
+ providers.push({
69
+ provide: FeatureAccessPort,
70
+ useClass: options.featureAccess,
71
+ } as never);
72
+ }
73
+
74
+ return {
75
+ global: options?.isGlobal ?? false,
76
+ module: PaymentModule,
77
+ imports: [ConfigModule.register('platform-payments', PLATFORM_PAYMENTS_CONFIG_ENTRIES)],
78
+ providers: providers,
79
+ exports: [StripeClient, FeatureGuard, FeatureUsageInterceptor],
80
+ };
81
+ }
82
+
83
+ }
84
+ ```
85
+
86
+ ### 4. Consumer Registration
87
+
88
+ ```typescript
89
+ // In the consuming application:
90
+ @Module({
91
+ imports: [
92
+ PaymentModule.register({
93
+ featureAccess: MyFeatureAccessAdapter,
94
+ isGlobal: true,
95
+ }),
96
+ ],
97
+ })
98
+ export class AppModule {}
99
+ ```
100
+
101
+ ## Variants in the Codebase
102
+
103
+ ### Simple: PaymentModule
104
+
105
+ - 1 optional port (`featureAccess`)
106
+ - Optional `isGlobal` flag
107
+ - Config via `ConfigModule.register()`
108
+
109
+ ### Complex: AuthModule
110
+
111
+ - 4 required ports (`authSubject`, `mfaSubject`, `sessionPersistence`, `verificationSubject`)
112
+ - 2 optional ports (`socialAuth`, `tokenEnricher`)
113
+ - Conditional strategy registration (social OAuth only when `socialAuth` provided)
114
+ - Imports: PassportModule, JwtModule, MappingModule, EventModule, IdentifierModule
115
+ - Middleware configuration via `configure(consumer)`
116
+
117
+ ### Provider-based: BlobModule
118
+
119
+ - Uses `forRoot()` instead of `register()` (global by default)
120
+ - Discriminated union for provider selection: `{ kind: 'Vercel' }` or `{ kind: 'Custom', useClass: ... }`
121
+ - Optional persistence ports (`objectPersistence`, `variantPersistence`)
122
+
123
+ ### Infrastructure: DatabaseModule
124
+
125
+ - Both `forRoot()` (global) and `register()` (scoped) variants
126
+ - Factory provider for PrismaService with extensions
127
+ - Health indicator bootstrapping
128
+
129
+ ### Async: McpModule
130
+
131
+ - `register(options)` for synchronous configuration
132
+ - `registerAsync({ useFactory, inject })` for async (e.g., reading config at runtime)
133
+ - `registerAsync({ useClass })` for factory class pattern
134
+ - `registerAsync({ useExisting })` for reusing an existing factory
135
+
136
+ ## ConfigModule Integration
137
+
138
+ Every library module imports `ConfigModule.register()` to declare its configuration
139
+ dependencies:
140
+
141
+ ```typescript
142
+ imports: [ConfigModule.register('platform-payments', PLATFORM_PAYMENTS_CONFIG_ENTRIES)]
143
+ ```
144
+
145
+ This registers typed config keys into the global `ConfigRegistry` for validation
146
+ and discovery.
147
+
148
+ ## MappingModule Integration
149
+
150
+ Modules that need object mapping import `MappingModule.withProfiles()`:
151
+
152
+ ```typescript
153
+ imports: [MappingModule.withProfiles([SessionMappingProfile])]
154
+ ```
155
+
156
+ ## Health Indicator Pattern
157
+
158
+ Infrastructure modules (Database, Blob) register health indicators:
159
+
160
+ ```typescript
161
+ providers: [
162
+ BlobHealthIndicator,
163
+ {
164
+ provide: 'BLOB_HEALTH_INDICATOR_BOOTSTRAP',
165
+ useFactory: (orchestrator: HealthOrchestrator, indicator: BlobHealthIndicator) => {
166
+ orchestrator.registerIndicator(indicator);
167
+ return true;
168
+ },
169
+ inject: [HealthOrchestrator, BlobHealthIndicator],
170
+ },
171
+ ]
172
+ ```
173
+
174
+ ## Rules
175
+
176
+ 1. **Ports are abstract classes** — not interfaces — so they work as DI tokens.
177
+ 2. **`register()` for stateless config**, `registerAsync()` when config depends on runtime values.
178
+ 3. **`forRoot()` for global singletons** (database, blob storage), `register()` for scoped modules.
179
+ 4. **Always import ConfigModule.register()** to declare environment dependencies.
180
+ 5. **Optional ports use conditional provider registration** (`if (options?.port)`).
181
+ 6. **Required ports are listed in the options interface** without optional markers.
182
+ 7. **Exports should list concrete services, guards, interceptors** — not internal implementation details.
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: Query Pattern
3
+ description: Repository + Query pattern with IRepositoryQuery, factory functions, transactional queries, and rules.
4
+ order: 7
5
+ ---
6
+
7
+ # Archipel Query Pattern (v1)
8
+
9
+ ## Overview
10
+
11
+ In Archipel, data access follows the **Repository + Query** pattern. Repositories never expose
12
+ raw Prisma delegate methods to services. Instead, every data operation is wrapped in a
13
+ **query factory function** that returns an `IRepositoryQuery` object. Services call
14
+ `repository.execute(someQuery(...))` — never `repository.findFirst(...)` directly.
15
+
16
+ ## Core Interface
17
+
18
+ ```typescript
19
+ export interface IRepositoryQuery<TDelegate, TResult> {
20
+ readonly name: string;
21
+ run(model: TDelegate): Promise<TResult>;
22
+ }
23
+ ```
24
+
25
+ - `TDelegate` — the Prisma delegate type (e.g. `Prisma.UserDelegate`)
26
+ - `TResult` — the query's return type
27
+ - `name` — identifier used for logging and debugging
28
+
29
+ ## Factory Function
30
+
31
+ ```typescript
32
+ import { IRepositoryQuery } from '@breadstone/archipel-platform-database';
33
+
34
+ export function query<TDelegate, TResult>(
35
+ name: string,
36
+ run: (model: TDelegate) => Promise<TResult>,
37
+ ): IRepositoryQuery<TDelegate, TResult> {
38
+ return { name, run };
39
+ }
40
+ ```
41
+
42
+ ## Type Extraction
43
+
44
+ ```typescript
45
+ export type QueryResultType<T> = T extends IRepositoryQuery<unknown, infer R> ? R : never;
46
+ ```
47
+
48
+ Use this to derive the result type from a query factory without duplicating types:
49
+ ```typescript
50
+ type UserProfileResult = QueryResultType<ReturnType<typeof findUserProfileQuery>>;
51
+ ```
52
+
53
+ ## How to Write a Query
54
+
55
+ ### Step 1: Define the query factory function
56
+
57
+ Each query is a **named function** that returns an `IRepositoryQuery`. The function may accept
58
+ parameters — these become the query's runtime arguments.
59
+
60
+ ```typescript
61
+ import { Prisma } from '@prisma/client';
62
+ import { query } from '@breadstone/archipel-platform-database';
63
+
64
+ export function findUserByEmailQuery(email: string) {
65
+ return query<Prisma.UserDelegate, { id: string; email: string; name: string } | null>(
66
+ 'findUserByEmail',
67
+ (model) =>
68
+ model.findFirst({
69
+ where: { email },
70
+ select: { id: true, email: true, name: true },
71
+ }),
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### Step 2: Call from a service via repository.execute()
77
+
78
+ ```typescript
79
+ // In the service:
80
+ const user = await this._userRepository.execute(findUserByEmailQuery(email));
81
+ ```
82
+
83
+ ### Step 3: Extract result type if needed for mapping
84
+
85
+ ```typescript
86
+ type FindUserByEmailResult = QueryResultType<ReturnType<typeof findUserByEmailQuery>>;
87
+ ```
88
+
89
+ ## Transactional Queries
90
+
91
+ For operations that span multiple models, use `transactionalQuery`:
92
+
93
+ ```typescript
94
+ import { Prisma } from '@prisma/client';
95
+ import { transactionalQuery } from '@breadstone/archipel-platform-database';
96
+
97
+ export function createOrderWithItemsQuery(data: { userId: string; items: Array<{ productId: string; quantity: number }> }) {
98
+ return transactionalQuery<{ orderId: string }>(
99
+ 'createOrderWithItems',
100
+ async (tx: Prisma.TransactionClient) => {
101
+ const order = await tx.order.create({
102
+ data: { userId: data.userId },
103
+ select: { id: true },
104
+ });
105
+
106
+ await tx.orderItem.createMany({
107
+ data: data.items.map((item) => ({
108
+ orderId: order.id,
109
+ productId: item.productId,
110
+ quantity: item.quantity,
111
+ })),
112
+ });
113
+
114
+ return { orderId: order.id };
115
+ },
116
+ );
117
+ }
118
+ ```
119
+
120
+ Called via:
121
+ ```typescript
122
+ const result = await this._orderRepository.executeTransactional(
123
+ createOrderWithItemsQuery({ userId, items }),
124
+ );
125
+ ```
126
+
127
+ ## Rules
128
+
129
+ 1. **Never call Prisma delegate methods directly from services.** Always go through `execute(query)`.
130
+ 2. **Always select only the fields you need.** Use `select` — never return full records.
131
+ 3. **Query names must be descriptive.** Use the pattern: `verbModelByConditionQuery`
132
+ (e.g. `findUserByEmailQuery`, `countOrdersByStatusQuery`, `updateUserNameQuery`).
133
+ 4. **One query per file** for non-trivial queries. Small related queries may share a file.
134
+ 5. **Type the result explicitly.** The second generic parameter of `query()` should be an inline
135
+ object type or a dedicated interface matching the `select` shape.
136
+ 6. **Each query factory is a standalone function** (not a class method). Import `query` from
137
+ `@breadstone/archipel-platform-database`.
@@ -0,0 +1,208 @@
1
+ ---
2
+ title: Repository Pattern
3
+ description: RepositoryBase subclasses, DelegateArgs/DelegateReturnTypes helpers, module registration, and service injection.
4
+ order: 8
5
+ ---
6
+
7
+ # Archipel Repository Pattern
8
+
9
+ ## Overview
10
+
11
+ Every Prisma model gets a dedicated **Repository class** extending `RepositoryBase`.
12
+ Repositories are the ONLY code that touches Prisma delegates. Services never call
13
+ Prisma directly — they call `repository.execute(someQuery(...))` or
14
+ `repository.executeTransactional(someTxQuery(...))`.
15
+
16
+ ## RepositoryBase Signature
17
+
18
+ ```typescript
19
+ import { RepositoryBase } from '@breadstone/archipel-platform-database';
20
+
21
+ export abstract class RepositoryBase<
22
+ TDelegate extends Record<RepositoryOperations, (args: any) => Promise<any>>,
23
+ TArgs extends Record<RepositoryOperations, unknown>,
24
+ TReturn extends Record<RepositoryOperations, unknown>,
25
+ TEntity = unknown
26
+ >
27
+ ```
28
+
29
+ ### Generic Parameters
30
+
31
+ | Param | Purpose | Example |
32
+ |-------|---------|---------|
33
+ | `TDelegate` | Prisma delegate type from generated client | `Prisma.UserDelegate` |
34
+ | `TArgs` | Argument shapes for each operation | `Prisma.UserFindManyArgs`, etc. |
35
+ | `TReturn` | Return shapes for each operation | `User`, `User[]`, etc. |
36
+ | `TEntity` | Domain entity interface (optional) | `IUserEntity` |
37
+
38
+ ### Helper Types
39
+
40
+ ```typescript
41
+ import { DelegateArgs, DelegateReturnTypes } from '@breadstone/archipel-platform-database';
42
+
43
+ // These extract args and return types from a delegate automatically:
44
+ type UserArgs = DelegateArgs<Prisma.UserDelegate>;
45
+ type UserReturns = DelegateReturnTypes<Prisma.UserDelegate>;
46
+ ```
47
+
48
+ ## How to Create a Repository
49
+
50
+ ### Step 1: Create the repository class
51
+
52
+ ```typescript
53
+ // repositories/UserRepository.ts
54
+ import { Injectable } from '@nestjs/common';
55
+ import { Prisma } from '@prisma/client';
56
+ import {
57
+ DatabaseService,
58
+ DelegateArgs,
59
+ DelegateReturnTypes,
60
+ RepositoryBase,
61
+ } from '@breadstone/archipel-platform-database';
62
+
63
+ @Injectable()
64
+ export class UserRepository extends RepositoryBase<
65
+ Prisma.UserDelegate,
66
+ DelegateArgs<Prisma.UserDelegate>,
67
+ DelegateReturnTypes<Prisma.UserDelegate>,
68
+ IUserEntity
69
+ > {
70
+
71
+ // #region Ctor
72
+
73
+ public constructor(db: DatabaseService) {
74
+ super(db, db.client.user);
75
+ }
76
+
77
+ // #endregion
78
+
79
+ }
80
+ ```
81
+
82
+ The constructor receives `DatabaseService` and passes both the service and the
83
+ Prisma delegate (`db.client.user`) to the base class.
84
+
85
+ ### Step 2: Register as a provider in a module
86
+
87
+ ```typescript
88
+ @Module({
89
+ imports: [DatabaseModule.register()],
90
+ providers: [UserRepository, UserService],
91
+ exports: [UserService],
92
+ })
93
+ export class UserModule {}
94
+ ```
95
+
96
+ ### Step 3: Inject into a service
97
+
98
+ ```typescript
99
+ @Injectable()
100
+ export class UserService {
101
+
102
+ // #region Fields
103
+
104
+ private readonly _userRepository: UserRepository;
105
+
106
+ // #endregion
107
+
108
+ // #region Ctor
109
+
110
+ public constructor(userRepository: UserRepository) {
111
+ this._userRepository = userRepository;
112
+ }
113
+
114
+ // #endregion
115
+
116
+ // #region Methods
117
+
118
+ public async findById(id: string): Promise<IUserEntity | null> {
119
+ return this._userRepository.execute(findUserByIdQuery(id));
120
+ }
121
+
122
+ public async findAll(skip = 0, take = 20): Promise<IUserEntity[]> {
123
+ return this._userRepository.execute(findAllUsersQuery(skip, take));
124
+ }
125
+
126
+ // #endregion
127
+
128
+ }
129
+ ```
130
+
131
+ ## Key Methods on RepositoryBase
132
+
133
+ ### execute(query)
134
+
135
+ Primary method for data access. Delegates to a query object.
136
+
137
+ ```typescript
138
+ public execute<TResult>(query: IRepositoryQuery<TDelegate, TResult>): Promise<TResult>
139
+ ```
140
+
141
+ ### executeTransactional(query)
142
+
143
+ For multi-model operations within a transaction.
144
+
145
+ ```typescript
146
+ public executeTransactional<TResult>(query: ITransactionalRepositoryQuery<TResult>): Promise<TResult>
147
+ ```
148
+
149
+ ### Direct Methods (for legacy or internal use only)
150
+
151
+ The base class also exposes `findUnique`, `findMany`, `findFirst`, `create`,
152
+ `createMany`, `update`, `updateMany`, `upsert`, `delete`, `deleteMany`,
153
+ `aggregate`, `count`, `groupBy`, `merge`.
154
+
155
+ **Important:** New code should use `execute(query)` exclusively.
156
+ Direct method calls are available but violate the query pattern convention.
157
+
158
+ ### findMany with Pagination
159
+
160
+ ```typescript
161
+ // Direct method (legacy)
162
+ const results = await this._repository.findMany(args, { page: 1, perPage: 20 });
163
+ ```
164
+
165
+ ## Error Handling
166
+
167
+ All Prisma errors are caught by the base class `tryCatch` wrapper and re-thrown
168
+ as `RepositoryError`:
169
+
170
+ - `PrismaClientKnownRequestError` → `RepositoryError` with code `'R_KNOWN'`
171
+ - `PrismaClientUnknownRequestError` → `RepositoryError` with code `'R_UNKNOWN'`
172
+ - Other errors are re-thrown unchanged
173
+
174
+ The global `RepositoryExceptionFilter` catches `RepositoryError` and returns
175
+ HTTP 500 with a structured envelope.
176
+
177
+ ## Query Integration
178
+
179
+ Repositories work with query factories from the query pattern:
180
+
181
+ ```typescript
182
+ // queries/findUserByIdQuery.ts
183
+ import { Prisma } from '@prisma/client';
184
+ import { query } from '@breadstone/archipel-platform-database';
185
+
186
+ export function findUserByIdQuery(id: string) {
187
+ return query<Prisma.UserDelegate, IUserEntity | null>(
188
+ 'findUserById',
189
+ (model) => model.findFirst({
190
+ where: { id },
191
+ select: { id: true, email: true, name: true, createdAt: true },
192
+ }),
193
+ );
194
+ }
195
+
196
+ // Service usage:
197
+ const user = await this._userRepository.execute(findUserByIdQuery(id));
198
+ ```
199
+
200
+ ## Rules
201
+
202
+ 1. **One repository per Prisma model** — e.g. `UserRepository`, `OrderRepository`.
203
+ 2. **Constructor receives `DatabaseService`** and passes the delegate via `db.client.<model>`.
204
+ 3. **Use `DelegateArgs` and `DelegateReturnTypes`** helper types for the RepositoryBase generics.
205
+ 4. **New code uses `execute(query)`** — never direct calls like `repository.findFirst()` from services.
206
+ 5. **Register as provider** in the feature module, import `DatabaseModule.register()`.
207
+ 6. **Repositories are `@Injectable()`** — they participate in NestJS DI.
208
+ 7. **Domain entity interface as fourth generic** (`TEntity`) is optional but recommended.