@terreno/mcp 57.3.0 → 57.4.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 (250) hide show
  1. package/README.md +7 -1
  2. package/dist/bootstrap.d.ts +0 -18
  3. package/dist/bootstrap.d.ts.map +1 -1
  4. package/dist/bootstrap.js +10 -2428
  5. package/dist/bootstrap.js.map +1 -1
  6. package/dist/docs/guidelines/admin-frontend/guidelines/core.md +5 -1
  7. package/dist/docs/guidelines/api/skills/mongoose-schema-safety/SKILL.md +23 -10
  8. package/dist/docs/resources/syncdb.md +4 -1
  9. package/dist/docs/upgrades/57.4.0.md +140 -0
  10. package/dist/docs/versioned/next/README.md +3 -0
  11. package/dist/docs/versioned/next/explanation/README.md +4 -1
  12. package/dist/docs/versioned/next/explanation/admin-interface.md +20 -13
  13. package/dist/docs/versioned/next/explanation/charts.md +29 -0
  14. package/dist/docs/versioned/next/explanation/deployment-architecture-gcp.md +32 -0
  15. package/dist/docs/versioned/next/explanation/deployment-baseline.md +1 -1
  16. package/dist/docs/versioned/next/explanation/example-coverage.md +43 -0
  17. package/dist/docs/versioned/next/explanation/local-first-data.md +5 -2
  18. package/dist/docs/versioned/next/explanation/loop-engineering.md +9 -6
  19. package/dist/docs/versioned/next/explanation/model-router-actions.md +19 -2
  20. package/dist/docs/versioned/next/explanation/organizations.md +88 -0
  21. package/dist/docs/versioned/next/explanation/planning-plugins.md +114 -0
  22. package/dist/docs/versioned/next/explanation/positioning.md +3 -3
  23. package/dist/docs/versioned/next/explanation/repository-settings.md +6 -5
  24. package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +44 -34
  25. package/dist/docs/versioned/next/explanation/source-rules.md +1 -1
  26. package/dist/docs/versioned/next/explanation/static-analysis.md +76 -16
  27. package/dist/docs/versioned/next/how-to/README.md +10 -0
  28. package/dist/docs/versioned/next/how-to/add-gpt-chat-mascot.md +92 -0
  29. package/dist/docs/versioned/next/how-to/add-organizations.md +204 -0
  30. package/dist/docs/versioned/next/how-to/admin-add-model.md +9 -1
  31. package/dist/docs/versioned/next/how-to/admin-import-prebuilt.md +7 -1
  32. package/dist/docs/versioned/next/how-to/audit-log.md +85 -0
  33. package/dist/docs/versioned/next/how-to/background-jobs.md +296 -0
  34. package/dist/docs/versioned/next/how-to/build-admin-screens.md +42 -13
  35. package/dist/docs/versioned/next/how-to/charts-and-dashboards.md +37 -0
  36. package/dist/docs/versioned/next/how-to/circleci.md +136 -27
  37. package/dist/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +36 -0
  38. package/dist/docs/versioned/next/how-to/configure-better-auth.md +4 -0
  39. package/dist/docs/versioned/next/how-to/create-a-terreno-app.md +154 -0
  40. package/dist/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +2 -0
  41. package/dist/docs/versioned/next/how-to/github-actions-ci.md +4 -3
  42. package/dist/docs/versioned/next/how-to/github-issue-lifecycle.md +12 -8
  43. package/dist/docs/versioned/next/how-to/in-app-notifications.md +147 -0
  44. package/dist/docs/versioned/next/how-to/install-agent-skills.md +24 -12
  45. package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +19 -3
  46. package/dist/docs/versioned/next/how-to/product-announcements.md +155 -0
  47. package/dist/docs/versioned/next/how-to/run-mongodb-migrations.md +127 -0
  48. package/dist/docs/versioned/next/how-to/run-tests-locally.md +102 -0
  49. package/dist/docs/versioned/next/how-to/seed-a-database.md +7 -2
  50. package/dist/docs/versioned/next/implementationPlans/README.md +8 -5
  51. package/dist/docs/versioned/next/implementationPlans/admin-scripts-durable-jobs.md +44 -0
  52. package/dist/docs/versioned/next/implementationPlans/agent-ui-blocks.md +386 -0
  53. package/dist/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +11 -8
  54. package/dist/docs/versioned/next/implementationPlans/announcements-surfaces.md +231 -0
  55. package/dist/docs/versioned/next/implementationPlans/announcements.md +289 -0
  56. package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +3 -1
  57. package/dist/docs/versioned/next/implementationPlans/charts-and-dashboards.md +246 -0
  58. package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +4 -3
  59. package/dist/docs/versioned/next/implementationPlans/create-terreno-app.md +177 -0
  60. package/dist/docs/versioned/next/implementationPlans/datatable-server-side-filtering.md +219 -0
  61. package/dist/docs/versioned/next/implementationPlans/examples-demo-coverage.md +17 -17
  62. package/dist/docs/versioned/next/implementationPlans/framework-audit-log.md +247 -0
  63. package/dist/docs/versioned/next/implementationPlans/gpt-chat-mascot.md +40 -0
  64. package/dist/docs/versioned/next/implementationPlans/job-queues.md +330 -0
  65. package/dist/docs/versioned/next/implementationPlans/knip-cleanup.md +136 -0
  66. package/dist/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +210 -0
  67. package/dist/docs/versioned/next/implementationPlans/mongodb-migrations-tooling.md +254 -0
  68. package/dist/docs/versioned/next/implementationPlans/notification-center.md +185 -0
  69. package/dist/docs/versioned/next/implementationPlans/org-management-ui.md +8 -3
  70. package/dist/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -1
  71. package/dist/docs/versioned/next/reference/README.md +4 -0
  72. package/dist/docs/versioned/next/reference/admin-backend.md +83 -5
  73. package/dist/docs/versioned/next/reference/admin-config.md +7 -0
  74. package/dist/docs/versioned/next/reference/admin-frontend.md +178 -5
  75. package/dist/docs/versioned/next/reference/admin-spa.md +18 -1
  76. package/dist/docs/versioned/next/reference/ai.md +2 -0
  77. package/dist/docs/versioned/next/reference/announcements.md +179 -0
  78. package/dist/docs/versioned/next/reference/api.md +343 -4
  79. package/dist/docs/versioned/next/reference/comms.md +33 -0
  80. package/dist/docs/versioned/next/reference/create-terreno-app.md +44 -0
  81. package/dist/docs/versioned/next/reference/environment-variables.md +29 -0
  82. package/dist/docs/versioned/next/reference/jobs.md +319 -0
  83. package/dist/docs/versioned/next/reference/legacy/rtk.md +5 -1
  84. package/dist/docs/versioned/next/reference/lifecycle-plugin.md +29 -11
  85. package/dist/docs/versioned/next/reference/mcp-server.md +2 -43
  86. package/dist/docs/versioned/next/reference/scan-plugin.md +169 -0
  87. package/dist/docs/versioned/next/reference/syncdb.md +38 -12
  88. package/dist/docs/versioned/next/reference/test.md +57 -6
  89. package/dist/docs/versioned/next/reference/ui-performance.md +2 -1
  90. package/dist/docs/versioned/next/reference/ui.md +257 -3
  91. package/dist/docs/versioned/next/tasks/admin-scripts-durable-jobs.md +10 -0
  92. package/dist/docs/versioned/next/tasks/agent-ui-blocks.md +114 -0
  93. package/dist/docs/versioned/next/tasks/announcements-surfaces.md +101 -0
  94. package/dist/docs/versioned/next/tasks/announcements.md +173 -0
  95. package/dist/docs/versioned/next/tasks/charts-and-dashboards.md +120 -0
  96. package/dist/docs/versioned/next/tasks/create-terreno-app.md +82 -0
  97. package/dist/docs/versioned/next/tasks/datatable-server-side-filtering.md +87 -0
  98. package/dist/docs/versioned/next/tasks/examples-demo-coverage.md +123 -17
  99. package/dist/docs/versioned/next/tasks/framework-audit-log.md +86 -0
  100. package/dist/docs/versioned/next/tasks/gpt-chat-mascot.md +13 -0
  101. package/dist/docs/versioned/next/tasks/job-queues.md +144 -0
  102. package/dist/docs/versioned/next/tasks/knip-cleanup.md +146 -0
  103. package/dist/docs/versioned/next/tasks/migrate-admin-to-syncdb.md +209 -0
  104. package/dist/docs/versioned/next/tasks/mongodb-migrations-tooling.md +107 -0
  105. package/dist/docs/versioned/next/tasks/notification-center.md +102 -0
  106. package/dist/docs/versioned/next/tasks/org-management-ui.md +14 -14
  107. package/dist/docs/versioned/next/tutorials/README.md +1 -1
  108. package/dist/docs/versioned/next/tutorials/getting-started.md +62 -22
  109. package/dist/help/excerpt.d.ts +2 -0
  110. package/dist/help/excerpt.d.ts.map +1 -0
  111. package/dist/help/excerpt.js +8 -0
  112. package/dist/help/excerpt.js.map +1 -0
  113. package/dist/help/updateNotes.d.ts +42 -0
  114. package/dist/help/updateNotes.d.ts.map +1 -0
  115. package/dist/help/updateNotes.js +235 -0
  116. package/dist/help/updateNotes.js.map +1 -0
  117. package/dist/index.js +1 -1
  118. package/dist/index.js.map +1 -1
  119. package/dist/local/tools/databaseQuery.d.ts +1 -0
  120. package/dist/local/tools/databaseQuery.d.ts.map +1 -1
  121. package/dist/local/tools/databaseQuery.js +1 -0
  122. package/dist/local/tools/databaseQuery.js.map +1 -1
  123. package/dist/packageGuidelines.d.ts +2 -2
  124. package/dist/packageGuidelines.d.ts.map +1 -1
  125. package/dist/packageGuidelines.js +2 -8
  126. package/dist/packageGuidelines.js.map +1 -1
  127. package/dist/resources.d.ts +3 -0
  128. package/dist/resources.d.ts.map +1 -1
  129. package/dist/resources.js +3 -0
  130. package/dist/resources.js.map +1 -1
  131. package/dist/search/chunker.d.ts +1 -0
  132. package/dist/search/chunker.d.ts.map +1 -1
  133. package/dist/search/chunker.js +1 -0
  134. package/dist/search/chunker.js.map +1 -1
  135. package/dist/search/docIndex.d.ts +1 -5
  136. package/dist/search/docIndex.d.ts.map +1 -1
  137. package/dist/search/docIndex.js +1 -0
  138. package/dist/search/docIndex.js.map +1 -1
  139. package/dist/search/docVersion.d.ts +2 -1
  140. package/dist/search/docVersion.d.ts.map +1 -1
  141. package/dist/search/docVersion.js +3 -1
  142. package/dist/search/docVersion.js.map +1 -1
  143. package/dist/tools.d.ts +2 -2
  144. package/dist/tools.d.ts.map +1 -1
  145. package/dist/tools.js +113 -2
  146. package/dist/tools.js.map +1 -1
  147. package/package.json +28 -27
  148. package/src/docs/guidelines/admin-frontend/guidelines/core.md +5 -1
  149. package/src/docs/guidelines/api/skills/mongoose-schema-safety/SKILL.md +23 -10
  150. package/src/docs/resources/syncdb.md +4 -1
  151. package/src/docs/upgrades/57.4.0.md +140 -0
  152. package/src/docs/versioned/next/README.md +3 -0
  153. package/src/docs/versioned/next/explanation/README.md +4 -1
  154. package/src/docs/versioned/next/explanation/admin-interface.md +20 -13
  155. package/src/docs/versioned/next/explanation/charts.md +29 -0
  156. package/src/docs/versioned/next/explanation/deployment-architecture-gcp.md +32 -0
  157. package/src/docs/versioned/next/explanation/deployment-baseline.md +1 -1
  158. package/src/docs/versioned/next/explanation/example-coverage.md +43 -0
  159. package/src/docs/versioned/next/explanation/local-first-data.md +5 -2
  160. package/src/docs/versioned/next/explanation/loop-engineering.md +9 -6
  161. package/src/docs/versioned/next/explanation/model-router-actions.md +19 -2
  162. package/src/docs/versioned/next/explanation/organizations.md +88 -0
  163. package/src/docs/versioned/next/explanation/planning-plugins.md +114 -0
  164. package/src/docs/versioned/next/explanation/positioning.md +3 -3
  165. package/src/docs/versioned/next/explanation/repository-settings.md +6 -5
  166. package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +44 -34
  167. package/src/docs/versioned/next/explanation/source-rules.md +1 -1
  168. package/src/docs/versioned/next/explanation/static-analysis.md +76 -16
  169. package/src/docs/versioned/next/how-to/README.md +10 -0
  170. package/src/docs/versioned/next/how-to/add-gpt-chat-mascot.md +92 -0
  171. package/src/docs/versioned/next/how-to/add-organizations.md +204 -0
  172. package/src/docs/versioned/next/how-to/admin-add-model.md +9 -1
  173. package/src/docs/versioned/next/how-to/admin-import-prebuilt.md +7 -1
  174. package/src/docs/versioned/next/how-to/audit-log.md +85 -0
  175. package/src/docs/versioned/next/how-to/background-jobs.md +296 -0
  176. package/src/docs/versioned/next/how-to/build-admin-screens.md +42 -13
  177. package/src/docs/versioned/next/how-to/charts-and-dashboards.md +37 -0
  178. package/src/docs/versioned/next/how-to/circleci.md +136 -27
  179. package/src/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +36 -0
  180. package/src/docs/versioned/next/how-to/configure-better-auth.md +4 -0
  181. package/src/docs/versioned/next/how-to/create-a-terreno-app.md +154 -0
  182. package/src/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +2 -0
  183. package/src/docs/versioned/next/how-to/github-actions-ci.md +4 -3
  184. package/src/docs/versioned/next/how-to/github-issue-lifecycle.md +12 -8
  185. package/src/docs/versioned/next/how-to/in-app-notifications.md +147 -0
  186. package/src/docs/versioned/next/how-to/install-agent-skills.md +24 -12
  187. package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +19 -3
  188. package/src/docs/versioned/next/how-to/product-announcements.md +155 -0
  189. package/src/docs/versioned/next/how-to/run-mongodb-migrations.md +127 -0
  190. package/src/docs/versioned/next/how-to/run-tests-locally.md +102 -0
  191. package/src/docs/versioned/next/how-to/seed-a-database.md +7 -2
  192. package/src/docs/versioned/next/implementationPlans/README.md +8 -5
  193. package/src/docs/versioned/next/implementationPlans/admin-scripts-durable-jobs.md +44 -0
  194. package/src/docs/versioned/next/implementationPlans/agent-ui-blocks.md +386 -0
  195. package/src/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +11 -8
  196. package/src/docs/versioned/next/implementationPlans/announcements-surfaces.md +231 -0
  197. package/src/docs/versioned/next/implementationPlans/announcements.md +289 -0
  198. package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +3 -1
  199. package/src/docs/versioned/next/implementationPlans/charts-and-dashboards.md +246 -0
  200. package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +4 -3
  201. package/src/docs/versioned/next/implementationPlans/create-terreno-app.md +177 -0
  202. package/src/docs/versioned/next/implementationPlans/datatable-server-side-filtering.md +219 -0
  203. package/src/docs/versioned/next/implementationPlans/examples-demo-coverage.md +17 -17
  204. package/src/docs/versioned/next/implementationPlans/framework-audit-log.md +247 -0
  205. package/src/docs/versioned/next/implementationPlans/gpt-chat-mascot.md +40 -0
  206. package/src/docs/versioned/next/implementationPlans/job-queues.md +330 -0
  207. package/src/docs/versioned/next/implementationPlans/knip-cleanup.md +136 -0
  208. package/src/docs/versioned/next/implementationPlans/migrate-admin-to-syncdb.md +210 -0
  209. package/src/docs/versioned/next/implementationPlans/mongodb-migrations-tooling.md +254 -0
  210. package/src/docs/versioned/next/implementationPlans/notification-center.md +185 -0
  211. package/src/docs/versioned/next/implementationPlans/org-management-ui.md +8 -3
  212. package/src/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -1
  213. package/src/docs/versioned/next/reference/README.md +4 -0
  214. package/src/docs/versioned/next/reference/admin-backend.md +83 -5
  215. package/src/docs/versioned/next/reference/admin-config.md +7 -0
  216. package/src/docs/versioned/next/reference/admin-frontend.md +178 -5
  217. package/src/docs/versioned/next/reference/admin-spa.md +18 -1
  218. package/src/docs/versioned/next/reference/ai.md +2 -0
  219. package/src/docs/versioned/next/reference/announcements.md +179 -0
  220. package/src/docs/versioned/next/reference/api.md +343 -4
  221. package/src/docs/versioned/next/reference/comms.md +33 -0
  222. package/src/docs/versioned/next/reference/create-terreno-app.md +44 -0
  223. package/src/docs/versioned/next/reference/environment-variables.md +29 -0
  224. package/src/docs/versioned/next/reference/jobs.md +319 -0
  225. package/src/docs/versioned/next/reference/legacy/rtk.md +5 -1
  226. package/src/docs/versioned/next/reference/lifecycle-plugin.md +29 -11
  227. package/src/docs/versioned/next/reference/mcp-server.md +2 -43
  228. package/src/docs/versioned/next/reference/scan-plugin.md +169 -0
  229. package/src/docs/versioned/next/reference/syncdb.md +38 -12
  230. package/src/docs/versioned/next/reference/test.md +57 -6
  231. package/src/docs/versioned/next/reference/ui-performance.md +2 -1
  232. package/src/docs/versioned/next/reference/ui.md +257 -3
  233. package/src/docs/versioned/next/tasks/admin-scripts-durable-jobs.md +10 -0
  234. package/src/docs/versioned/next/tasks/agent-ui-blocks.md +114 -0
  235. package/src/docs/versioned/next/tasks/announcements-surfaces.md +101 -0
  236. package/src/docs/versioned/next/tasks/announcements.md +173 -0
  237. package/src/docs/versioned/next/tasks/charts-and-dashboards.md +120 -0
  238. package/src/docs/versioned/next/tasks/create-terreno-app.md +82 -0
  239. package/src/docs/versioned/next/tasks/datatable-server-side-filtering.md +87 -0
  240. package/src/docs/versioned/next/tasks/examples-demo-coverage.md +123 -17
  241. package/src/docs/versioned/next/tasks/framework-audit-log.md +86 -0
  242. package/src/docs/versioned/next/tasks/gpt-chat-mascot.md +13 -0
  243. package/src/docs/versioned/next/tasks/job-queues.md +144 -0
  244. package/src/docs/versioned/next/tasks/knip-cleanup.md +146 -0
  245. package/src/docs/versioned/next/tasks/migrate-admin-to-syncdb.md +209 -0
  246. package/src/docs/versioned/next/tasks/mongodb-migrations-tooling.md +107 -0
  247. package/src/docs/versioned/next/tasks/notification-center.md +102 -0
  248. package/src/docs/versioned/next/tasks/org-management-ui.md +14 -14
  249. package/src/docs/versioned/next/tutorials/README.md +1 -1
  250. package/src/docs/versioned/next/tutorials/getting-started.md +62 -22
@@ -11,6 +11,8 @@ flowchart TD
11
11
  U["User<br/>iOS / Android / Web"]
12
12
  CDN["Cloud CDN + GCS bucket<br/>expo export -p web output"]
13
13
  CR["Cloud Run<br/>@terreno/api backend"]
14
+ CT["Cloud Tasks<br/>durable jobs push queue"]
15
+ JW["Cloud Run<br/>private jobs worker service"]
14
16
  SM["Secret Manager<br/>auth secrets, MONGO_URI"]
15
17
  AT["MongoDB Atlas<br/>replica set (change streams)"]
16
18
  GCS["GCS bucket<br/>user file uploads"]
@@ -21,6 +23,9 @@ flowchart TD
21
23
  CR --> SM
22
24
  CR --> AT
23
25
  CR --> GCS
26
+ CR -->|"enqueue"| CT
27
+ CT -->|"OIDC POST /jobs/execute"| JW
28
+ JW --> AT
24
29
  AR --> CR
25
30
  ```
26
31
 
@@ -30,6 +35,8 @@ flowchart TD
30
35
  |-----------|------|
31
36
  | **Artifact Registry** | Stores versioned backend container images built from `example-backend/Dockerfile` |
32
37
  | **Cloud Run** | Runs the long-lived `@terreno/api` process (HTTP + Socket.io) |
38
+ | **Cloud Tasks** | Dispatches persisted `@terreno/jobs` rows to an authenticated HTTP worker with queue-level concurrency limits |
39
+ | **Jobs worker service** | Runs the same example-backend image and job definitions; exposes only the Cloud Tasks execute callback through Cloud Run IAM |
33
40
  | **Secret Manager** | Holds `MONGO_URI`, JWT secrets, and other credentials — mounted as env vars |
34
41
  | **MongoDB Atlas** | Primary database; must be a replica set for change streams (realtime, feature flags) |
35
42
  | **GCS (web bucket)** | Serves static web export; CDN caches at the edge |
@@ -59,6 +66,31 @@ flowchart TD
59
66
 
60
67
  Native iOS and Android apps call Cloud Run directly; only the web client uses the CDN origin.
61
68
 
69
+ ## Durable jobs and PR isolation
70
+
71
+ Cloud Tasks is a push service; it does not expose a pull-consumer API. Cloud Run worker
72
+ pools do not have HTTP ingress, so the example uses a private Cloud Run service as the
73
+ execution pool. Queue rate limits bound dispatch concurrency and Cloud Run scales the
74
+ worker instances.
75
+
76
+ Production and PR revisions share one queue safely because every task stores its complete
77
+ callback URL. A PR backend targets the matching `pr-<number>` worker tag and uses
78
+ `terreno-example-pr-<number>` as its Mongo database. Removing a preview removes both
79
+ service tags. An old callback then fails closed instead of reaching production or another
80
+ PR. A failed backend preview tag cannot stay on a not-Ready revision: CD rebuilds traffic
81
+ from Ready tags, deploys the new revision without `--tag`, then tags it.
82
+
83
+ Every example-frontend PR preview is paired with this isolated backend, including
84
+ frontend-only PRs. The exported Netlify bundle targets the matching `pr-<number>` Cloud
85
+ Run tag, whose CORS configuration trusts only that preview origin. Preview clients never
86
+ fall back to the production backend or production database.
87
+
88
+ Queue IAM grants `cloudtasks.enqueuer` and `iam.serviceAccountUser` on
89
+ `terreno-jobs-invoker` only to `terreno-backend-runtime`, the example API Cloud Run
90
+ identity. The project default Compute Engine SA (MCP and any other service that omits a
91
+ runtime identity) cannot create tasks that present that OIDC token. The worker remains
92
+ invokable only by `terreno-jobs-invoker`.
93
+
62
94
  ## Related
63
95
 
64
96
  - [Deployment baseline](deployment-baseline.md) — seven requirements every host must satisfy
@@ -73,6 +73,6 @@ Three details consumers get wrong:
73
73
 
74
74
  - **`PORT`** — Cloud Run and other platforms assign the listen port via `PORT`. Terreno reads `process.env.PORT` in `api/src/terrenoApp.ts` (default `9000` if unset).
75
75
  - **Non-root** — Do not run the container as root in production.
76
- - **Compile order** — Workspace packages (`@terreno/api`, `@terreno/test`, etc.) must compile before the example backend bundles.
76
+ - **Compile order** — Workspace packages (`@terreno/api`, `@terreno/jobs`, `@terreno/test`, etc.) must compile before the example backend bundles. Compile `@terreno/jobs` before `@terreno/admin-backend` — admin-backend imports jobs. The image `exports` point at `dist/`, so skipping a workspace compile fails `bun build --compile` with an unresolved `@terreno/*` import.
77
77
 
78
78
  CI builds the image on every PR that touches backend paths (`.github/workflows/example-backend-docker.yml`).
@@ -0,0 +1,43 @@
1
+ # Example app coverage
2
+
3
+ The `example-backend` and `example-frontend` apps are the living checklist for
4
+ framework capabilities. When you add a capability to `@terreno/*`, update this
5
+ matrix in the same slice.
6
+
7
+ Citations are paths from the repository root. A "yes" means a reader can follow
8
+ that file (and its imports) to a working example. Gaps stay explicit.
9
+
10
+ ## Capability matrix
11
+
12
+ | Capability | example-backend | example-frontend | Notes |
13
+ | --- | --- | --- | --- |
14
+ | `modelRouter` CRUD | yes — `example-backend/src/api/todos.ts` | yes — `example-frontend/components/SyncTodosScreen.tsx` (syncdb hooks generated from the same collection) | Todos are synced; list/create/update/delete go through `@terreno/syncdb`, not RTK collection hooks. |
15
+ | Owner permissions | yes — `OwnerQueryFilter` + `Permissions.IsOwner` in `example-backend/src/api/todos.ts` | yes — the todos screen only shows the signed-in user's rows after sync scopes apply | Also gated by RBAC `access: {resource: "todo"}`. |
16
+ | Admin panel (embedded) | yes — Admin plugin registration in `example-backend/src/server.ts` | yes — `example-frontend/app/admin/` | Expo routes wrap `@terreno/admin-frontend` screens. |
17
+ | Admin SPA | yes — `AdminSpaServeApp` in `example-backend/src/server.ts` | n/a | Standalone SPA is served from the backend; not a frontend route. |
18
+ | AI streaming chat | yes — `example-backend/src/api/ai.ts` (`addGptRoutes`) | yes — `example-frontend/app/(tabs)/ai.tsx` (`GPTChat`, optional `mascot`) | Empty-chat mascot is consumer-owned; the example fox is not a framework default. |
19
+ | AI structured output | no | no | `@terreno/ai` supports structured generation; the example only streams chat. Recorded gap — not claimed by a current tutorial. |
20
+ | Feature flags + live updates | yes — `FeatureFlagsApp` in `example-backend/src/server.ts`, seed `example-backend/src/scripts/seed-feature-flags.ts` | yes — `useTerrenoFeatureFlags` in `example-frontend/app/_layout.tsx` | Socket-backed live updates share the realtime connection. |
21
+ | Websockets / realtime | yes — `RealtimeApp` in `example-backend/src/server.ts`, `example-backend/src/websockets.ts` | yes — `useSocketConnection` in `example-frontend/app/_layout.tsx` | Sync deltas also use the socket (`SyncApp` + `@terreno/syncdb`). |
22
+ | Consent forms | yes — `example-backend/src/consentDefinitions.ts`, seed scripts | yes — `example-frontend/app/(tabs)/consents.tsx`, admin `example-frontend/app/admin/consent-forms/` | First-login flow is covered by e2e (`example-frontend/e2e/consents.spec.ts`). |
23
+ | File upload / GCS | yes — `example-backend/src/api/settings.ts`, AI file routes in `example-backend/src/api/ai.ts` | yes — `example-frontend/app/(tabs)/files.tsx`, `example-frontend/app/gcs-settings.tsx` | |
24
+ | Better Auth | yes — `example-backend/src/utils/betterAuthConfig.ts`, `BetterAuthApp` in `example-backend/src/server.ts` | yes — `example-frontend/app/login.tsx`, `example-frontend/lib/betterAuth.ts` | Default `AUTH_PROVIDER` is `better-auth`. |
25
+ | syncdb local-first | yes — `SyncApp` in `example-backend/src/server.ts` | yes — `example-frontend/store/syncdb.ts`, `example-frontend/app/(tabs)/index.tsx` | PR #869 closed without merge; `@terreno/syncdb` shipped on the launch line and is the example todos path. |
26
+ | RBAC | yes — `example-backend/src/rbacRoles.ts`, `access.ts`, `access: {resource: "todo"}` on the todo router | yes — `example-frontend/app/admin/roles.tsx` | Shipped. The IP snapshot that marked RBAC "not shipped" is stale. Plan: [rbac-permissions.md](../implementationPlans/rbac-permissions.md). |
27
+ | Organizations | yes — `createAccess({organizations: true})`, `organizationSettingsSchema`, `orgScopedPlugin` on projects | yes — admin org directory/settings at `example-frontend/app/admin/orgs/` | Settings live on `Organization.settings`; example registers a nested timezone schema. |
28
+ | Background jobs | no | no | No generic job queue example. Admin maintenance scripts (`example-backend/src/adminScripts.ts`, script runner widget) are a related but different surface. Plan: [admin-script-runner.md](../implementationPlans/admin-script-runner.md). |
29
+
30
+ ## Gaps
31
+
32
+ | Gap | Why it stays | Follow-up |
33
+ | --- | --- | --- |
34
+ | AI structured output | Chat streaming already demonstrates the AI pillar; structured `generateObject`-style routes are unused by current tutorials | Track with [AI-first tutorials #1010](https://github.com/FlourishHealth/terreno/issues/1010) (`add-ai-features.md` requires one structured-output call). |
35
+ | Generic background jobs | Unshipped as a first-class example; do not invent a queue UI here | Track with [Durable background jobs #1188](https://github.com/FlourishHealth/terreno/issues/1188). Admin script runner is a related surface — [admin-script-runner.md](../implementationPlans/admin-script-runner.md). |
36
+
37
+ ## Keeping the matrix true
38
+
39
+ When you add a framework capability:
40
+
41
+ 1. Exercise it in `example-backend` and/or `example-frontend`.
42
+ 2. Update this page (cite the file).
43
+ 3. Mention the example in the PR.
@@ -27,7 +27,10 @@ Think **apply locally, then reconcile** instead of **request, wait, update cache
27
27
  3. **Refetch orchestration** — `invalidatesTags`, `refetch()`, and list/detail cache coordination after mutations.
28
28
  4. **Treating the network as the read path** — list screens blocked on `isLoading` for every navigation.
29
29
 
30
- RTK Query remains appropriate for **non-synced** endpoints: `/auth/me`, admin RPC, AI routes, and anything that should stay request/response.
30
+ RTK Query remains appropriate for **non-synced generated** endpoints such as
31
+ `/auth/me` and AI routes. Built-in admin RPC stays request/response through its
32
+ host-bound fetch client; ObjectId/API-only admin CRUD keeps RTK compatibility in
33
+ Terreno 57.
31
34
 
32
35
  ## What you start doing
33
36
 
@@ -35,7 +38,7 @@ RTK Query remains appropriate for **non-synced** endpoints: `/auth/me`, admin RP
35
38
  2. **Sync-status UX** — Surface offline state, queued mutations, and drain progress with `useSyncStatus` (and optionally `SyncStatusBanner`).
36
39
  3. **Encryption at rest (web)** — Web persistence uses AES-GCM via the default `createServerKeyProvider`; understand key fetch and `onDecryptFailure` for support flows.
37
40
  4. **Key lifecycle on logout** — Call `syncDb.stop()` and consider `wipeLocalData` when the authenticated user changes so one account does not read another's local store.
38
- 5. **Backend sync registration** — Every synced collection needs `syncPlugin`, `isDeletedPlugin`, and a `sync` block on `modelRouter`, plus `SyncApp` and `RealtimeApp` on the server.
41
+ 5. **Backend sync registration** — Every synced collection needs `syncPlugin`, `isDeletedPlugin`, and a `sync` block on `modelRouter`, plus `SyncApp` and `RealtimeApp` on the server. Optional `sync.adminBroadcast: true` also emits `sync:delta` to `{collection}|admin`. Admin clients subscribe with `mode: "window"` (`createSyncDb({windowCollections})`) so they do not snapshot or reconcile that collection; they call `hydrateWindow` (REST membership ids + `GET /sync/entities`). Pass the same `accessControl` into `SyncApp` that `AdminApp` uses so `{collection}|admin` requires `admin:access`. `AdminApp.register` also installs that model's admin list/read/`queryFilter` on the admin window so hydrate and live `|admin` deltas match `/admin` REST. Without RBAC, `user.admin` is enough for the shell gate. Live deltas on that stream apply only to ids already in the window; Refresh is a REST re-query plus `hydrateWindow`.
39
42
 
40
43
  ## Tradeoffs
41
44
 
@@ -49,8 +49,10 @@ the inner loop until the approved task list is done. Roast never invokes Pick. B
49
49
  Taste additionally wait while async review bots are running, preferring provider CLI
50
50
  watch hooks or harness event subscriptions over timer polling. Taste also waits in a
51
51
  loop for product CI with `gh` or `circleci` until jobs are terminal or the wait times
52
- out. Before any push it always pulls latest `master`, then lints in a no-context
53
- subagent, then pushes and watches CI.
52
+ out. Before any push it always pulls latest `master`, then records last-run failed tests
53
+ and re-verifies them locally, then runs the repository's root
54
+ `prepush` package script in a no-context subagent when present (falling back to affected
55
+ package lint, typecheck, and tests), then pushes and watches CI.
54
56
 
55
57
  Invocable outer loops in the plugin:
56
58
 
@@ -81,9 +83,10 @@ daemon. It waits until async review bots (Bugbot, CodeQL, and similar) on the cu
81
83
  head have reported, then waits in a loop for product CI using GitHub CLI
82
84
  (`gh pr checks --watch`, `gh run watch`) or CircleCI CLI (`circleci run watch`) until
83
85
  jobs are terminal or the wait times out. Before any push it always pulls latest
84
- `master`, then proves lint, typecheck, and affected tests in a fresh subagent with no
85
- parent conversation, then pushes and watches CI. It emits `PASS`, `FAIL`, `BLOCKED`, or
86
- `PENDING`, and exits.
86
+ `master`, records last-run failed tests and re-verifies them locally, then runs root
87
+ `prepush` when present in a fresh subagent with no parent
88
+ conversation. If absent, it proves affected-package lint, typecheck, and tests instead.
89
+ It then pushes and watches CI, emits `PASS`, `FAIL`, `BLOCKED`, or `PENDING`, and exits.
87
90
 
88
91
  Brew review-bot waits use only hooks targeted to the matched bot so ordinary CI cannot
89
92
  extend Brew. Taste's product-CI wait uses unfiltered GitHub/CircleCI watches on purpose.
@@ -118,7 +121,7 @@ include:
118
121
  | UI/app | `terreno-ui`, `building-terreno-apps`, `verify-ui-changes` |
119
122
  | AI/prompts | `ai-prompt-governance` |
120
123
  | Docs/submission | `update-docs`, Brew, `fix-conflicts` |
121
- | GitHub issues | `create-github-issue`, `work-github-issues`, `implement-ready-for-dev` (Pick plan comment is the Roast contract) |
124
+ | GitHub issues | `create-github-issue`, `work-github-issues`, `implement-ready-for-dev` (Pick plan comment is the Roast contract; unattended Grow may also write an IP) |
122
125
  | Deployment/runtime | `deploy-gcp`, Expo deployment/workflow skills |
123
126
 
124
127
  This inventory is descriptive, not a plugin dependency list. Stages inspect the actual
@@ -6,18 +6,35 @@ CRUD **create, update, and delete** (not named actions) share one write pipeline
6
6
 
7
7
  ## When to use actions
8
8
 
9
+ Use `collectionActions` / `instanceActions` for every application GET or POST that is not
10
+ plain document CRUD. Do **not** register `app.get`, `app.post`, `router.get`, or
11
+ `router.post` for those endpoints.
12
+
9
13
  Use actions when an endpoint performs an operation that is not a plain create/read/update/delete on the model document:
10
14
 
11
15
  - **Collection scope** (`POST /todos/bulkComplete`) — operate on many documents or the collection as a whole.
12
16
  - **Instance scope** (`POST /todos/:id/markComplete`) — operate on one loaded document.
13
17
 
14
- Use [custom routes with `createOpenApiBuilder`](./modular-api-design.md) when the URL does not fit the `/:id/{actionName}` or `/{actionName}` pattern.
18
+ Leave Express `app.get` / `app.post` only for:
19
+
20
+ - Inbound webhooks (`WebhooksApp`)
21
+ - Static SPA / file serving
22
+ - Framework auth, health, and version-check plugins
23
+ - SSE or other streaming handlers that write the response themselves
24
+ - Tests and harnesses
25
+
26
+ PATCH and DELETE are CRUD (or a POST action that performs the same work). Do not add a
27
+ hand-rolled DELETE next to a modelRouter.
28
+
29
+ Use [custom routes with `createOpenApiBuilder`](./modular-api-design.md) only when the
30
+ URL cannot be `/{actionName}` or `/:id/{actionName}` **and** the exceptions above do not
31
+ apply.
15
32
 
16
33
  ## Example
17
34
 
18
35
  ```typescript
19
36
  import {modelRouter, Permissions, z} from "@terreno/api";
20
- import {Todo} from "../models";
37
+ import {Todo} from "../models/todo";
21
38
 
22
39
  export const todoRouter = modelRouter("/todos", Todo, {
23
40
  permissions: {
@@ -0,0 +1,88 @@
1
+ # How organization tenancy works
2
+
3
+ Terreno treats organizations as an optional framework primitive. Existing
4
+ single-tenant apps do not pay a migration or authorization cost; multi-tenant
5
+ apps opt in at the access, application, model, and admin layers. New apps
6
+ generated by `create-terreno-app` opt in by default.
7
+
8
+ ## Identity and authorization layers
9
+
10
+ Platform and tenant authority are separate:
11
+
12
+ | Authority | Storage | Scope |
13
+ | --- | --- | --- |
14
+ | `superadmin` | `User.roles` | Every framework permission |
15
+ | `operator` | `User.roles` | Organization directory and every organization |
16
+ | `org-admin` | `Membership.roleName` | One organization |
17
+ | `member` | `Membership.roleName` | One organization; app permissions decide actions |
18
+
19
+ `user.admin` does not imply operator access. `org-admin` is deliberately not a
20
+ global RBAC role: putting it on `User.roles` grants nothing. During an
21
+ organization request, `createAccess({organizations: true})` adds the current
22
+ active Membership grants to the normal role permissions.
23
+
24
+ ## Request context
25
+
26
+ Tenant routes resolve `X-Organization-Id` after authentication. An operator or
27
+ superadmin may enter any organization but must choose one. An org-admin with
28
+ exactly one administered organization may omit the header; Terreno infers it.
29
+ Ambiguous or unauthorized context fails before model queries run.
30
+
31
+ The resolved organization and membership are stored in AsyncLocalStorage as
32
+ well as `req.organization` / `req.membership`. This lets `OrgQueryFilter` add
33
+ the server-owned organization id without trusting a client query parameter.
34
+
35
+ ## Isolation boundaries
36
+
37
+ Tenant isolation uses multiple checks rather than one convention:
38
+
39
+ 1. `orgContextMiddleware({required: true})` rejects missing or unauthorized context.
40
+ 2. `OrgQueryFilter` ANDs the selected organization into list and search queries.
41
+ 3. `Permissions.IsOrganizationMember` rejects cross-org object reads and writes.
42
+ 4. Create hooks overwrite client-supplied organization ids.
43
+ 5. `orgScopedPlugin` rejects any post-create change to `organizationId` (REST, admin, sync, direct save).
44
+ 6. Sync scopes resolve active Membership rows and partition streams by organization.
45
+
46
+ `AdminApp({organizations: true})` applies these boundaries automatically to
47
+ admin models whose schema contains `organizationId`. Models without that path
48
+ remain platform-scoped.
49
+
50
+ ## Disabled organizations
51
+
52
+ When `Organization.disabled` is `true`, tenant context and membership mutations
53
+ stop, but operators can still manage the organization record itself:
54
+
55
+ | Surface | Disabled org behavior |
56
+ | --- | --- |
57
+ | `orgContextMiddleware` / inferred org context | 403 `Organization is disabled` |
58
+ | `GET /orgs/mine` | Disabled orgs omitted from the switcher list |
59
+ | `GET /orgs` (operator directory) | Disabled orgs still listed |
60
+ | `GET` / `PATCH /orgs/:id` | Allowed (operators use `PATCH` with `disabled: false` to re-enable) |
61
+ | `POST` / `PATCH` / `DELETE /orgs/:id/members` | 403 while disabled |
62
+ | Soft-deleted orgs | Still 404 everywhere |
63
+
64
+ Disabling or deleting an organization suspends its memberships. Re-enabling does
65
+ not automatically reactivate them.
66
+
67
+ ## Why organizations are optional
68
+
69
+ Automatically registering routes, roles, or Mongoose models would change
70
+ existing apps merely because they upgraded `@terreno/api`. Instead:
71
+
72
+ - `createAccess` omits Membership grants and the `operator` seed unless
73
+ `organizations: true`;
74
+ - `TerrenoApp` does not mount `/orgs` unless organizations are enabled;
75
+ - `AdminApp` does not scope models unless organizations are enabled;
76
+ - Organization and Membership Mongoose models register lazily on first use.
77
+ Apps add fields to `Organization.settings` with `createOrganizationSettingsSchema`
78
+ and `registerOrganizationSettings`, not by replacing the Organization model.
79
+
80
+ This keeps upgrades backward compatible while letting bootstrap generate
81
+ multi-tenant-ready apps.
82
+
83
+ ## Related
84
+
85
+ - [Add organizations](../how-to/add-organizations.md)
86
+ - [API reference](../reference/api.md#organizations)
87
+ - [Admin backend reference](../reference/admin-backend.md#organization-scoping)
88
+ - [Admin frontend reference](../reference/admin-frontend.md#orgdirectoryscreen)
@@ -0,0 +1,114 @@
1
+ # Planning plugins
2
+
3
+ Terreno ships its agentic workflows as **two host plugins**. They divide along one line:
4
+ the lifecycle plugin knows *how to build one approved thing correctly*, and the scan
5
+ plugin knows *what is worth building next and whether it worked*.
6
+
7
+ ```text
8
+ terreno-scan terreno (lifecycle)
9
+ ------------ -------------------
10
+ Aim charter a measurable goal
11
+ Sweep shard + map the repository
12
+ Sift reduce to verified findings
13
+ Plot slice findings into briefs ───► Grow shape IP + tasks
14
+ Pick ⇄ Roast build and prove
15
+ Brew submit the PR
16
+ Taste react to CI and review
17
+ Track re-measure, close findings ◄─── (merged)
18
+ ```
19
+
20
+ A scan never edits product code. The lifecycle never decides what the repository should
21
+ become. Every slice crosses that boundary exactly once, as an approved IP and task list.
22
+
23
+ ## terreno (lifecycle plugin)
24
+
25
+ Five bounded transitions plus three outer loops. Canonical source:
26
+ `plugins/terreno-planning/`; Claude Code consumes the generated `plugins/terreno-claude/`.
27
+
28
+ | Stage | Owns | PASS next |
29
+ | --- | --- | --- |
30
+ | Grow | Research, grilling, approved IP and dependency-aware task list, criterion → verification map | Pick |
31
+ | Pick | Implement one task, then Roast it, then take the next until the list is done | Roast, or Brew when done |
32
+ | Roast | Independently prove the current task against its criteria | Pick if tasks remain, else Brew |
33
+ | Brew | Final checks, commit, push, PR, evidence, CI trigger, wait for review bots | Taste |
34
+ | Taste | One reaction to the current head: bots, CI on every host, conflicts, comments | null or fresh Taste |
35
+
36
+ | Outer loop | Walks |
37
+ | --- | --- |
38
+ | `pick-roast-loop` | An approved plan through every Pick/Roast retry, one ledger, stop only at completion or a genuine human gate |
39
+ | `planning-loop` | Grow/Pick/Brew/Taste, restrictable with `phases=` |
40
+ | `taste-sweep` | Every open PR of yours that is conflicting or failing, until each is mergeable |
41
+
42
+ Full contract: [lifecycle plugin reference](../reference/lifecycle-plugin.md) and
43
+ [loop engineering](loop-engineering.md).
44
+
45
+ ## terreno-scan (scan plugin)
46
+
47
+ Five bounded transitions plus two outer loops. Canonical source: `plugins/terreno-scan/`;
48
+ Claude Code consumes the generated `plugins/terreno-scan-claude/`. It depends on the
49
+ lifecycle plugin — Plot hands every slice to Grow.
50
+
51
+ | Stage | Owns | PASS next |
52
+ | --- | --- | --- |
53
+ | Aim | Charter: metric with a command, measured baseline, dry-run detection rules, exclusions, validity rule, severity rubric, slice policy, review routing, budget | Sweep |
54
+ | Sweep | Run the rules, shard hits deterministically, map fresh workers into candidate findings | Sift |
55
+ | Sift | Dedupe, adversarially verify, drop what does not reproduce, rank, write the findings report | Plot, or Track when dry |
56
+ | Plot | Slice findings into PR-sized units with standalone Grow briefs | Track, handing off to Grow |
57
+ | Track | Re-measure the metric, close or reopen findings with evidence, record the round, choose the next move | Plot, Sweep, or null |
58
+
59
+ | Outer loop | Walks |
60
+ | --- | --- |
61
+ | `campaign` | Bounded rounds: Aim → Sweep → Sift → Plot → lifecycle → Track. Stops at every gate. |
62
+ | `loop` | Resident session: the same rounds, plus a heartbeat over open campaign PRs — route, answer review through Taste, fix red CI, Track merges — refilling work up to `wipLimit`. |
63
+
64
+ Full contract: [scan plugin reference](../reference/scan-plugin.md).
65
+
66
+ ## Which one to invoke
67
+
68
+ | Situation | Start with |
69
+ | --- | --- |
70
+ | You know what to build | `1-grow` |
71
+ | You have an approved plan and want it built | `pick-roast-loop` |
72
+ | A PR of yours is red or conflicting | `5-taste`, or `taste-sweep` for all of them |
73
+ | You know the outcome you want, not the work | `scan 1-aim` |
74
+ | You want that outcome pursued unattended | `scan loop` |
75
+
76
+ ## What each plugin persists
77
+
78
+ | Artifact | Owner | Committed |
79
+ | --- | --- | --- |
80
+ | IP and task list | Grow | yes |
81
+ | Execution state (`.terreno/pipeline/<slug>.json`) | Lifecycle outer loops | no |
82
+ | Charter (`docs/scans/<goal>/charter.md`) | Aim | yes |
83
+ | Findings report (`docs/scans/<goal>/round-<n>-findings.md`) | Sift | yes |
84
+ | Campaign state (`.terreno/scan/<goal>.json`) | Scan outer loops | no |
85
+
86
+ Both plugins emit the same shaped result — `v: 2`, `status` of `PASS` / `FAIL` /
87
+ `BLOCKED` / `PENDING`, a `next`, and a concrete `action` — in a collapsed details block,
88
+ with `status` / `next` / `action` as the visible lines. Neither persists
89
+ chain-of-thought.
90
+
91
+ ## Why the split
92
+
93
+ Three properties fall out of keeping discovery and delivery in separate plugins:
94
+
95
+ - **A finding must earn its slice.** Sift drops anything that cannot be tied to the
96
+ goal metric, so the lifecycle only ever receives work with a stated payoff.
97
+ - **Delivery rules stay in one place.** Review response, CI waiting, the pre-push gate,
98
+ and documentation obligations live in the lifecycle, so a scan cannot invent a
99
+ shortcut around them.
100
+ - **Progress is measured, not asserted.** Track re-runs the metric command after the
101
+ work merges, so "we improved it" is always a number with its command output.
102
+
103
+ ## Hosts
104
+
105
+ | Host | Lifecycle | Scan |
106
+ | --- | --- | --- |
107
+ | Cursor | `terreno-planning`, `/terreno-1-grow` | `terreno-scan`, `/terreno-scan-1-aim` |
108
+ | Codex | `terreno-planning`, `$terreno-1-grow` | `terreno-scan`, `$terreno-scan-1-aim` |
109
+ | Claude Code | `terreno`, `/terreno:1-grow` | `terreno-scan`, `/terreno-scan:1-aim` |
110
+
111
+ Install both from the marketplaces described in
112
+ [install agent skills](../how-to/install-agent-skills.md). Claude Code resolves a plugin
113
+ skill's command from its frontmatter `name`, which is why the two `*-claude/` trees are
114
+ generated with shortened names by `bun run skills:sync`.
@@ -103,8 +103,8 @@ your codebase is the 20% that is unique to your product.
103
103
 
104
104
  The analogy earns two honest caveats. First, Terreno targets a document store
105
105
  (MongoDB via Mongoose), not a relational ORM, and it has no migrations framework.
106
- Second, it is younger — several Django/Rails staples (background jobs,
107
- server-side rendering, role-based access control) are not shipped yet. The
106
+ Second, it is younger — several Django/Rails staples (server-side rendering,
107
+ role-based access control) are not shipped yet. The
108
108
  comparison table below is deliberately straight about where the analogy holds and
109
109
  where it does not; being honest about the gaps is what makes the analogy credible
110
110
  rather than marketing.
@@ -125,7 +125,7 @@ shipped" row links the implementation plan or roadmap item that tracks it.
125
125
  | Auth + permissions | Better Auth (`api/src/betterAuthApp.ts`) + `Permissions` (`api/src/permissions.ts`) | Fine-grained RBAC is in progress ([`rbac-permissions`](../implementationPlans/rbac-permissions.md)) |
126
126
  | Templates / views | `@terreno/ui` components — one universal codebase for iOS, Android, and web | Server-side rendering for web is not shipped yet ([`web-ssr-and-admin-spa`](../implementationPlans/web-ssr-and-admin-spa.md)) |
127
127
  | `manage.py` / generators | MCP server tools — the *tool* layer (`mcp-server/src/tools.ts`) + the `/terreno-*` SDLC pipeline — the *process* layer (`plugins/terreno-planning/skills/`) | Agent-driven rather than CLI-driven; the pipeline is not yet packaged for consumer apps ([`agentic-sdlc-plugin`](../implementationPlans/agentic-sdlc-plugin.md) Task 2.5) |
128
- | Celery / ActiveJob (background jobs) | Not shipped | On the [roadmap](../../ROADMAP.md) |
128
+ | Celery / ActiveJob (background jobs) | `@terreno/jobs` `JobsApp` (`jobs/`) | [How-to](../how-to/background-jobs.md), [reference](../reference/jobs.md); optional GCP Cloud Tasks and Vercel Queues runners |
129
129
  | Migrations | No migrations framework | Schema evolution is convention plus the published `mongoose-schema-safety` skill |
130
130
 
131
131
  ## Language rules
@@ -31,8 +31,9 @@ descriptions):
31
31
  **Path:** Settings → Branches → Branch protection rules → `master`
32
32
 
33
33
  - Require a pull request before merging
34
- - Require status checks to pass (include Repository policies, package CI, and
35
- Rulesync Check jobs relevant to the change)
34
+ - Require status checks to pass (include CircleCI `repo-policies`, package CI,
35
+ and Rulesync Check jobs relevant to the change — see the check name map in
36
+ [how-to/circleci.md](../how-to/circleci.md))
36
37
  - Require branches to be up to date before merging
37
38
  - Do not allow bypassing the above settings
38
39
 
@@ -50,9 +51,9 @@ as GitHub App checks; they are not CircleCI jobs.
50
51
 
51
52
  **Path:** Settings → Environments
52
53
 
53
- Same-repo PR jobs in `cd.yml` (`Terraform preview`, `Backend deploy (preview)`)
54
- skip when `head.repo.full_name != github.repository`. Also restrict the
55
- `gcp-cd-preview` environment (create it on first deploy if missing) with a
54
+ Same-repo PR jobs in `cd.yml` (`Terraform preview`, `Tasks deploy (preview)`,
55
+ `Backend deploy (preview)`) skip when `head.repo.full_name != github.repository`.
56
+ Also restrict the `gcp-cd-preview` environment (create it on first deploy if missing) with a
56
57
  **deployment branch policy** or **required reviewers** so a fork that edits
57
58
  `cd.yml` cannot mint a prod WIF token.
58
59
 
@@ -553,7 +553,9 @@ org-admins manage only the current org. Invites and billing are design-only plac
553
553
 
554
554
  - **Implementation plan:** [org-management-ui.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/org-management-ui.md)
555
555
  - **Tasks:** [org-management-ui.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/org-management-ui.md)
556
- - **RTK flag:** Partial — admin screens use generated SDK / `useAdminApi`
556
+ - **RTK flag:** Partial — custom non-synced routes use the generated SDK;
557
+ ObjectId admin compatibility may use `useAdminApi` in Terreno 57, while
558
+ eligible String-`_id` CRUD uses windowed syncdb
557
559
  - **Depends on:** rbac-permissions
558
560
 
559
561
  ---
@@ -605,15 +607,15 @@ same binary. Manifest finalized 2026-08-09 (decisions D1/D3/D7); TenTap excluded
605
607
  **Title:** `create-terreno-app scaffolding CLI`
606
608
 
607
609
  **Labels:** `area:dx`, `type:feature`
608
- **Project fields:** Area=`dx`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
610
+ **Project fields:** Area=`dx`, Target=`Next`, Impact=`Feature`, IP=`create-terreno-app`, Status=`In progress`
609
611
 
610
612
  Today the MCP bootstrap tool returns markdown instructions and writes no files. This ships
611
613
  a real `create-terreno-app` CLI (or template repo) that produces a running, deployable app
612
614
  — backend, Expo app, env files, seeded auth — in one command, with the MCP bootstrap
613
615
  delegating to it.
614
616
 
615
- - **Implementation plan:** *(not yet written)*
616
- - **Tasks:** *(not yet written)*
617
+ - **Implementation plan:** [create-terreno-app.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/create-terreno-app.md)
618
+ - **Tasks:** [create-terreno-app.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/create-terreno-app.md)
617
619
  - **RTK flag:** Partial — scaffold output follows the syncdb + Better Auth direction
618
620
  - **Depends on:** deployment-foundation
619
621
 
@@ -624,15 +626,14 @@ delegating to it.
624
626
  **Title:** `Charts and dashboard primitives`
625
627
 
626
628
  **Labels:** `area:ui`, `type:feature`
627
- **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
629
+ **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=`charts-and-dashboards`, Status=`In progress`
628
630
 
629
- `@terreno/ui` has a stubbed `Chart` export and no implementation. Adds themed chart
630
- components (line, bar, area, donut) on `victory-native` — JS-only, since its Skia /
631
- Reanimated / Gesture Handler peers are already linked — plus a simple dashboard grid
632
- layout, with demo stories and docs.
631
+ `@terreno/ui` ships themed `LineChart`, `BarChart`, `AreaChart`, `DonutChart` on owned
632
+ `react-native-svg` (not `victory-native`) plus `DashboardGrid`. Demo stories and Diátaxis
633
+ docs are the proof; comms admin stats consume these primitives later.
633
634
 
634
- - **Implementation plan:** *(not yet written)*
635
- - **Tasks:** *(not yet written)*
635
+ - **Implementation plan:** [charts-and-dashboards.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/charts-and-dashboards.md)
636
+ - **Tasks:** [charts-and-dashboards.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/charts-and-dashboards.md)
636
637
  - **RTK flag:** None
637
638
  - **Depends on:** —
638
639
 
@@ -662,14 +663,14 @@ root views and system chrome follow the scheme.
662
663
  **Title:** `DataTable server-side filtering and search`
663
664
 
664
665
  **Labels:** `area:ui`, `type:feature`
665
- **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
666
+ **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=`datatable-server-side-filtering`, Status=`Planned`
666
667
 
667
668
  DataTable sorts and paginates but has no filter UI. Adds per-column filter controls and a
668
669
  search box that emit modelRouter-compatible query params (`queryFields`, `$and`/`$or`), so
669
670
  list screens get server-side filtering without custom plumbing. Admin tables adopt it.
670
671
 
671
- - **Implementation plan:** *(not yet written)*
672
- - **Tasks:** *(not yet written)*
672
+ - **Implementation plan:** [datatable-server-side-filtering.md](../implementationPlans/datatable-server-side-filtering.md)
673
+ - **Tasks:** [datatable-server-side-filtering.md](../tasks/datatable-server-side-filtering.md)
673
674
  - **RTK flag:** Partial — query wiring examples depend on the frontend data layer
674
675
  - **Depends on:** —
675
676
 
@@ -699,14 +700,14 @@ native module baseline regardless, so this lands as a JS/OTA feature when schedu
699
700
  **Title:** `In-app notification center`
700
701
 
701
702
  **Labels:** `area:ui`, `type:feature`
702
- **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
703
+ **Project fields:** Area=`ui`, Target=`Next`, Impact=`Feature`, IP=`notification-center` (Approved), Status=`Planned`
703
704
 
704
705
  Adds a Notification model with per-user preferences, realtime delivery over the existing
705
706
  change-stream socket layer, and a bell/inbox UI in `@terreno/ui` with read/unread state —
706
707
  the in-app channel beside `@terreno/comms` mail/SMS/push.
707
708
 
708
- - **Implementation plan:** *(not yet written)*
709
- - **Tasks:** *(not yet written)*
709
+ - **Implementation plan:** [notification-center.md](../implementationPlans/notification-center.md)
710
+ - **Tasks:** [notification-center.md](../tasks/notification-center.md)
710
711
  - **RTK flag:** Partial — inbox screens target the syncdb data layer where available
711
712
  - **Depends on:** comms-abstraction
712
713
 
@@ -826,17 +827,20 @@ enforcement hooks in the permission layer.
826
827
  **Title:** `Framework-level audit log`
827
828
 
828
829
  **Labels:** `area:api`, `type:feature`
829
- **Project fields:** Area=`api`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
830
+ **Project fields:** Area=`api`, Target=`Next`, Impact=`Feature`, IP=`framework-audit-log`, Status=`Planned`
830
831
 
831
832
  Generalizes the admin/consent audit patterns into a first-class audit log: an AuditEvent
832
833
  model, modelRouter hooks that record who changed what (with before/after diffs), org
833
834
  scoping, retention policy, and an admin viewer — a hard requirement for compliance-minded
834
835
  B2B customers.
835
836
 
836
- - **Implementation plan:** *(not yet written)*
837
- - **Tasks:** *(not yet written)*
837
+ Shipping this work **closes** https://github.com/FlourishHealth/terreno/issues/1186.
838
+
839
+ - **Implementation plan:** [framework-audit-log.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/framework-audit-log.md)
840
+ - **Tasks:** [framework-audit-log.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/framework-audit-log.md)
841
+ - **How-to:** [audit-log.md](../how-to/audit-log.md)
838
842
  - **RTK flag:** None
839
- - **Depends on:** org-management-ui
843
+ - **Depends on:** — (optional `organizationId` now; org-admin list filter waits on org-management-ui)
840
844
 
841
845
  ---
842
846
 
@@ -866,15 +870,19 @@ Shipping this work **closes** https://github.com/FlourishHealth/terreno/issues/1
866
870
  **Title:** `Durable background jobs`
867
871
 
868
872
  **Labels:** `area:api`, `type:feature`
869
- **Project fields:** Area=`api`, Target=`Next`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
873
+ **Project fields:** Area=`api`, Target=`Released`, Impact=`Feature`, IP=`job-queues`, Status=`Shipped`
870
874
 
871
- Terreno has an in-process cron helper and admin script runner but no durable queue. Adds a
872
- job abstraction with retries, scheduling, and dead-lettering — Mongo-backed by default with
873
- a Redis/BullMQ driver — so email sends, webhook retries, and billing sync survive restarts.
875
+ Adds `@terreno/jobs`: Mongo-recorded jobs with retries, schedules, dead-lettering, in-process or
876
+ standalone workers, and pluggable runners (Mongo, GCP Cloud Tasks, Vercel Queues, custom).
877
+ Email/webhook/billing consumers enqueue later; this item ships the queue.
874
878
 
875
- - **Implementation plan:** *(not yet written)*
876
- - **Tasks:** *(not yet written)*
877
- - **RTK flag:** None
879
+ Shipping this work **closes** https://github.com/FlourishHealth/terreno/issues/1188.
880
+
881
+ - **Implementation plan:** [job-queues.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/job-queues.md)
882
+ - **Tasks:** [job-queues.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/job-queues.md)
883
+ - **How-to:** [background-jobs.md](../how-to/background-jobs.md)
884
+ - **Reference:** [jobs.md](../reference/jobs.md)
885
+ - **RTK flag:** Partial — admin screens use generated SDK
878
886
  - **Depends on:** —
879
887
 
880
888
  ---
@@ -883,15 +891,17 @@ a Redis/BullMQ driver — so email sends, webhook retries, and billing sync surv
883
891
 
884
892
  **Title:** `MongoDB migrations tooling`
885
893
 
886
- **Labels:** `area:api`, `type:feature`
887
- **Project fields:** Area=`api`, Target=`Future`, Impact=`Feature`, IP=*(not yet written)*, Status=`Planned`
894
+ **Labels:** `area:api`, `type:feature`
895
+ **Project fields:** Area=`api`, Target=`Future`, Impact=`Feature`, IP=`mongodb-migrations-tooling`, Status=`Planned`
888
896
 
889
897
  A migrations runner for Terreno apps: versioned migration files, up/down with a lock
890
- collection, CI checks, and integration with the mongoose-schema-safety guidance — replacing
891
- ad-hoc backfill scripts.
898
+ collection, CI checks, CLI generate-from-schema-diff, optional boot apply, and an admin
899
+ Migrations page — replacing ad-hoc backfill scripts for once-per-environment schema changes.
892
900
 
893
- - **Implementation plan:** *(not yet written)*
894
- - **Tasks:** *(not yet written)*
901
+ Shipping this work **closes** https://github.com/FlourishHealth/terreno/issues/1189.
902
+
903
+ - **Implementation plan:** [mongodb-migrations-tooling.md](https://github.com/FlourishHealth/terreno/blob/master/docs/implementationPlans/mongodb-migrations-tooling.md)
904
+ - **Tasks:** [mongodb-migrations-tooling.md](https://github.com/FlourishHealth/terreno/blob/master/docs/tasks/mongodb-migrations-tooling.md)
895
905
  - **RTK flag:** None
896
906
  - **Depends on:** —
897
907