@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
@@ -12,14 +12,19 @@ Problem-oriented, practical steps. Use these when you know what you want to do.
12
12
 
13
13
  ## Contents
14
14
 
15
+ - [Create a Terreno app](create-a-terreno-app.md) — Scaffold a full-stack app with `create-terreno-app` (Bun or npm)
15
16
  - [Update dependencies](update-dependencies.md) — Daily rolling PR, exercise test, Expo fingerprint freeze
16
17
  - [CircleCI](circleci.md) — Dual-run CI on CircleCI (package CI / policy / e2e; deploys later)
18
+ - [Run tests locally](run-tests-locally.md) — Map every CircleCI test job to a Cursor Cloud / laptop command
17
19
  - [GitHub Actions CI](github-actions-ci.md) — Cut PR runtime: docs previews, compile-once e2e, pinned Bun
18
20
  - [Add feature flags](add-feature-flags.md) — Add feature flags, A/B testing, and OpenFeature migration
19
21
  - [Rate limiting](rate-limiting.md) — Opt-in HTTP limiter on `TerrenoApp` (memory or Redis)
20
22
  - [Receive inbound webhooks](inbound-webhooks.md) — HMAC, Stripe, Twilio, and SendGrid signatures on `WebhooksApp`
23
+ - [Durable background jobs](background-jobs.md) — `@terreno/jobs`: enqueue, workers, schedules, Cloud Tasks / Vercel Queues
21
24
  - [Create a Mongoose model](create-a-model.md) — Define models with proper conventions
25
+ - [Enable the framework audit log](audit-log.md) — `AuditApp`, per-router `audit`, append-only events
22
26
  - [Seed a database](seed-a-database.md) — Idempotent sync, dry runs, and guarded reset-and-reseed
27
+ - [Run MongoDB migrations](run-mongodb-migrations.md) — Versioned `up`/`down` files, `terreno-migrate`, production gate
23
28
  - [Add GitHub OAuth authentication](add-github-oauth.md) — Enable GitHub login for your API
24
29
  - [Configure Better Auth](configure-better-auth.md) — Set up Better Auth with social OAuth (Google, GitHub, Apple)
25
30
  - [Password reset and email verification](password-reset.md) — JWT routes, comms templates, Better Auth hooks
@@ -32,7 +37,12 @@ Problem-oriented, practical steps. Use these when you know what you want to do.
32
37
  - [Upgrade banner](upgrade-banner.md) — Soft warning and hard-block app update UX
33
38
  - [Upgrade Terreno](upgrade-terreno.md) — Lockstep `@terreno/*` bumps, note range, order, rollback
34
39
  - [Track upstream Expo](track-upstream-expo.md) — Morning probe for SDK betas; `release-X.Y.Z` loop log + native fingerprint deps
40
+ - [Compose charts in a dashboard grid](charts-and-dashboards.md) — `LineChart` / `BarChart` / `AreaChart` / `DonutChart` inside `Card`s in `DashboardGrid`
41
+ - [Compare rendered chart snapshots](compare-chart-rendered-snapshots.md) — PNG goldens for the chart visual gallery, not JSON snapshots
35
42
  - [Migrate from @terreno/rtk to @terreno/syncdb](migrate-rtk-to-syncdb.md) — Move data sync to the local-first layer
43
+ - [In-app notifications](in-app-notifications.md) — Register `NotificationsApp`, syncdb inbox, and UI bell
44
+ - [Add organizations](add-organizations.md) — Opt into Membership-backed tenancy, RBAC, admin, and seeded examples
45
+ - [Add a GPT chat mascot](add-gpt-chat-mascot.md) — Optional consumer-owned character on empty `GPTChat`
36
46
 
37
47
  ## Admin
38
48
 
@@ -0,0 +1,92 @@
1
+ # Add a GPT chat mascot
2
+
3
+ Pass a `mascot` node into `GPTChat`. Terreno does not ship a character — the consumer owns the image, Lottie, icon, or copy.
4
+
5
+ ## When it shows
6
+
7
+ | Chat state | Mascot |
8
+ | --- | --- |
9
+ | `currentMessages` is empty | Rendered, centered in the chat panel above suggested prompts |
10
+ | One or more messages | Hidden |
11
+
12
+ The empty state fills the message area and centers both axes. GPTChat sizes that hero to the message viewport so a short mascot stays centered, and the same scroller still reaches a large mascot, suggested prompts, or an open keyboard. Streaming feedback stays with the centered hero until the first message arrives. Size the mascot for a hero slot (`Heading size="2xl"`, a large `Image`, or a Lottie view).
13
+
14
+ Omit `mascot` to keep the default empty chat (prompts only, or a blank panel).
15
+
16
+ ## Steps
17
+
18
+ ### 1. Build the node in your app
19
+
20
+ Keep the asset in the consumer package. `GPTChat` only mounts whatever you pass.
21
+
22
+ ```tsx
23
+ import {Box, Heading} from "@terreno/ui";
24
+ import {Image} from "react-native";
25
+ import {useState} from "react";
26
+
27
+ const MASCOTS = [
28
+ require("../assets/mascot-1.png"),
29
+ require("../assets/mascot-2.png"),
30
+ require("../assets/mascot-3.png"),
31
+ require("../assets/mascot-4.png"),
32
+ ];
33
+
34
+ const ChatScreen: React.FC = (): React.ReactElement => {
35
+ // Select once per screen mount; ordinary re-renders keep the same character.
36
+ const [mascot] = useState(() => MASCOTS[Math.floor(Math.random() * MASCOTS.length)]);
37
+
38
+ return (
39
+ <GPTChat
40
+ currentMessages={currentMessages}
41
+ histories={histories}
42
+ mascot={
43
+ <Box alignItems="center" gap={3}>
44
+ <Image
45
+ accessibilityLabel="App mascot"
46
+ resizeMode="cover"
47
+ source={mascot}
48
+ style={{borderRadius: 112, height: 224, width: 224}}
49
+ />
50
+ <Heading align="center" size="md">Ask anything.</Heading>
51
+ </Box>
52
+ }
53
+ onCreateHistory={handleCreateHistory}
54
+ onDeleteHistory={handleDeleteHistory}
55
+ onSelectHistory={handleSelectHistory}
56
+ onSubmit={handleSubmit}
57
+ />
58
+ );
59
+ };
60
+ ```
61
+
62
+ For a single fixed mascot, pass one asset directly instead of selecting from an array.
63
+
64
+ ### 2. Pass it to `GPTChat`
65
+
66
+ ```tsx
67
+ <GPTChat
68
+ currentMessages={currentMessages}
69
+ histories={histories}
70
+ mascot={ChatMascot}
71
+ onCreateHistory={handleCreateHistory}
72
+ onDeleteHistory={handleDeleteHistory}
73
+ onSelectHistory={handleSelectHistory}
74
+ onSubmit={handleSubmit}
75
+ suggestedPrompts={["What can you help with?"]}
76
+ />
77
+ ```
78
+
79
+ ### 3. Confirm empty vs thread
80
+
81
+ Open a new chat: the mascot is visible. After the first user or assistant message, it is gone.
82
+
83
+ ## Example
84
+
85
+ The example app bundles four consumer-owned plant robots in
86
+ `example-frontend/assets/gptMascots/` and selects one on each AI screen mount. The
87
+ demo story `GPTChat` → `Mascot` shows the slot without a backend.
88
+
89
+ ## Related
90
+
91
+ - [`GPTChat` props](../reference/ui.md#gptchat)
92
+ - Demo: `http://localhost:8085/dev/GPTChat?story=Mascot`
@@ -0,0 +1,204 @@
1
+ # Add organizations to a Terreno app
2
+
3
+ Enable organizations only when the app is multi-tenant. Existing single-tenant
4
+ apps can omit every option in this guide.
5
+
6
+ ## 1. Enable organization RBAC
7
+
8
+ ``````typescript
9
+ import {createAccess, terrenoStatements} from "@terreno/api";
10
+
11
+ export const access = createAccess({
12
+ connection: mongoose.connection,
13
+ organizations: true,
14
+ statements: terrenoStatements,
15
+ userModel: User,
16
+ });
17
+
18
+ await access.roles.seedDefaults();
19
+ ``````
20
+
21
+ This adds Membership-based `org-admin` grants and seeds the locked `operator`
22
+ role. It does not change apps that omit `organizations`.
23
+
24
+ ## 2. Mount organization routes
25
+
26
+ ``````typescript
27
+ const app = new TerrenoApp({
28
+ accessControl: access,
29
+ organizations: true,
30
+ userModel: User,
31
+ });
32
+ ``````
33
+
34
+ This mounts `OrgsApp` at `/orgs`. To configure audit handling or a different
35
+ path, pass an options object:
36
+
37
+ ``````typescript
38
+ organizations: {
39
+ basePath: "/organizations",
40
+ onOrgAudit: recordOrganizationAudit,
41
+ settingsSchema: organizationSettingsSchema,
42
+ }
43
+ ``````
44
+
45
+ ## 3. Type organization settings
46
+
47
+ Keep native `Organization` fields unchanged. Put app fields on
48
+ `Organization.settings` with a nested Mongoose schema and a TypeScript
49
+ interface.
50
+
51
+ 1. Declare the settings shape (optional module augmentation):
52
+
53
+ ``````typescript
54
+ // src/types/models/organizationSettingsTypes.ts
55
+ export interface ExampleOrganizationSettings {
56
+ timezone?: string;
57
+ }
58
+
59
+ declare module "@terreno/api" {
60
+ interface OrganizationSettings extends ExampleOrganizationSettings {}
61
+ }
62
+ ``````
63
+
64
+ 2. Build the nested schema. Use optional fields or defaults so existing
65
+ organizations still validate:
66
+
67
+ ``````typescript
68
+ // src/models/organizationSettings.ts
69
+ import {createOrganizationSettingsSchema} from "@terreno/api";
70
+ import type {ExampleOrganizationSettings} from "../types/models/organizationSettingsTypes";
71
+
72
+ export const organizationSettingsSchema = createOrganizationSettingsSchema<ExampleOrganizationSettings>({
73
+ timezone: {
74
+ description: "IANA timezone used for organization-local dates",
75
+ type: String,
76
+ },
77
+ });
78
+ ``````
79
+
80
+ 3. Register before you create or patch organizations (startup and seeds):
81
+
82
+ ``````typescript
83
+ import {registerOrganizationSettings} from "@terreno/api";
84
+ import {organizationSettingsSchema} from "./models/organizationSettings";
85
+
86
+ registerOrganizationSettings(organizationSettingsSchema);
87
+ ``````
88
+
89
+ Or pass the same schema on `TerrenoApp` / `OrgsApp`:
90
+
91
+ ``````typescript
92
+ new TerrenoApp({
93
+ accessControl: access,
94
+ organizations: {settingsSchema: organizationSettingsSchema},
95
+ userModel: User,
96
+ });
97
+ ``````
98
+
99
+ Read typed settings with `organizationSettingsOf(organization)` or
100
+ `organizationSettingsOf<ExampleOrganizationSettings>(organization)`.
101
+
102
+ Without a registered schema, `settings` stays Mixed and accepts any object.
103
+ Unknown keys and wrong types fail with **400** `Organization settings are invalid`
104
+ once a schema is registered.
105
+
106
+ ## 4. Scope tenant models
107
+
108
+ Add `orgScopedPlugin` to models that use ObjectId organization keys. Put
109
+ `orgContextMiddleware({required: true})` before their routes, use
110
+ `OrgQueryFilter` for lists, and overwrite client organization ids during
111
+ create:
112
+
113
+ ``````typescript
114
+ import {
115
+ authenticateMiddleware,
116
+ getOrgContext,
117
+ modelRouter,
118
+ OrgQueryFilter,
119
+ orgContextMiddleware,
120
+ orgScopedPlugin,
121
+ Permissions,
122
+ type TerrenoPlugin,
123
+ } from "@terreno/api";
124
+ import type express from "express";
125
+
126
+ schema.plugin(orgScopedPlugin);
127
+
128
+ const projectOrgContextPlugin: TerrenoPlugin = {
129
+ register(expressApp: express.Application): void {
130
+ expressApp.use(
131
+ "/projects",
132
+ authenticateMiddleware(),
133
+ orgContextMiddleware({required: true})
134
+ );
135
+ },
136
+ };
137
+
138
+ const projectRouter = modelRouter("/projects", Project, {
139
+ permissions: {
140
+ create: [Permissions.IsAuthenticated, Permissions.IsOrganizationMember],
141
+ delete: [Permissions.IsAuthenticated, Permissions.IsOrganizationMember],
142
+ list: [Permissions.IsAuthenticated],
143
+ read: [Permissions.IsAuthenticated, Permissions.IsOrganizationMember],
144
+ update: [Permissions.IsAuthenticated, Permissions.IsOrganizationMember],
145
+ },
146
+ preCreate: (body, _req) => ({
147
+ ...body,
148
+ organizationId: getOrgContext()?.organization?._id,
149
+ }),
150
+ queryFilter: OrgQueryFilter,
151
+ });
152
+
153
+ app.register(projectOrgContextPlugin).register(projectRouter);
154
+ ``````
155
+
156
+ For admin CRUD, use `new AdminApp({accessControl: access, organizations:
157
+ true})`. Models with an `organizationId` schema path are scoped automatically,
158
+ except `AuditEvent` (the platform audit log lists without a selected org).
159
+ Admin-window `POST /sync/mutate` and socket `sync:mutate` use the same membership
160
+ check as REST for update and delete when `X-Organization-Id` (HTTP) or
161
+ `organizationId` (socket payload) is set. Admin `createSyncDb({organizationIdProvider})`
162
+ sends that id on every mutate.
163
+
164
+ `orgScopedPlugin` also makes `organizationId` immutable after the document is
165
+ created. Client PATCH bodies, admin writes, sync updates, and direct Mongoose
166
+ saves that change `organizationId` return HTTP 400 with
167
+ `organizationId cannot be changed`.
168
+
169
+ ## 5. Send organization context
170
+
171
+ Send `X-Organization-Id` on tenant-scoped requests. `org-admin` callers with
172
+ exactly one administered organization may omit it; Terreno infers that org.
173
+ Operators and superadmins must select an org.
174
+
175
+ Frontend admin hosts use `OrgContextProvider` + `OrgSwitcher`.
176
+ `useAdminApi` adds the selected organization header automatically.
177
+
178
+ Disabled organizations are excluded from `/orgs/mine` and cannot be selected as
179
+ tenant context. Operators re-enable them from the organization directory UI or
180
+ with `PATCH /orgs/:id` and `disabled: false` (see
181
+ [How organization tenancy works](../explanation/organizations.md#disabled-organizations)).
182
+
183
+ Creating or renaming an organization to a name that generates an existing slug,
184
+ including a slug still held by a **soft-deleted** organization, returns **409**
185
+ `Organization name already in use`. `OrgSwitcher` hides itself
186
+ when `/orgs/mine` returns **403** for callers without org-admin memberships.
187
+
188
+ ## Example app accounts
189
+
190
+ After `bun run backend:seed`, all accounts use password `testpassword123`:
191
+
192
+ | Account | Access |
193
+ | --- | --- |
194
+ | `operator@example.com` | Platform organization directory; may enter either org |
195
+ | `orgadmin-alpha@example.com` | Org admin for Alpha Workspace |
196
+ | `orgadmin-beta@example.com` | Org admin for Beta Workspace |
197
+ | `test@example.com` | Member of Alpha Workspace |
198
+ | `admin@example.com` / `superadmin@example.com` | Existing example superadmin accounts |
199
+
200
+ The seed creates Alpha Workspace and Beta Workspace plus two projects in Alpha
201
+ Workspace. Membership rows, not fields on User, are the source of tenant access.
202
+ In-process Better Auth seeding sets `disableRateLimit: true` so production
203
+ preview smoke tests can create all six accounts without hitting Better Auth's
204
+ sign-up limiter.
@@ -38,7 +38,15 @@ Common fields:
38
38
  - `searchFields`: string fields matched by the list search box (`q`) as a
39
39
  case-insensitive partial (`$regex`) query.
40
40
  - `sortableFields`: the only columns with sorting enabled.
41
- - `filters`: typed filter drawer controls.
41
+ - `filters`: typed list filters rendered on `DataTable` column headers (web) or the
42
+ mobile **Filters** sheet. `text` filters are case-insensitive contains (`$regex`);
43
+ `choice` filters support multi-select (`$in`); `ref` stays a single ObjectId. The
44
+ backend accepts only escaped literal regex patterns and rejects extra nested operators.
45
+ Optional choice fields (Mongoose path not `required`) automatically expose an **Empty**
46
+ filter option; set `allowEmpty: false` on the filter config to hide it, or
47
+ `allowEmpty: true` on required fields when you intentionally want unset matching.
48
+ Empty filters can be combined with toolbar search or concrete choices. The wire
49
+ sentinel is consumed before Mongo receives the query.
42
50
  - `fieldsets`: grouped form sections.
43
51
  - `readonlyFields` / `hiddenFields`: display-only or omitted form fields.
44
52
  - `adminPermissions`: optional admin-specific permission methods.
@@ -3,12 +3,15 @@
3
3
  Register first-party plugins on the same `TerrenoApp` as `AdminApp`:
4
4
 
5
5
  ```ts
6
+ import {JobsApp} from "@terreno/jobs";
7
+
6
8
  const app = new TerrenoApp({userModel: User})
7
9
  .register(new FeatureFlagsApp())
8
10
  .register(new ConsentApp({auditTrail: true}))
9
11
  .register(new DocumentStorageApp({bucketName: process.env.GCS_BUCKET ?? ""}))
10
12
  .register(new AIAdminApp())
11
- .register(new AdminApp({home: {slots: {main: ["modelStats"]}}}));
13
+ .register(new JobsApp({accessControl})) // optional — needs admin:access + admin:jobs
14
+ .register(new AdminApp({home: {slots: {main: ["modelStats", "jobs"]}}}));
12
15
  ```
13
16
 
14
17
  `AdminApp` aggregates each plugin's `adminContribution()`:
@@ -17,6 +20,9 @@ const app = new TerrenoApp({userModel: User})
17
20
  - `ConsentApp`: ConsentForm and ConsentResponse models plus consent field-widget IDs.
18
21
  - `DocumentStorageApp`: `documents` custom screen.
19
22
  - `AIAdminApp`: `ai-requests` custom screen and explorer API.
23
+ - `JobsApp`: `jobs` custom screen and home widget (`dead` / `running` counts). With
24
+ `accessControl`, requires **both** `admin:access` and `admin:jobs`; without it, legacy
25
+ `user.admin`. See [Durable background jobs](background-jobs.md).
20
26
 
21
27
  Wrap frontend admin routes in `AdminProvider`. First-party widgets are already in the built-in
22
28
  registry, so no consumer-side switch statement or custom-screen map is required.
@@ -0,0 +1,85 @@
1
+ # Enable the framework audit log
2
+
3
+ Register `AuditApp` and set `audit: true` on routers you want logged. Successful HTTP mutations write append-only `AuditEvent` rows. Default retention is forever.
4
+
5
+ ## Steps
6
+
7
+ ### 1. Register the plugin
8
+
9
+ ```typescript
10
+ import {AuditApp, TerrenoApp} from "@terreno/api";
11
+
12
+ new TerrenoApp({userModel: User}).register(new AuditApp()).start();
13
+ ```
14
+
15
+ Importing `@terreno/api` does not register `AuditEvent`. HTTP list/read is admin-only at `GET /audit-events` and `GET /admin/audit-events`. Create/update/delete over HTTP are disabled (405), including the admin remount.
16
+
17
+ ### 2. Opt in per router
18
+
19
+ ```typescript
20
+ modelRouter("/todos", Todo, {
21
+ audit: true, // or {redact: ["ssn"]}
22
+ permissions: {
23
+ /* ... */
24
+ },
25
+ });
26
+ ```
27
+
28
+ `audit: true` without `AuditApp` still returns 2xx and logs an error once per process.
29
+
30
+ ## Operations
31
+
32
+ | HTTP | `verb` | `operation` | Diff |
33
+ | --- | --- | --- | --- |
34
+ | POST `/` | `created` | `create` | `after` only |
35
+ | PATCH `/:id` | `updated` | `update` | Changed fields in `before` / `after` |
36
+ | DELETE `/:id` | `deleted` | `delete` | `before` only |
37
+ | POST `/:id/:field` | `updated` | `arrayPush` | Changed fields; `recordId` set |
38
+ | PATCH `/:id/:field/:itemId` | `updated` | `arrayUpdate` | Changed fields; `recordId` set |
39
+ | DELETE `/:id/:field/:itemId` | `updated` | `arrayRemove` | Changed fields; `recordId` set |
40
+
41
+ `source` is `modelRouter` for these writes. Secrets (`password`, `hash`, `salt`, `token`,
42
+ `secret`, `refreshToken`) are omitted at every object and array depth, including compound
43
+ keys such as `tokenHash`. Extra `redact` names merge with that list as exact field names.
44
+
45
+ ### 3. Admin mutations
46
+
47
+ When `AuditApp` is registered, AdminApp writes the same `AuditEvent` collection with
48
+ `source: "admin"` after successful admin POST/PATCH/DELETE. You do not need `onAdminAudit` for
49
+ that. `onAdminAudit` remains an extra sink if the app still wants a second destination.
50
+ Admin diffs also omit each model's `hiddenFields` and `excludeFields`.
51
+
52
+ RBAC mutations fan into the same collection when `createAccess({auditSink: persistRbacAuditToAuditEvent})` is set. `source` is `rbac`.
53
+
54
+ `organizationId` is copied onto the event when `req.organization` is set (`id` or `_id`), otherwise from the request org AsyncLocalStorage, then `X-Organization-Id`, then the mutated document's `organizationId` string. Socket admin-window mutates attach `organizationId` on the payload so non-tenant models still land in the selected organization's audit log. The field is omitted when none of those exist. Admin list/read for `AuditEvent` is not organization-scoped, so unscoped rows stay visible when no organization is selected.
55
+
56
+ `actorId` comes from `req.user.id` (or `_id`). Only a 24-hex Mongo ObjectId is stored;
57
+ mongoose's looser `isValidObjectId` (12-character strings) is not used. Any other id
58
+ shape still writes the event with `actorId` omitted and a warning logged.
59
+
60
+ Update and delete snapshot `before` only when `audit` is on. If that `toJSON` throws, the
61
+ mutation still completes and the event is recorded without a `before` snapshot.
62
+
63
+ ### 4. Fire-and-forget persist
64
+
65
+ HTTP handlers do not await Mongo. Diffs still run before the response so `before` / `after` are captured. Failures log; the mutation stays 2xx.
66
+
67
+ To persist completely off the API process, set Cloud Tasks env (`GCP_PROJECT`, `GCP_LOCATION`, `GCP_TASKS_AUDIT_QUEUE`, `AUDIT_TASKS_URL`, `AUDIT_TASKS_SECRET`) and `bun add @google-cloud/tasks`. `AuditApp` then enqueues the write and handles `POST /internal/audit-events` with header `X-Terreno-Audit-Secret`. Or pass `enqueue` yourself:
68
+
69
+ ```typescript
70
+ new AuditApp({
71
+ enqueue: async (write) => {
72
+ await myQueue.push(write);
73
+ },
74
+ processQueuePath: "/internal/audit-events",
75
+ processQueueSecret: process.env.AUDIT_TASKS_SECRET,
76
+ });
77
+ ```
78
+
79
+ Authenticated malformed queue payloads are acknowledged without persistence. They cannot
80
+ become valid on retry, and returning a non-2xx response would make Cloud Tasks retry the
81
+ same poison task indefinitely.
82
+
83
+ ### 5. Retention
84
+
85
+ Omit `retentionDays` or set `0` to keep events forever (no TTL index). `new AuditApp({retentionDays: 90})` creates a Mongo TTL index on `created` with `expireAfterSeconds = 90 * 86400`, replacing the default `{created: 1}` field index so Mongo does not reject a duplicate key pattern. Mongo expires documents in the background; lowering or removing TTL later requires dropping that index yourself (`db.auditevents.dropIndex(...)`) — Mongoose will not remove it.