autoworkflow 3.1.5 → 3.5.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 (123) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +26 -0
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/pre-edit.sh +129 -0
  12. package/.claude/hooks/session-check.sh +79 -0
  13. package/.claude/settings.json +40 -6
  14. package/.claude/settings.local.json +3 -1
  15. package/.claude/skills/actix.md +337 -0
  16. package/.claude/skills/alembic.md +504 -0
  17. package/.claude/skills/angular.md +237 -0
  18. package/.claude/skills/api-design.md +187 -0
  19. package/.claude/skills/aspnet-core.md +377 -0
  20. package/.claude/skills/astro.md +245 -0
  21. package/.claude/skills/auth-clerk.md +327 -0
  22. package/.claude/skills/auth-firebase.md +367 -0
  23. package/.claude/skills/auth-nextauth.md +359 -0
  24. package/.claude/skills/auth-supabase.md +368 -0
  25. package/.claude/skills/axum.md +386 -0
  26. package/.claude/skills/blazor.md +456 -0
  27. package/.claude/skills/chi.md +348 -0
  28. package/.claude/skills/code-review.md +133 -0
  29. package/.claude/skills/csharp.md +296 -0
  30. package/.claude/skills/css-modules.md +325 -0
  31. package/.claude/skills/cypress.md +343 -0
  32. package/.claude/skills/debugging.md +133 -0
  33. package/.claude/skills/diesel.md +392 -0
  34. package/.claude/skills/django.md +301 -0
  35. package/.claude/skills/docker.md +319 -0
  36. package/.claude/skills/doctrine.md +473 -0
  37. package/.claude/skills/documentation.md +182 -0
  38. package/.claude/skills/dotnet.md +409 -0
  39. package/.claude/skills/drizzle.md +293 -0
  40. package/.claude/skills/echo.md +321 -0
  41. package/.claude/skills/eloquent.md +256 -0
  42. package/.claude/skills/emotion.md +426 -0
  43. package/.claude/skills/entity-framework.md +370 -0
  44. package/.claude/skills/express.md +316 -0
  45. package/.claude/skills/fastapi.md +329 -0
  46. package/.claude/skills/fastify.md +299 -0
  47. package/.claude/skills/fiber.md +315 -0
  48. package/.claude/skills/flask.md +322 -0
  49. package/.claude/skills/gin.md +342 -0
  50. package/.claude/skills/git.md +116 -0
  51. package/.claude/skills/github-actions.md +353 -0
  52. package/.claude/skills/go.md +377 -0
  53. package/.claude/skills/gorm.md +409 -0
  54. package/.claude/skills/graphql.md +478 -0
  55. package/.claude/skills/hibernate.md +379 -0
  56. package/.claude/skills/hono.md +306 -0
  57. package/.claude/skills/java.md +400 -0
  58. package/.claude/skills/jest.md +313 -0
  59. package/.claude/skills/jpa.md +282 -0
  60. package/.claude/skills/kotlin.md +347 -0
  61. package/.claude/skills/kubernetes.md +363 -0
  62. package/.claude/skills/laravel.md +414 -0
  63. package/.claude/skills/mcp-browser.md +320 -0
  64. package/.claude/skills/mcp-database.md +219 -0
  65. package/.claude/skills/mcp-fetch.md +241 -0
  66. package/.claude/skills/mcp-filesystem.md +204 -0
  67. package/.claude/skills/mcp-github.md +217 -0
  68. package/.claude/skills/mcp-memory.md +240 -0
  69. package/.claude/skills/mcp-search.md +218 -0
  70. package/.claude/skills/mcp-slack.md +262 -0
  71. package/.claude/skills/micronaut.md +388 -0
  72. package/.claude/skills/mongodb.md +319 -0
  73. package/.claude/skills/mongoose.md +355 -0
  74. package/.claude/skills/mysql.md +281 -0
  75. package/.claude/skills/nestjs.md +335 -0
  76. package/.claude/skills/nextjs-app-router.md +260 -0
  77. package/.claude/skills/nextjs-pages.md +172 -0
  78. package/.claude/skills/nuxt.md +202 -0
  79. package/.claude/skills/openapi.md +489 -0
  80. package/.claude/skills/performance.md +199 -0
  81. package/.claude/skills/php.md +398 -0
  82. package/.claude/skills/playwright.md +371 -0
  83. package/.claude/skills/postgresql.md +257 -0
  84. package/.claude/skills/prisma.md +293 -0
  85. package/.claude/skills/pydantic.md +304 -0
  86. package/.claude/skills/pytest.md +313 -0
  87. package/.claude/skills/python.md +272 -0
  88. package/.claude/skills/quarkus.md +377 -0
  89. package/.claude/skills/react.md +230 -0
  90. package/.claude/skills/redis.md +391 -0
  91. package/.claude/skills/refactoring.md +143 -0
  92. package/.claude/skills/remix.md +246 -0
  93. package/.claude/skills/rest-api.md +490 -0
  94. package/.claude/skills/rocket.md +366 -0
  95. package/.claude/skills/rust.md +341 -0
  96. package/.claude/skills/sass.md +380 -0
  97. package/.claude/skills/sea-orm.md +382 -0
  98. package/.claude/skills/security.md +167 -0
  99. package/.claude/skills/sequelize.md +395 -0
  100. package/.claude/skills/spring-boot.md +416 -0
  101. package/.claude/skills/sqlalchemy.md +269 -0
  102. package/.claude/skills/sqlx-rust.md +408 -0
  103. package/.claude/skills/state-jotai.md +346 -0
  104. package/.claude/skills/state-mobx.md +353 -0
  105. package/.claude/skills/state-pinia.md +431 -0
  106. package/.claude/skills/state-redux.md +337 -0
  107. package/.claude/skills/state-tanstack-query.md +434 -0
  108. package/.claude/skills/state-zustand.md +340 -0
  109. package/.claude/skills/styled-components.md +403 -0
  110. package/.claude/skills/svelte.md +238 -0
  111. package/.claude/skills/sveltekit.md +207 -0
  112. package/.claude/skills/symfony.md +437 -0
  113. package/.claude/skills/tailwind.md +279 -0
  114. package/.claude/skills/terraform.md +394 -0
  115. package/.claude/skills/testing-library.md +371 -0
  116. package/.claude/skills/trpc.md +426 -0
  117. package/.claude/skills/typeorm.md +368 -0
  118. package/.claude/skills/vitest.md +330 -0
  119. package/.claude/skills/vue.md +202 -0
  120. package/.claude/skills/warp.md +365 -0
  121. package/README.md +135 -52
  122. package/package.json +1 -1
  123. package/system/triggers.md +152 -11
@@ -0,0 +1,473 @@
1
+ # Doctrine ORM Skill
2
+
3
+ ## Entity Definition
4
+ \`\`\`php
5
+ <?php
6
+
7
+ namespace App\\Entity;
8
+
9
+ use App\\Repository\\UserRepository;
10
+ use Doctrine\\Common\\Collections\\ArrayCollection;
11
+ use Doctrine\\Common\\Collections\\Collection;
12
+ use Doctrine\\DBAL\\Types\\Types;
13
+ use Doctrine\\ORM\\Mapping as ORM;
14
+ use Symfony\\Component\\Serializer\\Attribute\\Groups;
15
+
16
+ #[ORM\\Entity(repositoryClass: UserRepository::class)]
17
+ #[ORM\\Table(name: 'users')]
18
+ #[ORM\\Index(columns: ['email'], name: 'idx_users_email')]
19
+ #[ORM\\HasLifecycleCallbacks]
20
+ class User
21
+ {
22
+ #[ORM\\Id]
23
+ #[ORM\\GeneratedValue(strategy: 'CUSTOM')]
24
+ #[ORM\\CustomIdGenerator(class: UuidGenerator::class)]
25
+ #[ORM\\Column(type: Types::GUID)]
26
+ #[Groups(['user:list', 'user:read'])]
27
+ private string $id;
28
+
29
+ #[ORM\\Column(type: Types::STRING, length: 255, unique: true)]
30
+ #[Groups(['user:list', 'user:read'])]
31
+ private string $email;
32
+
33
+ #[ORM\\Column(type: Types::STRING, length: 100)]
34
+ #[Groups(['user:list', 'user:read'])]
35
+ private string $name;
36
+
37
+ #[ORM\\Column(type: Types::STRING)]
38
+ private string $password;
39
+
40
+ #[ORM\\Column(type: Types::BOOLEAN)]
41
+ #[Groups(['user:read'])]
42
+ private bool $isActive = true;
43
+
44
+ #[ORM\\Column(type: Types::DATETIME_IMMUTABLE)]
45
+ #[Groups(['user:read'])]
46
+ private \\DateTimeImmutable $createdAt;
47
+
48
+ #[ORM\\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
49
+ private ?\\DateTimeImmutable $updatedAt = null;
50
+
51
+ // Relationships
52
+ #[ORM\\OneToOne(targetEntity: Profile::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
53
+ #[Groups(['user:read'])]
54
+ private ?Profile $profile = null;
55
+
56
+ #[ORM\\OneToMany(targetEntity: Post::class, mappedBy: 'author', cascade: ['persist'], orphanRemoval: true)]
57
+ #[ORM\\OrderBy(['createdAt' => 'DESC'])]
58
+ private Collection $posts;
59
+
60
+ #[ORM\\ManyToMany(targetEntity: Role::class, inversedBy: 'users')]
61
+ #[ORM\\JoinTable(name: 'user_roles')]
62
+ private Collection $roles;
63
+
64
+ public function __construct()
65
+ {
66
+ $this->posts = new ArrayCollection();
67
+ $this->roles = new ArrayCollection();
68
+ }
69
+
70
+ #[ORM\\PrePersist]
71
+ public function setCreatedAtValue(): void
72
+ {
73
+ $this->createdAt = new \\DateTimeImmutable();
74
+ }
75
+
76
+ #[ORM\\PreUpdate]
77
+ public function setUpdatedAtValue(): void
78
+ {
79
+ $this->updatedAt = new \\DateTimeImmutable();
80
+ }
81
+
82
+ // Relationship helpers
83
+ public function addPost(Post $post): self
84
+ {
85
+ if (!$this->posts->contains($post)) {
86
+ $this->posts->add($post);
87
+ $post->setAuthor($this);
88
+ }
89
+ return $this;
90
+ }
91
+
92
+ public function removePost(Post $post): self
93
+ {
94
+ if ($this->posts->removeElement($post)) {
95
+ if ($post->getAuthor() === $this) {
96
+ $post->setAuthor(null);
97
+ }
98
+ }
99
+ return $this;
100
+ }
101
+
102
+ public function addRole(Role $role): self
103
+ {
104
+ if (!$this->roles->contains($role)) {
105
+ $this->roles->add($role);
106
+ }
107
+ return $this;
108
+ }
109
+
110
+ // Getters and setters...
111
+ public function getId(): string { return $this->id; }
112
+ public function getEmail(): string { return $this->email; }
113
+ public function setEmail(string $email): self { $this->email = $email; return $this; }
114
+ // ... etc
115
+ }
116
+ \`\`\`
117
+
118
+ ## Repository with Query Builder
119
+ \`\`\`php
120
+ <?php
121
+
122
+ namespace App\\Repository;
123
+
124
+ use App\\Entity\\User;
125
+ use Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository;
126
+ use Doctrine\\ORM\\QueryBuilder;
127
+ use Doctrine\\Persistence\\ManagerRegistry;
128
+
129
+ /**
130
+ * @extends ServiceEntityRepository<User>
131
+ */
132
+ final class UserRepository extends ServiceEntityRepository
133
+ {
134
+ public function __construct(ManagerRegistry $registry)
135
+ {
136
+ parent::__construct($registry, User::class);
137
+ }
138
+
139
+ public function findByEmail(string $email): ?User
140
+ {
141
+ return $this->findOneBy(['email' => $email]);
142
+ }
143
+
144
+ /**
145
+ * @return User[]
146
+ */
147
+ public function findActiveWithPosts(): array
148
+ {
149
+ return $this->createQueryBuilder('u')
150
+ ->leftJoin('u.posts', 'p')
151
+ ->addSelect('p')
152
+ ->where('u.isActive = :active')
153
+ ->setParameter('active', true)
154
+ ->orderBy('u.createdAt', 'DESC')
155
+ ->getQuery()
156
+ ->getResult();
157
+ }
158
+
159
+ /**
160
+ * @return User[]
161
+ */
162
+ public function findByRole(string $roleName): array
163
+ {
164
+ return $this->createQueryBuilder('u')
165
+ ->innerJoin('u.roles', 'r')
166
+ ->where('r.name = :role')
167
+ ->setParameter('role', $roleName)
168
+ ->getQuery()
169
+ ->getResult();
170
+ }
171
+
172
+ public function countByStatus(bool $isActive): int
173
+ {
174
+ return $this->createQueryBuilder('u')
175
+ ->select('COUNT(u.id)')
176
+ ->where('u.isActive = :active')
177
+ ->setParameter('active', $isActive)
178
+ ->getQuery()
179
+ ->getSingleScalarResult();
180
+ }
181
+
182
+ // Paginated query
183
+ public function createPaginatedQuery(): QueryBuilder
184
+ {
185
+ return $this->createQueryBuilder('u')
186
+ ->where('u.isActive = :active')
187
+ ->setParameter('active', true)
188
+ ->orderBy('u.createdAt', 'DESC');
189
+ }
190
+
191
+ // Search with multiple conditions
192
+ public function search(UserSearchCriteria $criteria): array
193
+ {
194
+ $qb = $this->createQueryBuilder('u');
195
+
196
+ if ($criteria->email !== null) {
197
+ $qb->andWhere('u.email LIKE :email')
198
+ ->setParameter('email', '%' . $criteria->email . '%');
199
+ }
200
+
201
+ if ($criteria->name !== null) {
202
+ $qb->andWhere('u.name LIKE :name')
203
+ ->setParameter('name', '%' . $criteria->name . '%');
204
+ }
205
+
206
+ if ($criteria->isActive !== null) {
207
+ $qb->andWhere('u.isActive = :active')
208
+ ->setParameter('active', $criteria->isActive);
209
+ }
210
+
211
+ if ($criteria->createdAfter !== null) {
212
+ $qb->andWhere('u.createdAt > :after')
213
+ ->setParameter('after', $criteria->createdAfter);
214
+ }
215
+
216
+ return $qb->setMaxResults($criteria->limit)
217
+ ->setFirstResult($criteria->offset)
218
+ ->getQuery()
219
+ ->getResult();
220
+ }
221
+ }
222
+ \`\`\`
223
+
224
+ ## DQL (Doctrine Query Language)
225
+ \`\`\`php
226
+ <?php
227
+
228
+ // Named queries in entity
229
+ #[ORM\\Entity]
230
+ #[ORM\\NamedQuery(
231
+ name: 'User.findActiveByRole',
232
+ query: 'SELECT u FROM App\\Entity\\User u JOIN u.roles r WHERE u.isActive = true AND r.name = :role'
233
+ )]
234
+ class User { }
235
+
236
+ // Usage
237
+ $users = $this->em
238
+ ->createNamedQuery('User.findActiveByRole')
239
+ ->setParameter('role', 'ADMIN')
240
+ ->getResult();
241
+
242
+ // Direct DQL
243
+ $users = $this->em->createQuery(
244
+ 'SELECT u, p FROM App\\Entity\\User u
245
+ LEFT JOIN u.posts p
246
+ WHERE u.isActive = :active
247
+ ORDER BY u.createdAt DESC'
248
+ )
249
+ ->setParameter('active', true)
250
+ ->getResult();
251
+
252
+ // Aggregate queries
253
+ $stats = $this->em->createQuery(
254
+ 'SELECT r.name, COUNT(u.id) as userCount
255
+ FROM App\\Entity\\User u
256
+ JOIN u.roles r
257
+ WHERE u.isActive = :active
258
+ GROUP BY r.name'
259
+ )
260
+ ->setParameter('active', true)
261
+ ->getResult();
262
+ \`\`\`
263
+
264
+ ## Transactions
265
+ \`\`\`php
266
+ <?php
267
+
268
+ namespace App\\Service;
269
+
270
+ use Doctrine\\ORM\\EntityManagerInterface;
271
+
272
+ final readonly class UserService
273
+ {
274
+ public function __construct(
275
+ private EntityManagerInterface $em,
276
+ ) {}
277
+
278
+ public function createWithProfile(CreateUserData $data): User
279
+ {
280
+ return $this->em->wrapInTransaction(function () use ($data) {
281
+ $user = new User();
282
+ $user->setEmail($data->email);
283
+ $user->setName($data->name);
284
+ $this->em->persist($user);
285
+
286
+ $profile = new Profile();
287
+ $profile->setUser($user);
288
+ $profile->setBio($data->bio);
289
+ $this->em->persist($profile);
290
+
291
+ return $user;
292
+ });
293
+ }
294
+
295
+ // Manual transaction control
296
+ public function complexOperation(): void
297
+ {
298
+ $this->em->beginTransaction();
299
+
300
+ try {
301
+ // Multiple operations...
302
+ $this->em->flush();
303
+ $this->em->commit();
304
+ } catch (\\Exception $e) {
305
+ $this->em->rollback();
306
+ throw $e;
307
+ }
308
+ }
309
+ }
310
+ \`\`\`
311
+
312
+ ## Migrations
313
+ \`\`\`bash
314
+ # Create migration
315
+ php bin/console make:migration
316
+
317
+ # Run migrations
318
+ php bin/console doctrine:migrations:migrate
319
+
320
+ # Rollback last migration
321
+ php bin/console doctrine:migrations:migrate prev
322
+
323
+ # Generate migration from entity changes
324
+ php bin/console doctrine:migrations:diff
325
+ \`\`\`
326
+
327
+ \`\`\`php
328
+ <?php
329
+ // migrations/Version20240115000000.php
330
+
331
+ declare(strict_types=1);
332
+
333
+ namespace DoctrineMigrations;
334
+
335
+ use Doctrine\\DBAL\\Schema\\Schema;
336
+ use Doctrine\\Migrations\\AbstractMigration;
337
+
338
+ final class Version20240115000000 extends AbstractMigration
339
+ {
340
+ public function up(Schema $schema): void
341
+ {
342
+ $this->addSql('CREATE TABLE users (
343
+ id UUID NOT NULL,
344
+ email VARCHAR(255) NOT NULL,
345
+ name VARCHAR(100) NOT NULL,
346
+ password VARCHAR(255) NOT NULL,
347
+ is_active BOOLEAN DEFAULT true NOT NULL,
348
+ created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
349
+ updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
350
+ PRIMARY KEY(id)
351
+ )');
352
+ $this->addSql('CREATE UNIQUE INDEX idx_users_email ON users (email)');
353
+ }
354
+
355
+ public function down(Schema $schema): void
356
+ {
357
+ $this->addSql('DROP TABLE users');
358
+ }
359
+ }
360
+ \`\`\`
361
+
362
+ ## Lifecycle Callbacks and Events
363
+ \`\`\`php
364
+ <?php
365
+
366
+ // In entity
367
+ #[ORM\\HasLifecycleCallbacks]
368
+ class User
369
+ {
370
+ #[ORM\\PrePersist]
371
+ public function onPrePersist(): void
372
+ {
373
+ $this->createdAt = new \\DateTimeImmutable();
374
+ }
375
+
376
+ #[ORM\\PreUpdate]
377
+ public function onPreUpdate(): void
378
+ {
379
+ $this->updatedAt = new \\DateTimeImmutable();
380
+ }
381
+
382
+ #[ORM\\PostPersist]
383
+ public function onPostPersist(): void
384
+ {
385
+ // After insert
386
+ }
387
+ }
388
+
389
+ // Event subscriber for complex logic
390
+ namespace App\\EventSubscriber;
391
+
392
+ use App\\Entity\\User;
393
+ use Doctrine\\Bundle\\DoctrineBundle\\Attribute\\AsDoctrineListener;
394
+ use Doctrine\\ORM\\Event\\PrePersistEventArgs;
395
+ use Doctrine\\ORM\\Events;
396
+
397
+ #[AsDoctrineListener(event: Events::prePersist)]
398
+ final readonly class UserSubscriber
399
+ {
400
+ public function __construct(
401
+ private PasswordHasherInterface $hasher,
402
+ ) {}
403
+
404
+ public function prePersist(PrePersistEventArgs $args): void
405
+ {
406
+ $entity = $args->getObject();
407
+
408
+ if (!$entity instanceof User) {
409
+ return;
410
+ }
411
+
412
+ // Hash password before insert
413
+ if ($entity->getPlainPassword() !== null) {
414
+ $entity->setPassword(
415
+ $this->hasher->hashPassword($entity, $entity->getPlainPassword())
416
+ );
417
+ $entity->eraseCredentials();
418
+ }
419
+ }
420
+ }
421
+ \`\`\`
422
+
423
+ ## Performance Optimization
424
+ \`\`\`php
425
+ <?php
426
+
427
+ // Eager loading to avoid N+1
428
+ $users = $this->createQueryBuilder('u')
429
+ ->leftJoin('u.posts', 'p')
430
+ ->addSelect('p') // Must addSelect for eager loading
431
+ ->getQuery()
432
+ ->getResult();
433
+
434
+ // Partial loading (only specific fields)
435
+ $users = $this->createQueryBuilder('u')
436
+ ->select('partial u.{id, email, name}')
437
+ ->getQuery()
438
+ ->getResult();
439
+
440
+ // DTO projection (best performance)
441
+ $users = $this->createQueryBuilder('u')
442
+ ->select('NEW App\\DTO\\UserDTO(u.id, u.email, u.name)')
443
+ ->getQuery()
444
+ ->getResult();
445
+
446
+ // Batch processing
447
+ $batchSize = 100;
448
+ $i = 0;
449
+ foreach ($users as $user) {
450
+ $user->setIsActive(false);
451
+
452
+ if (++$i % $batchSize === 0) {
453
+ $this->em->flush();
454
+ $this->em->clear(); // Detach all entities
455
+ }
456
+ }
457
+ $this->em->flush();
458
+ \`\`\`
459
+
460
+ ## ✅ DO
461
+ - Use typed properties and return types
462
+ - Use \`#[ORM\\HasLifecycleCallbacks]\` for entity hooks
463
+ - Use QueryBuilder for complex queries
464
+ - Use \`wrapInTransaction\` for multi-entity operations
465
+ - Use \`addSelect\` with joins to avoid N+1
466
+ - Use DTOs for read-only queries
467
+
468
+ ## ❌ DON'T
469
+ - Don't forget \`addSelect\` when joining (causes N+1)
470
+ - Don't use \`$em->find()\` in loops (use batch queries)
471
+ - Don't forget \`$em->flush()\` after changes
472
+ - Don't use \`EAGER\` fetch mode (query explicitly)
473
+ - Don't put heavy logic in lifecycle callbacks
@@ -0,0 +1,182 @@
1
+ # Documentation Skill
2
+
3
+ ## README Structure
4
+ \`\`\`markdown
5
+ # Project Name
6
+
7
+ Brief description of what it does.
8
+
9
+ ## Quick Start
10
+ \\\`\\\`\\\`bash
11
+ npm install && npm run dev
12
+ \\\`\\\`\\\`
13
+
14
+ ## Features
15
+ - Feature 1
16
+ - Feature 2
17
+
18
+ ## Configuration
19
+ | Variable | Description | Default |
20
+ |----------|-------------|---------|
21
+ | PORT | Server port | 3000 |
22
+
23
+ ## Architecture
24
+ See [Architecture Decision Records](./docs/adr/)
25
+
26
+ ## API Reference
27
+ See [API.md](./docs/API.md)
28
+
29
+ ## Contributing
30
+ See [CONTRIBUTING.md](./CONTRIBUTING.md)
31
+ \`\`\`
32
+
33
+ ## Architecture Decision Records (ADR)
34
+ \`\`\`markdown
35
+ # ADR-001: Use PostgreSQL for primary database
36
+
37
+ ## Status
38
+ Accepted
39
+
40
+ ## Context
41
+ We need a database that supports complex queries, transactions,
42
+ and can scale to millions of records.
43
+
44
+ ## Decision
45
+ Use PostgreSQL with Prisma ORM.
46
+
47
+ ## Consequences
48
+ ### Positive
49
+ - Strong ACID compliance
50
+ - Excellent query performance
51
+ - Rich ecosystem
52
+
53
+ ### Negative
54
+ - More complex than SQLite for development
55
+ - Requires managed service for production
56
+ \`\`\`
57
+
58
+ ## Changelog (Keep a Changelog format)
59
+ \`\`\`markdown
60
+ # Changelog
61
+
62
+ ## [Unreleased]
63
+ ### Added
64
+ - User authentication with OAuth
65
+
66
+ ## [1.2.0] - 2024-01-15
67
+ ### Added
68
+ - Dark mode support
69
+
70
+ ### Fixed
71
+ - Memory leak in dashboard component
72
+
73
+ ### Changed
74
+ - Upgraded to React 18
75
+ \`\`\`
76
+
77
+ ## Code Documentation
78
+ \`\`\`typescript
79
+ /**
80
+ * Calculates the total price including tax and discounts.
81
+ *
82
+ * @param items - Array of cart items
83
+ * @param taxRate - Tax rate as decimal (e.g., 0.08 for 8%)
84
+ * @returns Total price in cents
85
+ * @throws {InvalidDiscountError} If discount code is invalid
86
+ *
87
+ * @example
88
+ * const total = calculateTotal(cartItems, 0.08);
89
+ * // Returns: 10800 (for $100 + 8% tax)
90
+ */
91
+ function calculateTotal(items: CartItem[], taxRate: number): number { }
92
+ \`\`\`
93
+
94
+ ## Inline Comments Best Practices
95
+ \`\`\`typescript
96
+ // ❌ BAD: Explains "what" (obvious from code)
97
+ // Loop through users
98
+ for (const user of users) { }
99
+
100
+ // ✅ GOOD: Explains "why" (not obvious)
101
+ // Skip inactive users to avoid sending emails to churned accounts
102
+ for (const user of users.filter(u => u.isActive)) { }
103
+
104
+ // ✅ GOOD: Explains business logic
105
+ // Discount capped at 50% per legal requirement (see LEGAL-123)
106
+ const finalDiscount = Math.min(discount, 0.5);
107
+
108
+ // ✅ GOOD: Warns about non-obvious behavior
109
+ // IMPORTANT: This must run before auth middleware initializes
110
+ app.use(corsMiddleware);
111
+ \`\`\`
112
+
113
+ ## Diagrams as Code (Mermaid)
114
+ \`\`\`markdown
115
+ \\\`\\\`\\\`mermaid
116
+ flowchart TD
117
+ A[User Request] --> B{Authenticated?}
118
+ B -->|Yes| C[Process Request]
119
+ B -->|No| D[Return 401]
120
+ C --> E[Return Response]
121
+ \\\`\\\`\\\`
122
+
123
+ \\\`\\\`\\\`mermaid
124
+ erDiagram
125
+ USER ||--o{ POST : creates
126
+ USER ||--o{ COMMENT : writes
127
+ POST ||--o{ COMMENT : has
128
+ \\\`\\\`\\\`
129
+
130
+ \\\`\\\`\\\`mermaid
131
+ sequenceDiagram
132
+ Client->>+API: POST /login
133
+ API->>+DB: Verify credentials
134
+ DB-->>-API: User data
135
+ API-->>-Client: JWT token
136
+ \\\`\\\`\\\`
137
+ \`\`\`
138
+
139
+ ## API Documentation (OpenAPI)
140
+ \`\`\`yaml
141
+ paths:
142
+ /users/{id}:
143
+ get:
144
+ summary: Get user by ID
145
+ description: Returns a single user. Requires authentication.
146
+ parameters:
147
+ - name: id
148
+ in: path
149
+ required: true
150
+ schema:
151
+ type: string
152
+ format: uuid
153
+ responses:
154
+ '200':
155
+ description: User found
156
+ content:
157
+ application/json:
158
+ schema:
159
+ $ref: '#/components/schemas/User'
160
+ example:
161
+ id: "123e4567-e89b-12d3-a456-426614174000"
162
+ email: "user@example.com"
163
+ name: "John Doe"
164
+ '404':
165
+ description: User not found
166
+ \`\`\`
167
+
168
+ ## ❌ DON'T
169
+ - Document obvious code
170
+ - Let docs become stale
171
+ - Write docs with no examples
172
+ - Use outdated screenshots
173
+ - Write walls of text
174
+
175
+ ## ✅ DO
176
+ - Document the "why", not the "what"
177
+ - Include runnable examples
178
+ - Keep docs near the code
179
+ - Update docs with code changes
180
+ - Use diagrams for complex flows
181
+ - Write ADRs for architectural decisions
182
+ - Keep a changelog for releases