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.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/core/agents/aaron.md +152 -0
- package/core/agents/bert.md +115 -0
- package/core/agents/isabelle.md +136 -0
- package/core/agents/jody.md +150 -0
- package/core/agents/leith.md +111 -0
- package/core/agents/marcelo.md +282 -0
- package/core/agents/melvin.md +101 -0
- package/core/agents/nyx.md +152 -0
- package/core/agents/otto.md +168 -0
- package/core/agents/patricia.md +283 -0
- package/core/commands/design-audit-local.md +155 -0
- package/core/commands/design-audit.md +235 -0
- package/core/commands/design-critique.md +96 -0
- package/core/commands/file-issue.md +22 -0
- package/core/commands/generate-project.md +45 -0
- package/core/commands/implement-issue.md +37 -0
- package/core/commands/implement-project.md +40 -0
- package/core/commands/naturalize.md +61 -0
- package/core/commands/pre-push.md +29 -0
- package/core/commands/prep-review-collect.md +130 -0
- package/core/commands/prep-review-finalize.md +121 -0
- package/core/commands/prep-review-publish.md +113 -0
- package/core/commands/prep-review.md +65 -0
- package/core/commands/project-closeout.md +25 -0
- package/core/skills/agentic-eval/SKILL.md +195 -0
- package/core/skills/chrome-devtools/SKILL.md +97 -0
- package/core/skills/code-review/SKILL.md +26 -0
- package/core/skills/gh-cli/SKILL.md +2202 -0
- package/core/skills/git-commit/SKILL.md +124 -0
- package/core/skills/git-workflow-agents/SKILL.md +462 -0
- package/core/skills/git-workflow-agents/reference.md +220 -0
- package/core/skills/github-actions/SKILL.md +190 -0
- package/core/skills/github-issues/SKILL.md +154 -0
- package/core/skills/llm-structured-outputs/SKILL.md +323 -0
- package/core/skills/llm-structured-outputs/references/provider-details.md +392 -0
- package/core/skills/pre-push/SKILL.md +115 -0
- package/core/skills/refactor/SKILL.md +645 -0
- package/core/skills/web-design-reviewer/SKILL.md +371 -0
- package/core/skills/webapp-testing/SKILL.md +127 -0
- package/core/skills/webapp-testing/test-helper.js +56 -0
- package/core/templates/CLAUDE.md.tmpl +98 -0
- package/core/templates/adr-template.md +67 -0
- package/core/templates/gh-issue-templates/bug.md +39 -0
- package/core/templates/gh-issue-templates/content.md +42 -0
- package/core/templates/gh-issue-templates/enhancement.md +36 -0
- package/core/templates/gh-issue-templates/feature.md +39 -0
- package/core/templates/gh-issue-templates/infrastructure.md +41 -0
- package/core/templates/post-edit-reminders.sh.tmpl +19 -0
- package/core/templates/settings.json.tmpl +90 -0
- package/core/templates/settings.local.json.tmpl +3 -0
- package/core/workflows/agent-implementation-workflow.md +346 -0
- package/core/workflows/generate-project.md +258 -0
- package/core/workflows/implement-project-workflow.md +190 -0
- package/core/workflows/issue-tracking.md +89 -0
- package/core/workflows/project-closeout-ceremony.md +77 -0
- package/core/workflows/review-workflow.md +266 -0
- package/engsys.config.example.yaml +46 -0
- package/install +202 -0
- package/lessons-library/README.md +80 -0
- package/lessons-library/async-callbacks-verify-liveness.md +15 -0
- package/lessons-library/change-isnt-done-until-every-surface-updated.md +15 -0
- package/lessons-library/claim-then-act-for-irreversible-ops.md +16 -0
- package/lessons-library/co-commit-entangled-work.md +15 -0
- package/lessons-library/dependabot-triage-playbook.md +17 -0
- package/lessons-library/deploy-by-digest-and-verify-the-running-revision.md +15 -0
- package/lessons-library/enforce-your-guarantee-at-your-boundary.md +16 -0
- package/lessons-library/gate-changes-on-measurement-not-vibes.md +15 -0
- package/lessons-library/iac-first-no-console-changes.md +15 -0
- package/lessons-library/independent-objective-review-gate.md +15 -0
- package/lessons-library/keep-an-immutable-source-of-truth.md +15 -0
- package/lessons-library/long-agent-runs-checkpoint-not-poll.md +15 -0
- package/lessons-library/model-identity-with-stable-ids-and-provenance.md +15 -0
- package/lessons-library/operator-choices-are-first-class.md +15 -0
- package/lessons-library/prefer-tool-enforced-structured-output.md +15 -0
- package/lessons-library/prove-causation-before-acting.md +15 -0
- package/lessons-library/re-read-state-before-acting.md +14 -0
- package/lessons-library/read-layer-tolerates-unbackfilled-rows.md +15 -0
- package/lessons-library/shell-safety-pipefail-and-validate-before-teardown.md +14 -0
- package/lessons-library/shift-correctness-left-and-distrust-false-greens.md +15 -0
- package/lessons-library/stray-control-bytes-hide-changes.md +14 -0
- package/lessons-library/tests-can-assert-the-bug.md +15 -0
- package/lessons-library/verify-ground-truth-not-reports.md +15 -0
- package/lessons-library/worktrees-need-bootstrap-from-origin-main.md +15 -0
- package/lib/commands.js +356 -0
- package/lib/generate-team-avatars.mjs +251 -0
- package/lib/manifest.js +155 -0
- package/lib/render.js +135 -0
- package/lib/selftest.js +90 -0
- package/lib/util.js +89 -0
- package/lib/yaml.js +156 -0
- package/optional-agents/gary.md +86 -0
- package/optional-agents/jos.md +136 -0
- package/optional-agents/sandy.md +101 -0
- package/optional-agents/steve.md +161 -0
- package/package.json +43 -0
- package/stacks/cloud/aws/claude.fragment.md +17 -0
- package/stacks/cloud/aws/settings.fragment.json +39 -0
- package/stacks/cloud/aws/skills/aws-deployment-preflight/SKILL.md +165 -0
- package/stacks/cloud/aws/skills/cloud-architecture-aws/SKILL.md +265 -0
- package/stacks/cloud/azure/claude.fragment.md +17 -0
- package/stacks/cloud/azure/settings.fragment.json +45 -0
- package/stacks/cloud/azure/skills/azure-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/azure/skills/cloud-architecture-azure/SKILL.md +211 -0
- package/stacks/cloud/cloudflare/claude.fragment.md +21 -0
- package/stacks/cloud/cloudflare/settings.fragment.json +31 -0
- package/stacks/cloud/cloudflare/skills/cloud-architecture-cloudflare/SKILL.md +294 -0
- package/stacks/cloud/cloudflare/skills/cloudflare-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/gcp/claude.fragment.md +17 -0
- package/stacks/cloud/gcp/settings.fragment.json +40 -0
- package/stacks/cloud/gcp/skills/cloud-architecture-gcp/SKILL.md +208 -0
- package/stacks/cloud/gcp/skills/gcp-deployment-preflight/SKILL.md +137 -0
- package/stacks/db/mongo/skills/mongo-conventions/SKILL.md +96 -0
- package/stacks/db/prisma/claude.fragment.md +49 -0
- package/stacks/db/prisma/skills/docker-database-package-copy/SKILL.md +44 -0
- package/stacks/db/prisma/skills/prisma-conventions/SKILL.md +37 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/SKILL.md +184 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/official-links.md +53 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/SKILL.md +197 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/official-links.md +45 -0
- package/stacks/iac/bicep/claude.fragment.md +14 -0
- package/stacks/iac/bicep/settings.fragment.json +20 -0
- package/stacks/iac/bicep/skills/iac-bicep/SKILL.md +113 -0
- package/stacks/iac/cdk/claude.fragment.md +14 -0
- package/stacks/iac/cdk/settings.fragment.json +23 -0
- package/stacks/iac/cdk/skills/iac-cdk/SKILL.md +104 -0
- package/stacks/iac/terraform/claude.fragment.md +13 -0
- package/stacks/iac/terraform/settings.fragment.json +25 -0
- package/stacks/iac/terraform/skills/iac-terraform/SKILL.md +93 -0
- package/stacks/iac/terraform/skills/terraform-conventions/SKILL.md +87 -0
- package/stacks/lang/kotlin/skills/android-testing/SKILL.md +263 -0
- package/stacks/lang/kotlin/skills/jetpack-compose/SKILL.md +264 -0
- package/stacks/lang/kotlin/skills/kotlin-coroutines/SKILL.md +329 -0
- package/stacks/lang/python/skills/python-conventions/SKILL.md +61 -0
- package/stacks/lang/shell/skills/shell-scripting/SKILL.md +110 -0
- package/stacks/lang/swift/skills/swift-concurrency/SKILL.md +423 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/approachable-concurrency.md +80 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/concurrency-patterns.md +233 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/swiftui-concurrency.md +187 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/synchronization-primitives.md +341 -0
- package/stacks/lang/swift/skills/swift-testing/SKILL.md +497 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-advanced.md +106 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-patterns.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/SKILL.md +334 -0
- package/stacks/lang/swift/skills/swiftdata/references/core-data-coexistence.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-advanced.md +975 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-queries.md +675 -0
- package/stacks/lang/swift/skills/swiftui-patterns/SKILL.md +371 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/architecture-patterns.md +486 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/deprecated-migration.md +1097 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/design-polish.md +780 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/platform-and-sharing.md +696 -0
- package/stacks/lang/typescript/skills/typescript-conventions/SKILL.md +91 -0
- package/stacks/platform/android/claude.fragment.md +40 -0
- package/stacks/platform/android/hooks/pre-push-gradle.sh +70 -0
- package/stacks/platform/android/settings.fragment.json +13 -0
- package/stacks/platform/android/skills/android-build-conventions/SKILL.md +247 -0
- package/stacks/platform/ios/claude.fragment.md +24 -0
- package/stacks/platform/ios/hooks/pre-push-xcodebuild.sh +82 -0
- package/stacks/platform/ios/settings.fragment.json +21 -0
- package/stacks/platform/ios/skills/xcodebuildmcp-simulator-logs/SKILL.md +76 -0
- package/stacks/platform/web/skills/frontend-testing/SKILL.md +246 -0
- package/stacks/platform/web/skills/react-conventions/SKILL.md +261 -0
- package/stacks/platform/web/skills/web-platform-conventions/SKILL.md +55 -0
- package/stacks/tooling/issue-tracker-github/claude.fragment.md +10 -0
- package/stacks/tooling/issue-tracker-github/settings.fragment.json +24 -0
- package/stacks/tooling/issue-tracker-github/skills/issue-tracker-github/SKILL.md +278 -0
- package/stacks/tooling/issue-tracker-linear/claude.fragment.md +17 -0
- package/stacks/tooling/issue-tracker-linear/settings.fragment.json +9 -0
- 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.
|