@martinffx/atelier 2.0.0 → 3.0.0

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 (81) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,412 +0,0 @@
1
- # Entity Pattern
2
-
3
- Domain entities encapsulate business logic and data transformations between API, domain, and database layers.
4
-
5
- ## Core Concept
6
-
7
- Entities have **four transformation methods**:
8
-
9
- 1. `fromRequest(rq)` - API request → Entity
10
- 2. `fromRecord(record)` - Database record → Entity
11
- 3. `toRecord()` - Entity → Database insert/update
12
- 4. `toResponse()` - Entity → API response
13
-
14
- This creates clear boundaries between layers and centralizes data transformation logic.
15
-
16
- ## Basic Entity
17
-
18
- ```typescript
19
- import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
20
- import type { users } from '../schema'
21
-
22
- // Infer types from schema
23
- type UserRecord = InferSelectModel<typeof users>
24
- type UserInsert = InferInsertModel<typeof users>
25
-
26
- interface UserEntityData {
27
- id: string
28
- name: string
29
- email: string
30
- createdAt: Date
31
- updatedAt: Date
32
- }
33
-
34
- export class UserEntity {
35
- public readonly id: string
36
- public readonly name: string
37
- public readonly email: string
38
- public readonly createdAt: Date
39
- public readonly updatedAt: Date
40
-
41
- // Private constructor enforces factory methods
42
- private constructor(data: UserEntityData) {
43
- this.id = data.id
44
- this.name = data.name
45
- this.email = data.email
46
- this.createdAt = data.createdAt
47
- this.updatedAt = data.updatedAt
48
- }
49
-
50
- // 1. API request → Entity
51
- static fromRequest(rq: CreateUserRequest, id?: string): UserEntity {
52
- const now = new Date()
53
- return new UserEntity({
54
- id: id ?? crypto.randomUUID(),
55
- name: rq.name,
56
- email: rq.email,
57
- createdAt: now,
58
- updatedAt: now,
59
- })
60
- }
61
-
62
- // 2. DB record → Entity
63
- static fromRecord(record: UserRecord): UserEntity {
64
- return new UserEntity({
65
- id: record.id,
66
- name: record.name,
67
- email: record.email,
68
- createdAt: record.createdAt,
69
- updatedAt: record.updatedAt,
70
- })
71
- }
72
-
73
- // 3. Entity → DB record
74
- toRecord(): UserInsert {
75
- return {
76
- id: this.id,
77
- name: this.name,
78
- email: this.email,
79
- createdAt: this.createdAt,
80
- updatedAt: this.updatedAt,
81
- }
82
- }
83
-
84
- // 4. Entity → API response
85
- toResponse(): UserResponse {
86
- return {
87
- id: this.id,
88
- name: this.name,
89
- email: this.email,
90
- createdAt: this.createdAt.toISOString(),
91
- updatedAt: this.updatedAt.toISOString(),
92
- }
93
- }
94
- }
95
- ```
96
-
97
- ## Entity with TypeID
98
-
99
- Using TypeID for type-safe prefixed identifiers:
100
-
101
- ```typescript
102
- import { TypeID } from 'typeid-js'
103
- import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
104
- import type { users } from '../schema'
105
-
106
- type UserID = TypeID<'usr'>
107
- type UserRecord = InferSelectModel<typeof users>
108
- type UserInsert = InferInsertModel<typeof users>
109
-
110
- export class UserEntity {
111
- public readonly id: UserID
112
- public readonly name: string
113
- public readonly email: string
114
-
115
- private constructor(data: {
116
- id: UserID
117
- name: string
118
- email: string
119
- }) {
120
- this.id = data.id
121
- this.name = data.name
122
- this.email = data.email
123
- }
124
-
125
- static fromRequest(rq: CreateUserRequest, id?: string): UserEntity {
126
- return new UserEntity({
127
- id: id ? TypeID.fromString<'usr'>(id) : new TypeID('usr'),
128
- name: rq.name,
129
- email: rq.email,
130
- })
131
- }
132
-
133
- static fromRecord(record: UserRecord): UserEntity {
134
- return new UserEntity({
135
- id: TypeID.fromString<'usr'>(record.id),
136
- name: record.name,
137
- email: record.email,
138
- })
139
- }
140
-
141
- toRecord(): UserInsert {
142
- return {
143
- id: this.id.toString(), // TypeID → string for DB
144
- name: this.name,
145
- email: this.email,
146
- }
147
- }
148
-
149
- toResponse(): UserResponse {
150
- return {
151
- id: this.id.toString(), // TypeID → string for API
152
- name: this.name,
153
- email: this.email,
154
- }
155
- }
156
- }
157
- ```
158
-
159
- ## Entity with JSON Fields
160
-
161
- Handle JSON serialization/deserialization:
162
-
163
- ```typescript
164
- import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
165
- import type { users } from '../schema'
166
-
167
- type UserMetadata = {
168
- theme: 'light' | 'dark'
169
- notifications: boolean
170
- }
171
-
172
- type UserRecord = InferSelectModel<typeof users>
173
- type UserInsert = InferInsertModel<typeof users>
174
-
175
- export class UserEntity {
176
- public readonly id: string
177
- public readonly name: string
178
- public readonly metadata?: UserMetadata
179
-
180
- private constructor(data: {
181
- id: string
182
- name: string
183
- metadata?: UserMetadata
184
- }) {
185
- this.id = data.id
186
- this.name = data.name
187
- this.metadata = data.metadata
188
- }
189
-
190
- static fromRequest(rq: CreateUserRequest, id?: string): UserEntity {
191
- return new UserEntity({
192
- id: id ?? crypto.randomUUID(),
193
- name: rq.name,
194
- metadata: rq.metadata, // Already typed from API schema
195
- })
196
- }
197
-
198
- static fromRecord(record: UserRecord): UserEntity {
199
- // Parse JSON string from TEXT column
200
- let metadata: UserMetadata | undefined
201
- if (record.metadata) {
202
- metadata = JSON.parse(record.metadata)
203
- }
204
-
205
- return new UserEntity({
206
- id: record.id,
207
- name: record.name,
208
- metadata,
209
- })
210
- }
211
-
212
- toRecord(): UserInsert {
213
- return {
214
- id: this.id,
215
- name: this.name,
216
- // Serialize to JSON string for TEXT column
217
- metadata: this.metadata ? JSON.stringify(this.metadata) : undefined,
218
- }
219
- }
220
-
221
- toResponse(): UserResponse {
222
- return {
223
- id: this.id,
224
- name: this.name,
225
- metadata: this.metadata, // Send as object
226
- }
227
- }
228
- }
229
- ```
230
-
231
- ## Entity with Business Logic
232
-
233
- Entities can contain domain logic that operates on their data:
234
-
235
- ```typescript
236
- import { TypeID } from 'typeid-js'
237
- import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
238
- import type { ledgerAccounts } from '../schema'
239
-
240
- type LedgerAccountID = TypeID<'lat'>
241
- type LedgerAccountRecord = InferSelectModel<typeof ledgerAccounts>
242
- type LedgerAccountInsert = InferInsertModel<typeof ledgerAccounts>
243
-
244
- export class LedgerAccountEntity {
245
- public readonly id: LedgerAccountID
246
- public readonly name: string
247
- public readonly normalBalance: 'debit' | 'credit'
248
- public readonly postedAmount: number
249
- public readonly lockVersion: number
250
- public readonly updated: Date
251
-
252
- private constructor(data: {
253
- id: LedgerAccountID
254
- name: string
255
- normalBalance: 'debit' | 'credit'
256
- postedAmount: number
257
- lockVersion: number
258
- updated: Date
259
- }) {
260
- Object.assign(this, data)
261
- }
262
-
263
- static fromRecord(record: LedgerAccountRecord): LedgerAccountEntity {
264
- return new LedgerAccountEntity({
265
- id: TypeID.fromString<'lat'>(record.id),
266
- name: record.name,
267
- normalBalance: record.normalBalance as 'debit' | 'credit',
268
- postedAmount: record.postedAmount,
269
- lockVersion: record.lockVersion,
270
- updated: record.updated,
271
- })
272
- }
273
-
274
- /**
275
- * Apply a transaction entry and return a new immutable entity.
276
- * Uses double-entry accounting rules based on the account's normal balance.
277
- */
278
- applyEntry(entry: {
279
- direction: 'debit' | 'credit'
280
- amount: number
281
- }): LedgerAccountEntity {
282
- let newPostedAmount = this.postedAmount
283
-
284
- if (this.normalBalance === 'debit') {
285
- if (entry.direction === 'debit') {
286
- newPostedAmount += entry.amount // Debit increases debit accounts
287
- } else {
288
- newPostedAmount -= entry.amount // Credit decreases debit accounts
289
- }
290
- } else {
291
- // credit normal balance
292
- if (entry.direction === 'credit') {
293
- newPostedAmount += entry.amount // Credit increases credit accounts
294
- } else {
295
- newPostedAmount -= entry.amount // Debit decreases credit accounts
296
- }
297
- }
298
-
299
- // Return new immutable instance
300
- return new LedgerAccountEntity({
301
- ...this,
302
- postedAmount: newPostedAmount,
303
- updated: new Date(),
304
- })
305
- }
306
-
307
- toRecord(): LedgerAccountInsert {
308
- return {
309
- id: this.id.toString(),
310
- name: this.name,
311
- normalBalance: this.normalBalance,
312
- postedAmount: this.postedAmount,
313
- lockVersion: this.lockVersion,
314
- updated: this.updated,
315
- }
316
- }
317
-
318
- toResponse(): LedgerAccountResponse {
319
- return {
320
- id: this.id.toString(),
321
- name: this.name,
322
- normalBalance: this.normalBalance,
323
- postedAmount: this.postedAmount,
324
- updated: this.updated.toISOString(),
325
- }
326
- }
327
- }
328
- ```
329
-
330
- ## Entity with Defaults
331
-
332
- Handle default values consistently:
333
-
334
- ```typescript
335
- export class LedgerEntity {
336
- public readonly id: LedgerID
337
- public readonly organizationId: OrgID
338
- public readonly name: string
339
- public readonly currency: string
340
- public readonly currencyExponent: number
341
- public readonly metadata?: Record<string, unknown>
342
-
343
- private constructor(data: LedgerEntityData) {
344
- Object.assign(this, data)
345
- }
346
-
347
- static fromRequest(
348
- rq: LedgerRequest,
349
- organizationId: OrgID,
350
- id?: string
351
- ): LedgerEntity {
352
- return new LedgerEntity({
353
- id: id ? TypeID.fromString<'lgr'>(id) : new TypeID('lgr'),
354
- organizationId,
355
- name: rq.name,
356
- currency: rq.currency ?? 'USD', // Apply default
357
- currencyExponent: rq.currencyExponent ?? 2, // Apply default
358
- metadata: rq.metadata,
359
- })
360
- }
361
-
362
- static fromRecord(record: LedgerRecord): LedgerEntity {
363
- let metadata: Record<string, unknown> | undefined
364
- if (record.metadata) {
365
- metadata = JSON.parse(record.metadata)
366
- }
367
-
368
- return new LedgerEntity({
369
- id: TypeID.fromString<'lgr'>(record.id),
370
- organizationId: TypeID.fromString<'org'>(record.organizationId),
371
- name: record.name,
372
- currency: record.currency,
373
- currencyExponent: record.currencyExponent,
374
- metadata,
375
- })
376
- }
377
-
378
- toRecord(): LedgerInsert {
379
- return {
380
- id: this.id.toString(),
381
- organizationId: this.organizationId.toString(),
382
- name: this.name,
383
- currency: this.currency,
384
- currencyExponent: this.currencyExponent,
385
- metadata: this.metadata ? JSON.stringify(this.metadata) : undefined,
386
- }
387
- }
388
-
389
- toResponse(): LedgerResponse {
390
- return {
391
- id: this.id.toString(),
392
- name: this.name,
393
- currency: this.currency,
394
- currencyExponent: this.currencyExponent,
395
- metadata: this.metadata,
396
- }
397
- }
398
- }
399
- ```
400
-
401
- ## Guidelines
402
-
403
- 1. **Use immutable readonly properties** - Prevents accidental mutation
404
- 2. **Private constructor** - Forces use of factory methods (fromRequest, fromRecord)
405
- 3. **Four transformation methods** - Clear contracts for each layer boundary
406
- 4. **Business logic in entities** - Domain rules belong in entities, not repos or services
407
- 5. **Return new instances** - When applying changes, return new entity (immutability)
408
- 6. **Parse JSON in fromRecord** - Handle TEXT → object deserialization
409
- 7. **Stringify JSON in toRecord** - Handle object → TEXT serialization
410
- 8. **Format dates in toResponse** - Convert Date → ISO string for API
411
- 9. **Apply defaults in fromRequest** - Ensure defaults are set when creating from API
412
- 10. **Use TypeID for type safety** - Prevents ID mixups across entity types
@@ -1,191 +0,0 @@
1
- # PostgreSQL Patterns with Drizzle ORM
2
-
3
- PostgreSQL-specific patterns, connection setup, and error handling.
4
-
5
- ## Schema Definition
6
-
7
- ```typescript
8
- import {
9
- pgTable,
10
- serial,
11
- text,
12
- integer,
13
- timestamp,
14
- boolean,
15
- varchar,
16
- uuid,
17
- primaryKey,
18
- unique,
19
- index
20
- } from 'drizzle-orm/pg-core'
21
-
22
- export const users = pgTable('users', {
23
- id: serial('id').primaryKey(),
24
- name: text('name').notNull(),
25
- email: varchar('email', { length: 255 }).notNull().unique(),
26
- age: integer('age'),
27
- isActive: boolean('is_active').default(true),
28
- createdAt: timestamp('created_at').defaultNow().notNull(),
29
- updatedAt: timestamp('updated_at').$onUpdate(() => new Date()),
30
- })
31
-
32
- export const posts = pgTable('posts', {
33
- id: serial('id').primaryKey(),
34
- title: text('title').notNull(),
35
- content: text('content'),
36
- authorId: integer('author_id')
37
- .notNull()
38
- .references(() => users.id, { onDelete: 'cascade' }),
39
- createdAt: timestamp('created_at').defaultNow().notNull(),
40
- })
41
- ```
42
-
43
- ## Database Connection
44
-
45
- ```typescript
46
- import { drizzle } from 'drizzle-orm/node-postgres'
47
- import { Pool } from 'pg'
48
- import * as schema from './schema'
49
-
50
- const pool = new Pool({ connectionString: process.env.DATABASE_URL })
51
- export const db = drizzle(pool, { schema })
52
- ```
53
-
54
- ## Migrations (drizzle-kit)
55
-
56
- ```typescript
57
- // drizzle.config.ts
58
- import { defineConfig } from 'drizzle-kit'
59
-
60
- export default defineConfig({
61
- schema: './src/db/schema.ts',
62
- out: './drizzle',
63
- dialect: 'postgresql',
64
- dbCredentials: {
65
- url: process.env.DATABASE_URL!,
66
- },
67
- })
68
- ```
69
-
70
- ```bash
71
- # Generate migration
72
- npx drizzle-kit generate
73
-
74
- # Apply migrations
75
- npx drizzle-kit migrate
76
-
77
- # Open Drizzle Studio
78
- npx drizzle-kit studio
79
-
80
- # Pull schema from existing DB
81
- npx drizzle-kit pull
82
- ```
83
-
84
- ## Column Helpers
85
-
86
- ```typescript
87
- // UUID with auto-generation
88
- id: uuid('id').defaultRandom().primaryKey()
89
-
90
- // Timestamps
91
- createdAt: timestamp('created_at').defaultNow().notNull()
92
- updatedAt: timestamp('updated_at').$onUpdate(() => new Date())
93
-
94
- // Enum
95
- import { pgEnum } from 'drizzle-orm/pg-core'
96
- export const statusEnum = pgEnum('status', ['pending', 'active', 'archived'])
97
- // usage: status: statusEnum('status').default('pending')
98
-
99
- // JSON
100
- metadata: jsonb('metadata').$type<{ key: string }>()
101
- ```
102
-
103
- ## Composite Keys & Indexes
104
-
105
- ```typescript
106
- export const postTags = pgTable('post_tags', {
107
- postId: integer('post_id').references(() => posts.id),
108
- tagId: integer('tag_id').references(() => tags.id),
109
- }, (t) => [
110
- primaryKey({ columns: [t.postId, t.tagId] }),
111
- ])
112
-
113
- export const users = pgTable('users', {
114
- // columns...
115
- }, (t) => [
116
- unique('unique_email').on(t.email),
117
- index('name_idx').on(t.name),
118
- ])
119
- ```
120
-
121
- ## PostgreSQL Error Codes
122
-
123
- Map database error codes to domain errors:
124
-
125
- ```typescript
126
- type ErrorContext = {
127
- userId?: string
128
- resourceId?: string
129
- [key: string]: unknown
130
- }
131
-
132
- function handleDBError(error: unknown, context: ErrorContext = {}): never {
133
- const code = (error as { code?: string }).code
134
-
135
- switch (code) {
136
- case '23505': // unique_violation
137
- throw new ConflictError('Resource already exists', context)
138
- case '23503': // foreign_key_violation
139
- throw new NotFoundError('Referenced resource not found', context)
140
- case '40001': // serialization_failure
141
- throw new ServiceUnavailableError('Transaction conflict - please retry', {
142
- retryable: true,
143
- ...context,
144
- })
145
- case 'OC000': // AWS DSQL occ_conflict
146
- throw new ServiceUnavailableError('Optimistic concurrency conflict', {
147
- retryable: true,
148
- ...context,
149
- })
150
- default:
151
- throw error
152
- }
153
- }
154
- ```
155
-
156
- ## Optimistic Locking
157
-
158
- Prevent concurrent modification issues with version-based locking:
159
-
160
- ```typescript
161
- // Add lockVersion column to schema
162
- export const users = pgTable('users', {
163
- id: uuid('id').defaultRandom().primaryKey(),
164
- name: text('name').notNull(),
165
- lockVersion: integer('lock_version').default(0).notNull(),
166
- updatedAt: timestamp('updated_at').$onUpdate(() => new Date()),
167
- })
168
-
169
- // Update with version check
170
- async update(entity: UserEntity): Promise<UserEntity> {
171
- const result = await this.db
172
- .update(users)
173
- .set({
174
- ...entity.toRecord(),
175
- lockVersion: sql`${users.lockVersion} + 1`,
176
- })
177
- .where(and(
178
- eq(users.id, entity.id),
179
- eq(users.lockVersion, entity.lockVersion)
180
- ))
181
- .returning()
182
-
183
- if (result.length === 0) {
184
- throw new ConflictError({
185
- message: 'Resource was modified by another transaction',
186
- retryable: true,
187
- })
188
- }
189
- return UserEntity.fromRecord(result[0])
190
- }
191
- ```