engsys 1.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 (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/core/agents/aaron.md +152 -0
  4. package/core/agents/bert.md +115 -0
  5. package/core/agents/isabelle.md +136 -0
  6. package/core/agents/jody.md +150 -0
  7. package/core/agents/leith.md +111 -0
  8. package/core/agents/marcelo.md +282 -0
  9. package/core/agents/melvin.md +101 -0
  10. package/core/agents/nyx.md +152 -0
  11. package/core/agents/otto.md +168 -0
  12. package/core/agents/patricia.md +283 -0
  13. package/core/commands/design-audit-local.md +155 -0
  14. package/core/commands/design-audit.md +235 -0
  15. package/core/commands/design-critique.md +96 -0
  16. package/core/commands/file-issue.md +22 -0
  17. package/core/commands/generate-project.md +45 -0
  18. package/core/commands/implement-issue.md +37 -0
  19. package/core/commands/implement-project.md +40 -0
  20. package/core/commands/naturalize.md +61 -0
  21. package/core/commands/pre-push.md +29 -0
  22. package/core/commands/prep-review-collect.md +130 -0
  23. package/core/commands/prep-review-finalize.md +121 -0
  24. package/core/commands/prep-review-publish.md +113 -0
  25. package/core/commands/prep-review.md +65 -0
  26. package/core/commands/project-closeout.md +25 -0
  27. package/core/skills/agentic-eval/SKILL.md +195 -0
  28. package/core/skills/chrome-devtools/SKILL.md +97 -0
  29. package/core/skills/code-review/SKILL.md +26 -0
  30. package/core/skills/gh-cli/SKILL.md +2202 -0
  31. package/core/skills/git-commit/SKILL.md +124 -0
  32. package/core/skills/git-workflow-agents/SKILL.md +462 -0
  33. package/core/skills/git-workflow-agents/reference.md +220 -0
  34. package/core/skills/github-actions/SKILL.md +190 -0
  35. package/core/skills/github-issues/SKILL.md +154 -0
  36. package/core/skills/llm-structured-outputs/SKILL.md +323 -0
  37. package/core/skills/llm-structured-outputs/references/provider-details.md +392 -0
  38. package/core/skills/pre-push/SKILL.md +115 -0
  39. package/core/skills/refactor/SKILL.md +645 -0
  40. package/core/skills/web-design-reviewer/SKILL.md +371 -0
  41. package/core/skills/webapp-testing/SKILL.md +127 -0
  42. package/core/skills/webapp-testing/test-helper.js +56 -0
  43. package/core/templates/CLAUDE.md.tmpl +98 -0
  44. package/core/templates/adr-template.md +67 -0
  45. package/core/templates/gh-issue-templates/bug.md +39 -0
  46. package/core/templates/gh-issue-templates/content.md +42 -0
  47. package/core/templates/gh-issue-templates/enhancement.md +36 -0
  48. package/core/templates/gh-issue-templates/feature.md +39 -0
  49. package/core/templates/gh-issue-templates/infrastructure.md +41 -0
  50. package/core/templates/post-edit-reminders.sh.tmpl +19 -0
  51. package/core/templates/settings.json.tmpl +90 -0
  52. package/core/templates/settings.local.json.tmpl +3 -0
  53. package/core/workflows/agent-implementation-workflow.md +346 -0
  54. package/core/workflows/generate-project.md +258 -0
  55. package/core/workflows/implement-project-workflow.md +190 -0
  56. package/core/workflows/issue-tracking.md +89 -0
  57. package/core/workflows/project-closeout-ceremony.md +77 -0
  58. package/core/workflows/review-workflow.md +266 -0
  59. package/engsys.config.example.yaml +46 -0
  60. package/install +202 -0
  61. package/lessons-library/README.md +80 -0
  62. package/lessons-library/async-callbacks-verify-liveness.md +15 -0
  63. package/lessons-library/change-isnt-done-until-every-surface-updated.md +15 -0
  64. package/lessons-library/claim-then-act-for-irreversible-ops.md +16 -0
  65. package/lessons-library/co-commit-entangled-work.md +15 -0
  66. package/lessons-library/dependabot-triage-playbook.md +17 -0
  67. package/lessons-library/deploy-by-digest-and-verify-the-running-revision.md +15 -0
  68. package/lessons-library/enforce-your-guarantee-at-your-boundary.md +16 -0
  69. package/lessons-library/gate-changes-on-measurement-not-vibes.md +15 -0
  70. package/lessons-library/iac-first-no-console-changes.md +15 -0
  71. package/lessons-library/independent-objective-review-gate.md +15 -0
  72. package/lessons-library/keep-an-immutable-source-of-truth.md +15 -0
  73. package/lessons-library/long-agent-runs-checkpoint-not-poll.md +15 -0
  74. package/lessons-library/model-identity-with-stable-ids-and-provenance.md +15 -0
  75. package/lessons-library/operator-choices-are-first-class.md +15 -0
  76. package/lessons-library/prefer-tool-enforced-structured-output.md +15 -0
  77. package/lessons-library/prove-causation-before-acting.md +15 -0
  78. package/lessons-library/re-read-state-before-acting.md +14 -0
  79. package/lessons-library/read-layer-tolerates-unbackfilled-rows.md +15 -0
  80. package/lessons-library/shell-safety-pipefail-and-validate-before-teardown.md +14 -0
  81. package/lessons-library/shift-correctness-left-and-distrust-false-greens.md +15 -0
  82. package/lessons-library/stray-control-bytes-hide-changes.md +14 -0
  83. package/lessons-library/tests-can-assert-the-bug.md +15 -0
  84. package/lessons-library/verify-ground-truth-not-reports.md +15 -0
  85. package/lessons-library/worktrees-need-bootstrap-from-origin-main.md +15 -0
  86. package/lib/commands.js +356 -0
  87. package/lib/generate-team-avatars.mjs +251 -0
  88. package/lib/manifest.js +155 -0
  89. package/lib/render.js +135 -0
  90. package/lib/selftest.js +90 -0
  91. package/lib/util.js +89 -0
  92. package/lib/yaml.js +156 -0
  93. package/optional-agents/gary.md +86 -0
  94. package/optional-agents/jos.md +136 -0
  95. package/optional-agents/sandy.md +101 -0
  96. package/optional-agents/steve.md +161 -0
  97. package/package.json +43 -0
  98. package/stacks/cloud/aws/claude.fragment.md +17 -0
  99. package/stacks/cloud/aws/settings.fragment.json +39 -0
  100. package/stacks/cloud/aws/skills/aws-deployment-preflight/SKILL.md +165 -0
  101. package/stacks/cloud/aws/skills/cloud-architecture-aws/SKILL.md +265 -0
  102. package/stacks/cloud/azure/claude.fragment.md +17 -0
  103. package/stacks/cloud/azure/settings.fragment.json +45 -0
  104. package/stacks/cloud/azure/skills/azure-deployment-preflight/SKILL.md +175 -0
  105. package/stacks/cloud/azure/skills/cloud-architecture-azure/SKILL.md +211 -0
  106. package/stacks/cloud/cloudflare/claude.fragment.md +21 -0
  107. package/stacks/cloud/cloudflare/settings.fragment.json +31 -0
  108. package/stacks/cloud/cloudflare/skills/cloud-architecture-cloudflare/SKILL.md +294 -0
  109. package/stacks/cloud/cloudflare/skills/cloudflare-deployment-preflight/SKILL.md +175 -0
  110. package/stacks/cloud/gcp/claude.fragment.md +17 -0
  111. package/stacks/cloud/gcp/settings.fragment.json +40 -0
  112. package/stacks/cloud/gcp/skills/cloud-architecture-gcp/SKILL.md +208 -0
  113. package/stacks/cloud/gcp/skills/gcp-deployment-preflight/SKILL.md +137 -0
  114. package/stacks/db/mongo/skills/mongo-conventions/SKILL.md +96 -0
  115. package/stacks/db/prisma/claude.fragment.md +49 -0
  116. package/stacks/db/prisma/skills/docker-database-package-copy/SKILL.md +44 -0
  117. package/stacks/db/prisma/skills/prisma-conventions/SKILL.md +37 -0
  118. package/stacks/domain/mobile-growth/skills/apple-ads/SKILL.md +184 -0
  119. package/stacks/domain/mobile-growth/skills/apple-ads/references/benchmark-notes.md +47 -0
  120. package/stacks/domain/mobile-growth/skills/apple-ads/references/official-links.md +53 -0
  121. package/stacks/domain/mobile-growth/skills/google-play-growth/SKILL.md +197 -0
  122. package/stacks/domain/mobile-growth/skills/google-play-growth/references/benchmark-notes.md +47 -0
  123. package/stacks/domain/mobile-growth/skills/google-play-growth/references/official-links.md +45 -0
  124. package/stacks/iac/bicep/claude.fragment.md +14 -0
  125. package/stacks/iac/bicep/settings.fragment.json +20 -0
  126. package/stacks/iac/bicep/skills/iac-bicep/SKILL.md +113 -0
  127. package/stacks/iac/cdk/claude.fragment.md +14 -0
  128. package/stacks/iac/cdk/settings.fragment.json +23 -0
  129. package/stacks/iac/cdk/skills/iac-cdk/SKILL.md +104 -0
  130. package/stacks/iac/terraform/claude.fragment.md +13 -0
  131. package/stacks/iac/terraform/settings.fragment.json +25 -0
  132. package/stacks/iac/terraform/skills/iac-terraform/SKILL.md +93 -0
  133. package/stacks/iac/terraform/skills/terraform-conventions/SKILL.md +87 -0
  134. package/stacks/lang/kotlin/skills/android-testing/SKILL.md +263 -0
  135. package/stacks/lang/kotlin/skills/jetpack-compose/SKILL.md +264 -0
  136. package/stacks/lang/kotlin/skills/kotlin-coroutines/SKILL.md +329 -0
  137. package/stacks/lang/python/skills/python-conventions/SKILL.md +61 -0
  138. package/stacks/lang/shell/skills/shell-scripting/SKILL.md +110 -0
  139. package/stacks/lang/swift/skills/swift-concurrency/SKILL.md +423 -0
  140. package/stacks/lang/swift/skills/swift-concurrency/references/approachable-concurrency.md +80 -0
  141. package/stacks/lang/swift/skills/swift-concurrency/references/concurrency-patterns.md +233 -0
  142. package/stacks/lang/swift/skills/swift-concurrency/references/swiftui-concurrency.md +187 -0
  143. package/stacks/lang/swift/skills/swift-concurrency/references/synchronization-primitives.md +341 -0
  144. package/stacks/lang/swift/skills/swift-testing/SKILL.md +497 -0
  145. package/stacks/lang/swift/skills/swift-testing/references/testing-advanced.md +106 -0
  146. package/stacks/lang/swift/skills/swift-testing/references/testing-patterns.md +504 -0
  147. package/stacks/lang/swift/skills/swiftdata/SKILL.md +334 -0
  148. package/stacks/lang/swift/skills/swiftdata/references/core-data-coexistence.md +504 -0
  149. package/stacks/lang/swift/skills/swiftdata/references/swiftdata-advanced.md +975 -0
  150. package/stacks/lang/swift/skills/swiftdata/references/swiftdata-queries.md +675 -0
  151. package/stacks/lang/swift/skills/swiftui-patterns/SKILL.md +371 -0
  152. package/stacks/lang/swift/skills/swiftui-patterns/references/architecture-patterns.md +486 -0
  153. package/stacks/lang/swift/skills/swiftui-patterns/references/deprecated-migration.md +1097 -0
  154. package/stacks/lang/swift/skills/swiftui-patterns/references/design-polish.md +780 -0
  155. package/stacks/lang/swift/skills/swiftui-patterns/references/platform-and-sharing.md +696 -0
  156. package/stacks/lang/typescript/skills/typescript-conventions/SKILL.md +91 -0
  157. package/stacks/platform/android/claude.fragment.md +40 -0
  158. package/stacks/platform/android/hooks/pre-push-gradle.sh +70 -0
  159. package/stacks/platform/android/settings.fragment.json +13 -0
  160. package/stacks/platform/android/skills/android-build-conventions/SKILL.md +247 -0
  161. package/stacks/platform/ios/claude.fragment.md +24 -0
  162. package/stacks/platform/ios/hooks/pre-push-xcodebuild.sh +82 -0
  163. package/stacks/platform/ios/settings.fragment.json +21 -0
  164. package/stacks/platform/ios/skills/xcodebuildmcp-simulator-logs/SKILL.md +76 -0
  165. package/stacks/platform/web/skills/frontend-testing/SKILL.md +246 -0
  166. package/stacks/platform/web/skills/react-conventions/SKILL.md +261 -0
  167. package/stacks/platform/web/skills/web-platform-conventions/SKILL.md +55 -0
  168. package/stacks/tooling/issue-tracker-github/claude.fragment.md +10 -0
  169. package/stacks/tooling/issue-tracker-github/settings.fragment.json +24 -0
  170. package/stacks/tooling/issue-tracker-github/skills/issue-tracker-github/SKILL.md +278 -0
  171. package/stacks/tooling/issue-tracker-linear/claude.fragment.md +17 -0
  172. package/stacks/tooling/issue-tracker-linear/settings.fragment.json +9 -0
  173. package/stacks/tooling/issue-tracker-linear/skills/issue-tracker-linear/SKILL.md +183 -0
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: mongo-conventions
3
+ description: MongoDB conventions for this repo — async access via Motor, append-only data-lake discipline, and provenance on every datum. Use when reading/writing Mongo collections, adding ingest or transform pipelines, designing indexes, building an embedding/vector store on Mongo, or reasoning about which data is the system of record.
4
+ ---
5
+
6
+ # MongoDB Conventions
7
+
8
+ Applies to: any code touching MongoDB in this repo (storage layers, ingest scripts, transforms, API routes).
9
+
10
+ > Naturalize: confirm the driver, database name, and the system-of-record collection(s) in `CLAUDE.md`.
11
+
12
+ ## Async access (Motor)
13
+
14
+ - Use the **async driver (Motor)** end-to-end in async services; `await` every DB call. Don't block the event loop with the sync `pymongo` client in request paths.
15
+ - The sync `pymongo` client is acceptable only for things Motor doesn't cover (e.g. GridFS) or for offline scripts — keep it off the hot path.
16
+ - Centralize connection setup: build the connection string from the environment (`MONGODB_URI` / `DATABASE_URL`, falling back to a local default), and detect localhost to skip TLS for dev.
17
+ - Create collections and indexes idempotently in an `initialize_collections()`-style routine: check `list_collection_names()` first, then `create_index(...)`. Mark uniqueness explicitly (`unique=True`) on natural keys (e.g. `content_id`).
18
+ - Guard in-memory caches (vector indexes, derived state) with an `asyncio.Lock` so concurrent requests don't rebuild them simultaneously.
19
+
20
+ ```python
21
+ from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
22
+
23
+ client: AsyncIOMotorClient = AsyncIOMotorClient(connection_string)
24
+ db: AsyncIOMotorDatabase = client[db_name]
25
+ await client.admin.command("ping") # verify connectivity
26
+ await db.content_raw.create_index("content_id", unique=True)
27
+ docs = await db.content_chunks.count_documents({})
28
+ ```
29
+
30
+ ## Append-only lake discipline
31
+
32
+ When the source data is expensive to acquire (paid APIs, rate-limited crawls, one-shot captures), keep a **raw lake collection that is the system of record** and treat everything downstream as a replayable transform:
33
+
34
+ - **Fetch once, keep forever.** Write raw payloads (with original structure and timestamps) into a lake collection (e.g. `*_lake` / `content_raw`). **Never re-fetch what's already in the lake** — re-fetching spends real money/quota.
35
+ - **Transforms are replayable and never destructive to the lake.** Chunking, extraction, tagging, embedding all read from the lake and write to *derived* collections. If a derived collection is lost, you can rebuild it for free from the lake.
36
+ - **Budget every acquisition run.** Acquisition spends a finite credit allowance; downstream transforms are cheap/free (often local). Make that asymmetry explicit in scripts and logs.
37
+ - A lost derived cache should be an inconvenience, not a catastrophe — design caches to be rebuildable rather than precious.
38
+
39
+ ## Provenance on every datum
40
+
41
+ - **Every stored datum carries its source + timestamp.** Identity fields, extraction results, tags, and derived facts all record where they came from and when. The UI renders provenance; the pipeline must preserve it through every transform.
42
+ - **`null` over a guess.** When a field can't be confidently determined, store `null` rather than a plausible-but-wrong value. Known priors are hints for an extractor, never hard fallbacks (e.g. a likely author is a prior, not a default — exceptions exist).
43
+ - **Couple derived artifacts to their generator.** Vectors/embeddings are only comparable when query and corpus come from the *same* model. Funnel all query-side embedding through one code path; changing the model requires re-deriving the whole corpus (re-embed + re-index + re-tag) plus recalibrating any model-specific thresholds. Treat the model id as part of the data's provenance.
44
+ - **Aggregate numbers link back to primary sources.** Any rolled-up count or score should be traceable to the underlying documents.
45
+
46
+ ## Indexing & schema
47
+
48
+ - Index the fields you filter/sort on (`source_type`, `speaker`/owner, tenant/owner keys); add a unique index on natural identifiers.
49
+ - For text search, combine a `$text` index with vector retrieval and fuse with a rank-combination strategy (e.g. RRF) rather than relying on one signal.
50
+ - Store large blobs in GridFS (or external object storage) above a size threshold rather than inlining megabytes into documents.
51
+
52
+ ## Operational notes
53
+
54
+ - **Restart long-running readers after offline ingest** if they hold an in-memory index — a separate ingest process won't invalidate the running server's cache.
55
+ - **Re-derive after bulk ingest** — new raw rows arrive without derived tags/embeddings; run the tagging/embedding transform after any bulk add.
56
+ - Back up the lake (it's the irreplaceable part); derived collections are rebuildable by design.
57
+
58
+ ## Hard-won lessons
59
+
60
+ (MongoDB Atlas-specific — only relevant when the cluster is hosted on Atlas.)
61
+
62
+ ### Flex/M0 clusters can't do private endpoints or peering
63
+ **Symptom:** You designed a private DB path (Private Endpoint / VNet) but Atlas
64
+ won't let you create one on the cluster.
65
+ **Cause:** Private endpoints and network peering are **dedicated-tier (M10+)**
66
+ features; Atlas Flex and M0 support IP-allowlist connectivity only.
67
+ **Fix:** If the connection must be private, M10+ dedicated is a hard prerequisite,
68
+ not just a storage upgrade. On Flex, interim connectivity is IP-allowlist only.
69
+
70
+ ### The Atlas SRV subdomain is per-CLUSTER, not per-project
71
+ **Symptom:** After recreating a cluster, the app can't connect — DNS/SRV resolution
72
+ points at the old host.
73
+ **Cause:** The SRV connection-string subdomain (e.g. `…ijcgrnb…` → `…75tne5…`)
74
+ changes whenever the cluster is recreated; it is per-cluster, not per-project. The
75
+ DB user and IP access list are project-scoped and carry over, masking the change.
76
+ **Fix:** After any cluster recreation, update the connection string in **both** env
77
+ vars/`.env` **and** secret stores. Key your config off the immutable project ID, not
78
+ the (renamable) project name.
79
+
80
+ ### Disk autoscaling blocks writes while scaling — size disks for bulk restores
81
+ **Symptom:** A large restore aborts mid-way with `DiskUseThresholdExceeded`.
82
+ **Cause:** Atlas disk auto-scaling **blocks writes while it scales**, so a restore
83
+ that crosses the threshold stalls — and transient journal/firehose overhead can spike
84
+ usage well above the settled corpus size.
85
+ **Fix:** For bulk restores, set a **generous fixed disk** with auto-scaling **off**
86
+ (e.g. 32 GB for a ~6 GB corpus). Atlas disks don't shrink, so the chosen size is a
87
+ permanent floor — pick deliberately.
88
+
89
+ ### In-place tier upgrades can hang and auto-revert — prefer fresh + restore
90
+ **Symptom:** An in-place Flex→M10 upgrade runs ~1h in `UPDATING`, then Atlas
91
+ auto-reverts to the old tier on timeout.
92
+ **Cause:** In-place tier transitions are not reliable and can be system-aborted;
93
+ data survives but the upgrade doesn't land.
94
+ **Fix:** When a local/dump master of record exists (so re-restore is cheap),
95
+ **provision a clean target cluster** (via IaC) and **restore from a dump** rather
96
+ than upgrading in place. Remember the SRV subdomain changes (see above).
@@ -0,0 +1,49 @@
1
+ <!-- pack: db/prisma -->
2
+ ## Database — Prisma + shared package
3
+
4
+ Prisma schema + generated client, shared across backend services as a workspace package (e.g. `@org/database`). See the `docker-database-package-copy` skill for the container-build discipline summarized below.
5
+
6
+ > Naturalize: record the database-package path, package name, and DB engine (Postgres assumed below) in Project facts.
7
+
8
+ ### Migration workflow
9
+
10
+ **Never** run `prisma migrate deploy` against a shared environment (dev/staging/prod) from a laptop — CI only.
11
+
12
+ Local loop:
13
+
14
+ 1. Edit `schema.prisma`.
15
+ 2. `npx prisma generate` (or the repo's `db:generate` script).
16
+ 3. Write the code that uses the new shape.
17
+ 4. Push the branch.
18
+ 5. CI opens a migration PR; review the generated SQL.
19
+ 6. Merge — auto-deploy follows.
20
+
21
+ ### Schema conventions
22
+
23
+ - **Naming**: camelCase fields in Prisma, snake_case in the DB via `@map`.
24
+ - **IDs**: UUID `@id @default(uuid())`.
25
+ - **Soft delete**: `deletedAt DateTime?` on tables that need it; default queries filter out soft-deleted rows.
26
+ - **Timestamps**: timezone-aware with explicit precision (Postgres: `@db.Timestamptz(3)`).
27
+ - **Tenant scoping**: every multi-tenant table has `tenantId String` + `@@index([tenantId])`, enforced at the API gateway (e.g. a tenant-context interceptor).
28
+ - **Migrations must be backward-compatible** — services deploy independently of migrations, so old code must still work with the new schema. Add in one release; drop a release later.
29
+ - **JSON-preference columns are single-purpose** — give each per-entity runtime flag its own JSONB column rather than a god-`preferences` blob, so analytics queries hit a focused GIN index and migrations stay narrow. Pair a `?`-queried column with a `USING GIN` index.
30
+ - **Key-style flag naming**: keys inside JSON-preference columns follow `{surface}_{action}_v{N}` (e.g. `recs_kpi_confirm_v1`); bump `vN` to re-surface rather than reusing a key. Document the convention in the model-field comment.
31
+
32
+ ### Docker COPY discipline
33
+
34
+ Each consumer service Dockerfile copies **specific** TypeScript files from the database package, not the whole tree:
35
+
36
+ ```dockerfile
37
+ COPY services/database/index.ts ./services/database/
38
+ COPY services/database/types.ts ./services/database/
39
+ ```
40
+
41
+ When you add a new `.ts` file under the database package **and export it through `index.ts`**, every Dockerfile that builds the package needs a matching `COPY` line. Missing COPY → CI fails with `TS2307` even though the local full-tree build passes. Before pushing a new exported file:
42
+
43
+ ```bash
44
+ rg 'COPY services/database/' services/*/Dockerfile # find all consumers
45
+ # add a COPY line to every match, then optionally smoke-build one:
46
+ docker build -f services/<service>/Dockerfile -t db-probe .
47
+ ```
48
+
49
+ **Pre-push gate:** when the Prisma schema is touched, run `prisma generate && <build>`, then rebuild dependent services.
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: docker-database-package-copy
3
+ description: When adding or changing TypeScript under the shared database package that index.ts re-exports, update every service Dockerfile's COPY list or the container build fails with TS2307. Use for database-package modules, Dockerfile edits, or "works locally but the container build breaks".
4
+ ---
5
+
6
+ # Docker COPY list for the shared database package
7
+
8
+ Applies to monorepos where a shared Prisma/database package is consumed by multiple containerized services, and each service Dockerfile copies **specific** source files (not the whole tree).
9
+
10
+ > Naturalize: replace `services/database` with this repo's database-package path and the package name in `CLAUDE.md`.
11
+
12
+ ## Trigger
13
+
14
+ - New or renamed source file under the database package **reachable from** its `index.ts`.
15
+ - A PR touches the database package's `index.ts` **and** a service `Dockerfile`.
16
+
17
+ ## Do this
18
+
19
+ 1. Find every Dockerfile that copies database sources:
20
+ ```bash
21
+ rg 'COPY services/database/' services -g Dockerfile
22
+ ```
23
+ 2. For each **new** source file the package needs, add **once per Dockerfile** that copies database sources:
24
+
25
+ ```dockerfile
26
+ COPY services/database/<filename>.ts ./services/database/
27
+ ```
28
+
29
+ Keep the block with the other `services/database/*.ts` COPY lines.
30
+
31
+ 3. Prefer a quick smoke build before pushing:
32
+ ```bash
33
+ docker build -f services/<any-service>/Dockerfile -t probe .
34
+ ```
35
+
36
+ ## Why
37
+
38
+ Container images only contain explicitly copied files. A local `pnpm build` uses the full repo tree; **Docker does not**. A missing COPY line surfaces as `TS2307: Cannot find module '.../services/database/<file>'` in CI even though the local build passes.
39
+
40
+ **Doesn't apply to:** Prisma-only files, CLI-only scripts, anything under the database package that isn't re-exported via `index.ts`.
41
+
42
+ ## Canonical doc
43
+
44
+ The pack's `claude.fragment.md` (and the rendered `CLAUDE.md`) carries the rest of the Prisma + Docker workflow. If the repo mirrors rules into a Cursor ruleset, keep them in sync.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: prisma-conventions
3
+ description: Prisma ORM conventions for this repo — schema/migration discipline, constraints Prisma can't express, and the @@map/@map gotcha that bites $queryRaw. Activate when writing or reviewing Prisma schema (schema.prisma), migrations, generated-client usage, or raw SQL through Prisma ($queryRaw/$executeRaw), or when debugging P2002 unique-constraint errors or "relation does not exist" at runtime.
4
+ ---
5
+
6
+ # Prisma Conventions
7
+
8
+ Applies to any code touching Prisma in this repo — `schema.prisma`, migrations under
9
+ `prisma/migrations/`, the generated client, and raw SQL via `$queryRaw`/`$executeRaw`.
10
+
11
+ > Naturalize: confirm the schema path, datasource provider, and the database-package
12
+ > location in `CLAUDE.md`.
13
+
14
+ ## Hard-won lessons
15
+
16
+ ### Prisma can't express partial / conditional unique constraints
17
+ **Symptom:** You need uniqueness only under a condition (e.g. unique email *among
18
+ non-deleted rows*, or unique slug *per tenant where active*), but `@@unique` applies
19
+ unconditionally and rejects legitimate rows.
20
+ **Cause:** Prisma's schema DSL has no syntax for partial/filtered unique indexes —
21
+ `@@unique` maps to a plain `UNIQUE` constraint with no `WHERE`.
22
+ **Fix:** Hand-write the index in a migration —
23
+ `CREATE UNIQUE INDEX … ON … (…) WHERE …;` — and keep it out of the schema's
24
+ `@@unique`. Because Prisma doesn't model it, catch the violation in the service layer
25
+ by handling the **P2002** error code rather than relying on schema-level validation.
26
+
27
+ ### `$queryRaw` uses DB names (@@map/@map), not Prisma model names
28
+ **Symptom:** Mocked/unit tests pass, but against a real database `$queryRaw` /
29
+ `$executeRaw` throws `relation "User" does not exist` (or a missing-column error).
30
+ **Cause:** Raw SQL **bypasses the ORM** and goes straight to Postgres. Prisma model
31
+ and field names are a client-side abstraction; the actual table/column names are the
32
+ `@@map`/`@map` values from the schema (e.g. model `User` → table `users`). Mocks
33
+ don't hit the DB, so they never reveal the mismatch.
34
+ **Fix:** In any raw SQL, reference the **mapped** table and column names (the
35
+ `@@map`/`@map` values), never the Prisma model/field names. Grep the schema for the
36
+ relevant `@@map`/`@map` before writing the query, and prefer an integration test that
37
+ hits a real database for any raw-SQL path.
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: apple-ads
3
+ description: "Understand Apple Ads and App Store acquisition mechanics. Use when evaluating Apple Search Ads / Apple Ads placements, campaign structure, keyword strategy, custom product pages, customer type targeting, attribution via AdServices or AdAttributionKit, App Store creative alignment, or Apple app-growth cost planning such as CPT, CPA, ROAS, and budget scenarios."
4
+ ---
5
+
6
+ # Apple Ads
7
+
8
+ Use this skill when reasoning about paid growth in the App Store ecosystem.
9
+ It is for **Apple Ads** strategy and operations, not StoreKit billing or app
10
+ review.
11
+
12
+ ## When to Use This Skill
13
+
14
+ - The user asks about Apple Search Ads / Apple Ads.
15
+ - You need to explain App Store ad placements or campaign structure.
16
+ - You need to compare Apple acquisition costs, CPT, CPA, CPI, or ROAS.
17
+ - You need to reason about custom product pages, ad variations, or keyword
18
+ strategy.
19
+ - You need to refresh Apple Ads guidance from official docs or recent
20
+ benchmark sources.
21
+
22
+ ## What Exists in the Apple Ads Ecosystem
23
+
24
+ As of 2025-2026, the practical Apple app-growth stack is:
25
+
26
+ - **Search Results ads**: the highest-intent App Store placement; users have
27
+ already typed a query.
28
+ - **Search Tab ads**: discovery before the user searches; broader reach,
29
+ lower intent.
30
+ - **Today Tab ads**: premium awareness placement on the App Store front page;
31
+ best for launches, tentpole moments, or large bursts.
32
+ - **Product Pages ads**: contextual reach in the "You Might Also Like" area
33
+ on app product pages.
34
+ - **Custom Product Pages (CPPs)**: App Store landing pages tailored to
35
+ keyword themes, feature themes, geographies, or campaigns.
36
+ - **Ad variations**: connect different campaign themes to different CPPs.
37
+ - **AdServices attribution API**: the main deterministic measurement API for
38
+ Apple Ads itself.
39
+ - **AdAttributionKit**: privacy-preserving attribution for broader ad
40
+ measurement and postback handling outside the older SKAdNetwork mindset.
41
+
42
+ ## How Apple Ads Works Operationally
43
+
44
+ ### Placement Strategy
45
+
46
+ - Treat **Search Results** as the core direct-response channel.
47
+ - Treat **Search Tab** and **Today Tab** as upper-funnel or launch support,
48
+ then judge them by downstream quality, not raw volume.
49
+ - Treat **Product Pages** as contextual conquesting and adjacent-category
50
+ discovery.
51
+
52
+ ### Campaign Structure
53
+
54
+ Apple's best-practice structure is still the right default:
55
+
56
+ 1. **Brand**: your app name, company name, and close brand variants.
57
+ 2. **Category**: high-intent non-brand keywords describing the job your app
58
+ does.
59
+ 3. **Competitor**: competitor app names and adjacent alternatives.
60
+ 4. **Discovery**: Search Match plus broad match to mine new terms.
61
+
62
+ Keep these separated so you can:
63
+
64
+ - see what you are actually buying,
65
+ - protect brand cheaply,
66
+ - prevent competitor and discovery traffic from muddying performance, and
67
+ - move proven search terms into exact-match campaigns with tighter bidding.
68
+
69
+ ### Keywords and Search Terms
70
+
71
+ - **Exact match** belongs in Brand, Category, and Competitor campaigns.
72
+ - **Broad match** belongs mostly in Discovery.
73
+ - **Search Match** is a mining tool, not a substitute for campaign structure.
74
+ - Use **negative keywords** aggressively to stop overlap and irrelevance.
75
+ - Review the **search terms report** regularly and promote winners out of
76
+ Discovery.
77
+
78
+ ### Audience Refinements
79
+
80
+ Apple Ads audience settings matter, but search intent usually matters more.
81
+
82
+ Use refinements when there is a real reason:
83
+
84
+ - **Customer type**: new users, returning users, or users of your other apps.
85
+ - **Device**: iPhone vs iPad when monetization or conversion differs.
86
+ - **Location**: only when the app or offer is meaningfully geo-specific.
87
+ - **Demographics**: use carefully; intent usually beats inferred profile data.
88
+
89
+ ### Creative and Landing Surface
90
+
91
+ - Do not point every campaign at the default product page.
92
+ - Build **Custom Product Pages** around specific feature or keyword themes.
93
+ - Match screenshots, preview video, subtitle, and promotional text to the
94
+ user's likely reason for tapping.
95
+ - Use **ad variations** to map keyword clusters or campaigns to the right CPP.
96
+ - Treat CPPs as a conversion lever, not just a merchandising asset.
97
+
98
+ ## Cost Model and Planning Concepts
99
+
100
+ ### Core Buying Logic
101
+
102
+ - Apple Ads is an **auction system**.
103
+ - In **manual bidding**, model around **max CPT** for the search-led parts of
104
+ the system.
105
+ - In **automated bidding** for eligible search-results campaigns, model around
106
+ **Target CPA / Maximize Conversions**.
107
+ - Budgeting still needs enough volume for the algorithm to learn; underfunded
108
+ campaigns usually produce noisy, misleading results.
109
+
110
+ ### Practical Metrics
111
+
112
+ - **CPT**: cost per tap; the direct bid/control concept for search-led buying.
113
+ - **TTR**: tap-through rate; use it to judge keyword and creative relevance.
114
+ - **Conversion rate**: store tap to install.
115
+ - **CPA / CPI**: acquisition cost; what finance and growth actually care about.
116
+ - **ROAS**: use when the app has meaningful post-install revenue data.
117
+
118
+ ### Directional Cost Expectations
119
+
120
+ Use benchmark numbers as directional, not as promises. Apple does not publish
121
+ market-average costs.
122
+
123
+ - Search Results is usually the most efficient Apple placement because intent
124
+ is highest.
125
+ - Search Tab and Today Tab are typically broader-reach and lower-intent, so
126
+ they need different success criteria.
127
+ - US, Games, Finance, and other competitive categories are materially more
128
+ expensive than lower-intent regions and softer categories.
129
+
130
+ Use [references/benchmark-notes.md](references/benchmark-notes.md) for working
131
+ benchmark ranges and caveats.
132
+
133
+ ## Attribution and Measurement Reality
134
+
135
+ - For **Apple Ads itself**, start with the **AdServices attribution API**.
136
+ - For broader privacy-preserving install and re-engagement measurement on iOS,
137
+ understand **AdAttributionKit**.
138
+ - Treat **SKAdNetwork** as legacy context you may still encounter, not the only
139
+ framing.
140
+ - **ATT** still constrains what other networks can do; Apple Ads benefits from
141
+ its first-party App Store position.
142
+ - For revenue optimization, do not stop at installs. Join Apple Ads data with
143
+ in-app revenue, renewal, and retention data before making big spend calls.
144
+
145
+ ## Operational Advice
146
+
147
+ - Defend brand terms first. Letting competitors buy your brand is unforced
148
+ waste.
149
+ - Separate discovery from exploitation. Discovery finds terms; exact-match
150
+ campaigns scale them.
151
+ - Use CPPs wherever search intent clearly differs by theme or feature.
152
+ - Judge Search Tab and Today Tab on blended incremental value, not on direct
153
+ install cost alone.
154
+ - Revisit budget caps before declaring a campaign "bad"; many Apple Ads
155
+ campaigns are just underfed.
156
+ - Mine returning users separately if reacquisition economics are strong.
157
+
158
+ ## Common Mistakes
159
+
160
+ - Mixing brand, category, competitor, and discovery traffic in one campaign.
161
+ - Running Discovery forever without graduating winning terms.
162
+ - Using the default product page for every keyword theme.
163
+ - Evaluating all placements with the same KPI.
164
+ - Treating Apple Ads installs as automatically high quality without checking
165
+ retention, trial start, renewal, or payer mix.
166
+ - Assuming ATT-era attribution means "measurement is impossible" instead of
167
+ building a practical first-party reporting loop.
168
+
169
+ ## Refresh Workflow
170
+
171
+ When this skill may be stale:
172
+
173
+ 1. Read [references/official-links.md](references/official-links.md) first.
174
+ 2. Re-check Apple Ads help pages for placements, bidding, attribution, and
175
+ reporting definitions.
176
+ 3. Re-check Apple developer docs for CPPs, Apple Ads APIs, and
177
+ AdAttributionKit.
178
+ 4. Use benchmark sources only to set directional priors, never as hard budget
179
+ guarantees.
180
+
181
+ ## References
182
+
183
+ - [Official links](references/official-links.md)
184
+ - [Benchmark notes](references/benchmark-notes.md)
@@ -0,0 +1,47 @@
1
+ # Apple Ads Benchmark Notes
2
+
3
+ Apple does not publish market-average CPT, CPA, or ROAS benchmarks. Use the
4
+ sources below as directional planning inputs only.
5
+
6
+ ## Practical Benchmark Heuristics
7
+
8
+ - **Search Results** is usually the most efficient Apple placement because user
9
+ intent is explicit.
10
+ - **Search Tab** and **Today Tab** tend to look worse on direct CPA but can be
11
+ useful for awareness, launches, and broader brand capture.
12
+ - Expect large variation by:
13
+ - country,
14
+ - category,
15
+ - seasonality,
16
+ - brand strength,
17
+ - product-page conversion quality.
18
+
19
+ ## Common Directional Ranges Seen in 2025-2026 Reporting
20
+
21
+ - Global median **Search Results CPT** is often reported near the low-
22
+ single-dollar range.
23
+ - US **Search Results CPT** is often materially higher than global median.
24
+ - Highly competitive categories such as **Games** and **Finance** often cost
25
+ multiples of softer categories.
26
+ - Search-led install conversion rates are usually far better than non-search
27
+ placements.
28
+
29
+ These are not commit-worthy forecast numbers; they are sanity-check inputs.
30
+
31
+ ## Recommended Third-Party Refresh Sources
32
+
33
+ - AppTweak Apple Ads benchmarks: https://www.apptweak.com/en/aso-blog/apple-ads-benchmarks
34
+ - MobileAction Apple Search Ads benchmark report: https://www.mobileaction.co/report/apple-search-ads-2025-benchmark-report/
35
+ - SplitMetrics Apple Search Ads guides: https://splitmetrics.com/blog/apple-search-ads/
36
+
37
+ ## How to Use Benchmarks Safely
38
+
39
+ - Build **base / upside / downside** acquisition scenarios.
40
+ - Use benchmarks to detect obviously unrealistic plans, not to set exact bids.
41
+ - Always anchor final decisions to your own:
42
+ - tap-through rate,
43
+ - install conversion rate,
44
+ - trial or purchase conversion,
45
+ - payback period,
46
+ - 30-day retention,
47
+ - renewal or payer quality.
@@ -0,0 +1,53 @@
1
+ # Apple Ads Official Links
2
+
3
+ Use these first when refreshing the skill.
4
+
5
+ ## Core Apple Ads
6
+
7
+ - Apple Ads home: https://ads.apple.com/
8
+ - Apple Ads help center: https://ads.apple.com/help
9
+ - App Store ad placements overview: https://ads.apple.com/app-store/help/ad-placements/0081-ad-placement-options
10
+ - Today Tab placement: https://ads.apple.com/app-store/help/ad-placements/0083-today-tab
11
+ - Apple Ads best practices hub: https://ads.apple.com/app-store/best-practices
12
+
13
+ ## Campaign Design and Optimization
14
+
15
+ - Campaign structure: https://ads.apple.com/app-store/best-practices/campaign-structure
16
+ - Manual bidding: https://ads.apple.com/app-store/best-practices/manual-bidding
17
+ - Maximize Conversions: https://ads.apple.com/app-store/best-practices/maximize-conversions
18
+ - Ad variations: https://ads.apple.com/app-store/best-practices/ad-variations
19
+ - Redownloads / returning users: https://ads.apple.com/app-store/best-practices/redownloads
20
+ - Recommendations: https://ads.apple.com/app-store/best-practices/recommendations
21
+
22
+ ## Keywords, Targeting, and Budget
23
+
24
+ - Keyword match types: https://ads.apple.com/app-store/help/keywords/0059-understand-keyword-match-types
25
+ - Negative keywords: https://ads.apple.com/app-store/help/keywords/0060-use-negative-keywords
26
+ - Search Match: https://ads.apple.com/app-store/help/campaigns/0006-understand-search-match
27
+ - Audience settings: https://ads.apple.com/app-store/help/ad-groups/0021-modify-audience-settings
28
+ - Manage budgets: https://ads.apple.com/app-store/help/bids-and-budget/0016-manage-budgets
29
+
30
+ ## Measurement and Reporting
31
+
32
+ - Measuring ad performance: https://ads.apple.com/app-store/help/attribution/0028-measuring-ad-performance
33
+ - AdAttributionKit for Apple Ads measurement: https://ads.apple.com/app-store/help/attribution/0093-adattributionkit-to-measure-performance
34
+ - Reporting definitions: https://ads.apple.com/app-store/help/reporting/0023-reporting-options-and-definitions
35
+
36
+ ## Apple Developer Documentation
37
+
38
+ - Custom Product Pages: https://developer.apple.com/app-store/custom-product-pages/
39
+ - App Store ad attribution / AdAttributionKit overview: https://developer.apple.com/app-store/ad-attribution/
40
+ - Apple Ads developer documentation: https://developer.apple.com/documentation/apple_ads
41
+ - Apple Search Ads Campaign Management API 5: https://developer.apple.com/documentation/apple_ads/apple-search-ads-campaign-management-api-5
42
+
43
+ ## Supporting Apple Platform Docs
44
+
45
+ - ATT overview: https://support.apple.com/en-us/102420
46
+ - Personalized ads on iPhone: https://support.apple.com/guide/iphone/control-how-apple-delivers-advertising-to-you-iphf60a6a256/ios
47
+
48
+ ## Notes
49
+
50
+ - Prefer the Apple Ads help center and Apple developer docs over blog posts when
51
+ checking feature availability, measurement behavior, and API capabilities.
52
+ - Re-check placement availability and rollout notes before modeling inventory;
53
+ Apple changes the App Store ads surface gradually by market.