@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
@@ -0,0 +1,246 @@
1
+ # Implementation Plan: Charts and dashboard primitives
2
+
3
+ **Status:** In progress
4
+ **Branch:** `cursor/charts-and-dashboards-2bc3`
5
+ **Owner:** —
6
+ **Created:** 2026-09-10
7
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1175 (this feature **closes** that issue; implementation PRs use `Fixes #1175`)
8
+ **Task list:** [charts-and-dashboards.md](../tasks/charts-and-dashboards.md)
9
+ **Depends on:** —
10
+ **RTK deprecation flag:** None
11
+ **Program:** [B2B platform](b2b-platform-program.md) track E
12
+
13
+ ## Goal
14
+
15
+ Ship themed, universal chart and dashboard layout primitives in `@terreno/ui` so B2B
16
+ admin and product screens can compose line, bar, area, and donut charts without a
17
+ third-party chart API leaking into app code.
18
+
19
+ Rendering is **owned SVG** on `react-native-svg` (already used for icons). Public
20
+ components are `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, and `DashboardGrid`.
21
+ Proof is demo stories plus docs. No example-frontend screen and no comms-dashboard
22
+ wiring in this slice.
23
+
24
+ ## Non-Goals
25
+
26
+ - `victory-native`, Skia canvas charts, `react-native-gifted-charts`, `react-native-chart-kit`, WebView/ECharts.
27
+ - Example-frontend dashboard screen.
28
+ - Comms admin stats charts (comms IP already defers to this item; a later comms task consumes these primitives).
29
+ - Zoom, pan, brush, stacked/grouped multi-series cartesian, combo charts, maps, heatmaps.
30
+ - A new `DashboardCard` (reuse `Card`).
31
+ - Dark-mode palette work (`dark-mode-theme`); charts read `useTheme()` so they follow when that ships.
32
+ - Implementing the approved composition grammar in the visual-regression slice (Phase 6).
33
+
34
+ ## Decisions
35
+
36
+ | Question | Decision |
37
+ |----------|----------|
38
+ | Public exports | Named `LineChart`, `BarChart`, `AreaChart`, `DonutChart`. No `Chart` dispatcher. Remove the commented `export * from "./Chart"` stub. |
39
+ | First consumer | Demo stories only. |
40
+ | Interactivity | Legend plus press (native) / hover (web) tooltip. No zoom/pan. |
41
+ | Dashboard layout | `DashboardGrid` with responsive column counts; children are existing `Card`s. |
42
+ | Engine | Owned `react-native-svg` primitives in `@terreno/ui`. Not victory-native, not a wrap. |
43
+ | Series model | Single series this slice: `data: {label: string; value: number}[]`. Donut uses the same points as slices (`color?` optional per slice). Multi-series cartesian is future work. |
44
+ | Math | Private `d3-scale` + `d3-shape` in `ui/` only (single-package; raw versions, not catalog unless a second package needs them). Do not export d3 types. |
45
+ | Axis labels | Overlay `@terreno/ui` `Text` (theme fonts). Do not draw axis copy with SVG `<Text>` as the primary path. |
46
+ | Tooltip chrome | Terreno `Tooltip` when a mark can be the child; otherwise an internal overlay `Box`+`Text` at the hit point with the same copy (`label: value`). |
47
+ | Empty / loading | Empty `data` → `Text` (`emptyText`, default `"No data"`). `loading` → `Spinner`. |
48
+ | Colors | Theme tokens: series/slice fills from `primary` / `secondary` / `accent` / `error` (and tints). Grid/axis from `border` / `text.secondaryDark`. Optional `color` on a donut slice overrides. |
49
+ | Packaging | Chart components join the existing lazy root boundary (`heavyOptionalExports`). `DashboardGrid` stays eager (layout only). Subpaths `@terreno/ui/LineChart` etc. remain direct. |
50
+ | Dates | `label` is a display string. Callers format with Luxon before passing. No `Date` objects in props. |
51
+ | Visual proof | Rendered PNG goldens via `bun run ui:charts:compare`, not React JSON snapshots. |
52
+
53
+ ## Architecture
54
+
55
+ ```
56
+ @terreno/ui
57
+ LineChart / BarChart / AreaChart / DonutChart
58
+ ChartFrame (Box + sized Svg + overlay Text axes + legend + tooltip)
59
+ charts/scales.ts d3-scale linear / band (private)
60
+ charts/paths.ts d3-shape line / area / arc (private)
61
+ charts/theme.ts useTheme → stroke / fill / grid / axis
62
+ DashboardGrid
63
+ Box wrap + width percent from breakpoint column count
64
+ ```
65
+
66
+ ### Public props (minimal)
67
+
68
+ ```typescript
69
+ interface ChartPoint {
70
+ label: string;
71
+ value: number;
72
+ color?: string; // donut slice override
73
+ }
74
+
75
+ interface CartesianChartProps {
76
+ data: ChartPoint[];
77
+ height?: number; // default 200
78
+ legendLabel?: string;
79
+ emptyText?: string;
80
+ loading?: boolean;
81
+ accessibilityLabel?: string;
82
+ testID?: string;
83
+ }
84
+
85
+ interface DashboardGridProps {
86
+ columns?: {sm?: number; md?: number; lg?: number}; // default 1 / 2 / 3
87
+ gap?: SignedUpTo12;
88
+ children: React.ReactNode;
89
+ testID?: string;
90
+ }
91
+ ```
92
+
93
+ Cartesian charts share `CartesianChartProps`. `DonutChart` uses the same `data` as slices
94
+ (ignore `legendLabel`; legend is one row per slice).
95
+
96
+ Layout: `Box` around an `Svg` with a stable `viewBox`. Plot geometry is SVG. Tick labels
97
+ sit in `Box` rows/columns around the plot so Nunito/Titillium apply. Legend is a wrapping
98
+ `Box` of color swatch + `Text` below the plot.
99
+
100
+ Hit testing: map press/hover location to the nearest point (cartesian) or slice (donut).
101
+ Web uses hover in; native uses press. Tooltip copy is `{label}: {value}` (no extra
102
+ formatting unless `value` is shown with a caller-supplied `formatValue?: (n) => string`,
103
+ default `String(n)`).
104
+
105
+ ### File layout
106
+
107
+ | Path | Role |
108
+ |------|------|
109
+ | `ui/src/charts/types.ts` | `ChartPoint` and shared props (not a public barrel) |
110
+ | `ui/src/charts/scales.ts` | Private scale helpers + unit tests |
111
+ | `ui/src/charts/paths.ts` | Private path helpers + unit tests |
112
+ | `ui/src/charts/theme.ts` | Theme → paint |
113
+ | `ui/src/charts/ChartFrame.tsx` | Shared frame (not exported from package root) |
114
+ | `ui/src/LineChart.tsx` | Public line |
115
+ | `ui/src/BarChart.tsx` | Public bar |
116
+ | `ui/src/AreaChart.tsx` | Public area |
117
+ | `ui/src/DonutChart.tsx` | Public donut |
118
+ | `ui/src/DashboardGrid.tsx` | Public grid |
119
+ | `ui/src/index.tsx` | Eager `DashboardGrid`; lazy chart named exports |
120
+ | `ui/src/lazyBoundaries/heavyOptionalExports.tsx` | Chart lazy factories |
121
+ | `ui/package.json` | `d3-scale`, `d3-shape` (+ types) |
122
+
123
+ No `ui/src/charts/index.ts` barrel (Biome `noBarrelFile`).
124
+
125
+ ### Dependencies
126
+
127
+ `react-native-svg` is already a `ui` dependency. Add `d3-scale` and `d3-shape` to `ui/`
128
+ only. Do not add `victory-native`. Import-benchmark and `RootImportRegression` must show
129
+ chart implementation modules off the cold `@terreno/ui` root graph (same pattern as
130
+ `GPTChat`).
131
+
132
+ ### Chart visual regression
133
+
134
+ JSON snapshots of the React tree do not prove paint. The demo hosts
135
+ `/demo/chart-visual-gallery` (easy → hard fixtures in
136
+ `demo/chartVisual/fixtureCatalog.ts`). `bun run ui:charts:compare` launches Chromium,
137
+ screenshots each `[data-testid=chart-visual-<id>]`, and pixel-diffs against
138
+ `demo/rendered-snapshots/<id>.png`. Failures write
139
+ `demo/chart-visual-output/{actual,diff,report.json}`. Agents follow
140
+ `review-chart-visuals`. `bun run ui:charts:update-snapshots` rewrites goldens after an
141
+ intentional visual change.
142
+
143
+ ### Testing
144
+
145
+ Bun + `@testing-library/react-native` + `renderWithTheme`. Assert:
146
+
147
+ - Empty and loading states by text / `testID`.
148
+ - One mark per `data` item (`testID` suffix by index or label).
149
+ - Tooltip copy after press (native) or hover where the test renderer allows.
150
+ - Legend label / slice labels.
151
+ - Scale/path helpers with numeric fixtures (no renderer).
152
+ - `DashboardGrid`: child count and `testID`; width math via style when observable.
153
+
154
+ Do not mock `react-native-svg` unless a helper is untestable; prefer querying `testID`s
155
+ on wrapper `Box`es if SVG nodes are opaque in happy-dom.
156
+
157
+ ### Demo
158
+
159
+ Stories: `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, `DashboardGrid` (grid of
160
+ `Card`s each holding a chart). Register in `demoConfig.tsx` so the demo coverage
161
+ allowlist passes. Static fixture data only.
162
+
163
+ ## Models / APIs / Notifications
164
+
165
+ None.
166
+
167
+ ## UI
168
+
169
+ Universal React Native + web. No admin-v2 `home.slots` work. Comms dashboard is a future
170
+ consumer, not this IP.
171
+
172
+ ## Phases
173
+
174
+ 1. **Tracer:** private scales/paths/theme + `LineChart` (tooltip, legend, empty/loading) +
175
+ tests + demo story + reference stub.
176
+ 2. **Sibling charts:** `BarChart`, `AreaChart`, `DonutChart` on the same frame.
177
+ 3. **DashboardGrid** + composing demo story.
178
+ 4. **Packaging + docs:** lazy root exports, import regression, Diátaxis pages, TypeDoc,
179
+ changelog fragment, seed links, rules/skill mentions.
180
+ 5. **Rendered visual regression:** gallery + compare command + `review-chart-visuals` skill.
181
+ 6. **Composition grammar (approved, not this slice):** declarative children (`Chart`,
182
+ `ChartTitle`, cartesian/polar, series, axes, grid, legend, tooltip, data labels,
183
+ reference line/band). Keyed rows + `dataKey`. Facades stay additive `{label,value}`.
184
+ Tooltip overlay + footer (facades keep footer). Colors: theme tokens + hex.
185
+ `data`/`xKey` on `Chart`/`ChartCartesian`/`ChartPolar`. Grouped bars unless `stackId`.
186
+
187
+ ## Feature Flags & Migrations
188
+
189
+ None. Additive public components. Not a major.
190
+
191
+ ## Activity Log & User Updates
192
+
193
+ None.
194
+
195
+ ## Not Included / Future Work
196
+
197
+ - Composition grammar (Phase 6) — recorded Grow decisions; implement on a follow-up Pick.
198
+ - Multi-series cartesian beyond `dataKey` / `stackId` once the grammar ships.
199
+ - Wiring `CommsDashboardScreen` charts to the stats endpoint.
200
+ - Example-frontend dashboard.
201
+ - Zoom/pan.
202
+ - Victory/Skia renderer if a later product needs GPU-scale series (thousands of points).
203
+
204
+ ## Files to Create / Modify
205
+
206
+ See the task list. Docs created or updated in-slice:
207
+
208
+ - `docs/how-to/charts-and-dashboards.md` (create)
209
+ - `docs/how-to/README.md` (link)
210
+ - `docs/explanation/charts.md` (create — why owned SVG, not victory-native)
211
+ - `docs/explanation/README.md` (link)
212
+ - `docs/reference/ui.md` (Display exports + example)
213
+ - `docs/explanation/roadmap-seed-issues.md` (`charts-and-dashboards` IP/task links)
214
+ - `docs/implementationPlans/b2b-platform-program.md` / `comms-admin-dashboard.md` (pointer only if they still say “charts later” without a path)
215
+ - `.rulesync/rules/ui/00-ui.mdc` (export list)
216
+ - `changelog/unreleased/charts-and-dashboards.md`
217
+ - TypeDoc props so `docs-audit` is clean after `bun run website:generate`
218
+
219
+ ## Task List
220
+
221
+ [docs/tasks/charts-and-dashboards.md](../tasks/charts-and-dashboards.md)
222
+
223
+ ## Acceptance Criteria
224
+
225
+ - [ ] `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, and `DashboardGrid` are
226
+ importable from `@terreno/ui` and from component subpaths.
227
+ - [ ] Charts render with `react-native-svg`; `victory-native` is not a dependency.
228
+ - [ ] Single-series `{label, value}[]` is the only cartesian data contract.
229
+ - [ ] Empty and loading states are visible; tooltip + legend work (press native, hover web).
230
+ - [ ] Theme tokens drive default paints; overlay axis labels use `Text`.
231
+ - [ ] Chart implementations are lazy on the package root; `DashboardGrid` is eager.
232
+ - [ ] Focused bun tests cover scales, empty/loading, mark counts, tooltip copy, grid columns.
233
+ - [ ] Demo stories exist for all five exports and are registered.
234
+ - [ ] How-to, explanation, and `docs/reference/ui.md` describe the API; TypeDoc props exist.
235
+ - [ ] `bun test` (ui affected files), `bun run compile` in `ui`, and demo compile succeed.
236
+ - [ ] Frontend verification: demo stories exercised on web; artifacts on the implementation PR.
237
+ - [x] `bun run ui:charts:compare` matches `demo/rendered-snapshots/` for the gallery.
238
+
239
+ ## Risks
240
+
241
+ | Risk | Mitigation |
242
+ |------|------------|
243
+ | happy-dom SVG nodes hard to query | `testID` on `Box` wrappers around marks; helper unit tests for path strings |
244
+ | Hover vs press tooltip | Shared hit-test helper; platform-specific event wiring; tests cover press at minimum |
245
+ | Root import size | Lazy boundary + `performance:imports` / `RootImportRegression` |
246
+ | d3 + RN types | Confine d3 to `charts/scales.ts` and `charts/paths.ts` |
@@ -25,8 +25,9 @@ uses (`addAiRequestsExplorerRoutes`) but with mutation (retry) and much richer f
25
25
 
26
26
  - Building the messages themselves (comms-abstraction) or provider integrations (adapter
27
27
  IPs).
28
- - Charts beyond simple count cards — themed chart components arrive with
29
- `charts-and-dashboards`; the stats endpoint is designed so charts can be added then.
28
+ - Charts beyond simple count cards — themed chart components are in
29
+ [`charts-and-dashboards.md`](charts-and-dashboards.md); the stats endpoint is designed so
30
+ those primitives can be added later.
30
31
  - Broadcast/bulk *composition* from admin (sending new messages, campaign tooling).
31
32
  - User-facing notification history (`notification-center` item).
32
33
  - Cross-service log aggregation (Sentry/Cloud Logging stay the deep-debug tools; the
@@ -145,7 +146,7 @@ Every retry is itself a `CommsMessage` row (with `retriedFromId` and the acting
145
146
 
146
147
  - Failure-rate alerting (Slack/Google Chat notifier when a provider's failure rate spikes)
147
148
  — small follow-up once `/comms/stats` exists.
148
- - Charts on the stats endpoint (`charts-and-dashboards`).
149
+ - Charts on the stats endpoint — consume [`charts-and-dashboards`](charts-and-dashboards.md) primitives.
149
150
  - Editing a message before retry ("retry with edits").
150
151
  - Automatic scheduled retries with backoff — arrives with `job-queues`; this IP is
151
152
  explicitly *manual, admin-driven* retry.
@@ -0,0 +1,177 @@
1
+ # Implementation Plan: create-terreno-app scaffolding CLI
2
+
3
+ **Status:** In progress — all tasks Roast PASS; next: Brew
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1174
5
+ **Branch:** `cursor/create-terreno-app-ip-54bd`
6
+ **Owner:** unassigned
7
+ **Created:** 2026-09-10
8
+ **Program:** [B2B platform](b2b-platform-program.md) track D; [OSS launch](oss-launch-program.md) (zero-to-running DX)
9
+ **Depends on:** [`deployment-foundation`](deployment-foundation.md) (Complete)
10
+ **RTK deprecation flag:** **Partial** — scaffold output is Better Auth + `@terreno/syncdb`. Do not emit RTK Query collection CRUD.
11
+
12
+ ## Goal
13
+
14
+ Ship a published **`create-terreno-app`** CLI that writes a running, deployable Terreno app to disk in one non-interactive command. `terreno_bootstrap_app` uses the **same generator**: local MCP writes when `targetDir` is set; hosted MCP never writes and returns a short CLI instruction plus the file dump.
15
+
16
+ When this is done, an operator or agent can:
17
+
18
+ 1. Run `bunx create-terreno-app my-app --display-name "My App"` (or `npm create terreno-app`).
19
+ 2. Get `my-app/backend` + `my-app/frontend` (syncdb, Better Auth, admin, seed script, `.env` / `.env.example`, consumer `Dockerfile`, CI workflows, MCP config).
20
+ 3. Follow the printed README: replica-set MongoDB, `bun install`, `bun run seed`, `bun run sdk`, `bun run web`.
21
+ 4. Sign in as `test@example.com` / `testpassword123`.
22
+ 5. Deploy using existing how-tos; the scaffold Dockerfile and env examples match [deployment baseline](../explanation/deployment-baseline.md).
23
+
24
+ ## Non-Goals
25
+
26
+ | Out | Why |
27
+ | --- | --- |
28
+ | GitHub template repo | Q1 — one generator; a template would drift |
29
+ | Snapshot / clone of `example-*` | Q2 — examples include consent and monorepo-only Docker |
30
+ | Interactive prompts | Q5 — agents need flags |
31
+ | `bun install`, Mongo, or seed inside the CLI | Q5 — write files only |
32
+ | Terraform / GCP / Vercel copy-paste into the tree | Q4 — README links to how-tos |
33
+ | `--no-admin` | parked; v1 matches current bootstrap (admin included) |
34
+ | Hosted MCP writing the server disk | Q3 — dump + CLI instruction only |
35
+ | Copying `example-backend/Dockerfile` | that image builds this monorepo, not a consumer app |
36
+
37
+ ## Decisions
38
+
39
+ | ID | Question | Decision |
40
+ | --- | --- | --- |
41
+ | Q1 | Delivery vehicle | Unscoped npm CLI `create-terreno-app` in this monorepo (not a template repo) |
42
+ | Q2 | Generator source of truth | Extract `generateAllFiles` from `mcp-server/src/bootstrap.ts` into the CLI package; MCP imports it |
43
+ | Q3 | Hosted vs local MCP | Write when local + writable `targetDir`; otherwise CLI instructions + file dump |
44
+ | Q4 | Deployable in v1 | Consumer `Dockerfile` + `.env.example` + README links to deploy how-tos |
45
+ | Q5 | CLI UX | `bunx create-terreno-app my-app --display-name "My App"`; refuse non-empty dir; `--yes` derives display name; no prompts; no install/seed |
46
+ | Q6 | Package name | Unscoped `create-terreno-app` (`npm create terreno-app` / `bunx create-terreno-app`) |
47
+ | Q7 | MCP write path | Optional `targetDir`; write only if set and allowed; else dump |
48
+ | Q8 | Generated `@terreno/*` versions | Pin `^<create-terreno-app version>` (lockstep with published `@terreno/*`) |
49
+
50
+ ### Recorded assumptions (implementation detail)
51
+
52
+ - Workspace directory: `create-terreno-app/` at the repo root (same pattern as `mcp-server/`).
53
+ - One package: bin + exported `generateAllFiles` / `writeScaffold`. MCP depends on `create-terreno-app` via `workspace:*`.
54
+ - Version pin: read `create-terreno-app/package.json` `version` (lockstep with other packages at release). Generated deps use `^${version}`, not `"latest"`.
55
+ - Target layout: `<dir>/{backend,frontend,.github,README.md,Dockerfile,…}` matching today’s bootstrap file list, plus deploy files from Q4.
56
+ - Env files: write gitignored `backend/.env` and `frontend/.env` with local-dev defaults **and** committed `.env.example` siblings (issue asked for env files; Q4 asked for examples).
57
+ - Dockerfile: **consumer** backend image (`oven/bun:1-slim` or `oven/bun:1`, bind `0.0.0.0`, `PORT` from env, health on `/health`). Not the monorepo `example-backend/Dockerfile`.
58
+ - Non-empty: refuse if the target exists and contains anything other than `.git` / `.gitignore`.
59
+ - Hosted write guard: `terreno-mcp-local` sets `TERRENO_MCP_WRITE_SCAFFOLD=1`. HTTP hosted MCP never sets it and **ignores** `targetDir` even if passed.
60
+ - `targetDir` must be an absolute path; local MCP resolves and writes `join(targetDir, appName)` only if that path is empty as above. Do not write `/` or home without an explicit `appName` subdirectory.
61
+ - Publish: add `create-terreno-app` to tag publish (GitHub workflow + CircleCI `publish-package`) as an unscoped package. Changelog lockstep sentence gains this package.
62
+ - npm name `create-terreno-app` must be available under the publishing npm user; if publish fails on name claim, that is an **access** blocker, not a redesign.
63
+
64
+ ## Architecture
65
+
66
+ ```
67
+ bunx create-terreno-app my-app --display-name "My App"
68
+ │
69
+ ▼
70
+ create-terreno-app (bin)
71
+ parse flags → writeScaffold({appName, appDisplayName, targetDir})
72
+ │
73
+ ▼
74
+ generateAllFiles(args) ◄──── terreno_bootstrap_app (MCP)
75
+ │ │
76
+ │ ├─ TERRENO_MCP_WRITE_SCAFFOLD=1 + targetDir
77
+ │ │ → writeScaffold (local)
78
+ │ └─ else → markdown: CLI command + file dump
79
+ ▼
80
+ <dir>/backend + frontend + Dockerfile + .env(.example) + seed + CI + MCP config
81
+ ```
82
+
83
+ Public seams Pick must test:
84
+
85
+ | Seam | Behavior |
86
+ | --- | --- |
87
+ | `create-terreno-app` bin | Writes files; exits non-zero on missing `appName`, missing display name without `--yes`, or non-empty target |
88
+ | `generateAllFiles` | Returns the file list; `@terreno/*` versions are `^` + package version; includes Dockerfile and `.env.example` |
89
+ | `writeScaffold` | Creates files on disk; does not run `bun install` |
90
+ | `handleBootstrapToolCall` | Dump path unchanged in shape (instructions mention CLI); write path creates files only when the env guard is set |
91
+
92
+ ## Models / APIs / Notifications / UI
93
+
94
+ None. Scaffolded consumer apps keep the current bootstrap Todo + User + admin + Better Auth + syncdb shape.
95
+
96
+ ## CLI contract
97
+
98
+ ```bash
99
+ bunx create-terreno-app <appName> --display-name <string> [--description <string>] [--mcp-server-url <url>] [--yes]
100
+ npm create terreno-app <appName> -- --display-name <string>
101
+ ```
102
+
103
+ | Flag | Required | Default |
104
+ | --- | --- | --- |
105
+ | `appName` (positional) | yes | — (kebab-case; used as directory and package names) |
106
+ | `--display-name` | unless `--yes` | derived from `appName` when `--yes` |
107
+ | `--description` | no | empty |
108
+ | `--mcp-server-url` | no | current bootstrap default |
109
+ | `--yes` | no | off |
110
+
111
+ Print next commands (install, Mongo replica set, seed, sdk, web) after a successful write. Do not execute them.
112
+
113
+ ## MCP contract
114
+
115
+ `terreno_bootstrap_app` keeps `appName`, `appDisplayName`, `description`, `mcpServerUrl`, and adds:
116
+
117
+ | Param | Required | Role |
118
+ | --- | --- | --- |
119
+ | `targetDir` | no | Absolute directory that will contain `<appName>/` |
120
+
121
+ Write iff `targetDir` is set **and** `TERRENO_MCP_WRITE_SCAFFOLD=1`. Otherwise return the CLI one-liner plus the existing file dump (dump stays so hosted agents without shell can still materialize files).
122
+
123
+ `terreno_bootstrap_ai_rules` stays in `@terreno/mcp` (not this CLI).
124
+
125
+ ## Phases
126
+
127
+ 1. **Extract generator** — move file generation + existing bootstrap app tests into `create-terreno-app`; MCP imports the package; versions become `^<cli version>`.
128
+ 2. **CLI writer** — bin, flags, `writeScaffold`, refuse non-empty, print next steps.
129
+ 3. **Deploy files** — consumer Dockerfile, `.env.example`, README deploy section linking baseline + GCP/web how-tos.
130
+ 4. **MCP delegate** — `targetDir` + write guard; dump mentions CLI; local write tests.
131
+ 5. **Docs, publish, skills** — tutorial/how-to/reference, `build-terreno-app` Phase 2, workspace + publish jobs, changelog fragment.
132
+
133
+ ## Feature Flags & Migrations
134
+
135
+ None. Additive package + MCP params. Existing dump-only MCP clients keep working.
136
+
137
+ ## Not Included / Future Work
138
+
139
+ - GitHub template generated from the same `generateAllFiles`
140
+ - `--no-admin`, extra example slices, Windows-specific path docs
141
+ - Running install/seed from the CLI
142
+ - Provider-specific deploy folders
143
+
144
+ ## Files to Create / Modify
145
+
146
+ | Path | Change |
147
+ | --- | --- |
148
+ | `create-terreno-app/` | New workspace package (src, tests, `package.json` bin, README) |
149
+ | `mcp-server/src/bootstrap.ts` | Thin: args + MCP write/dump; import generator |
150
+ | `mcp-server/src/__tests__/bootstrap.test.ts` | Dump + write-guard tests; generation assertions live in the CLI package |
151
+ | `mcp-server/package.json` | `create-terreno-app` workspace dependency |
152
+ | `package.json` | Workspace entry; optional root script |
153
+ | `.github/workflows/publish-on-tag.yml` + CircleCI publish | Publish unscoped `create-terreno-app` |
154
+ | `docs/tutorials/getting-started.md` | First path is the CLI; clone-examples remains secondary |
155
+ | `docs/how-to/create-a-terreno-app.md` | Flags, layout, run, deploy pointers |
156
+ | `docs/reference/mcp-server.md` | Delegate + `targetDir` |
157
+ | `docs/README.md`, `docs/how-to/README.md` | Index the how-to and package |
158
+ | `.rulesync/skills/build-terreno-app/SKILL.md` | Phase 2 uses the CLI (MCP dump is fallback) |
159
+ | `changelog/unreleased/create-terreno-app.md` | Added |
160
+ | `mcp-server/src/docs/upgrades/<next>.md` | If the release notes file for the next version exists, mention the CLI |
161
+
162
+ ## Task List
163
+
164
+ [`docs/tasks/create-terreno-app.md`](../tasks/create-terreno-app.md)
165
+
166
+ ## Acceptance Criteria
167
+
168
+ - [ ] `bunx create-terreno-app <tmp>/my-app --display-name "My App"` writes backend + frontend and exits 0
169
+ - [ ] Non-empty target exits non-zero and writes nothing
170
+ - [ ] Generated `@terreno/*` dependencies are `^` + the CLI package version, not `latest`
171
+ - [ ] Scaffold includes consumer `Dockerfile`, `.env.example`, seed script, and README deploy links
172
+ - [ ] `terreno_bootstrap_app` without write guard still returns markdown dump that names the CLI
173
+ - [ ] `terreno_bootstrap_app` with write guard + `targetDir` writes the same files as the CLI
174
+ - [ ] Hosted path cannot write even if `targetDir` is passed
175
+ - [ ] Docs: getting-started, create how-to, MCP reference, build-terreno-app skill
176
+ - [ ] Package is in the workspace and on the publish list
177
+ - [ ] Focused bun tests cover CLI, generator versions, MCP dump vs write
@@ -0,0 +1,219 @@
1
+ # Implementation Plan: DataTable server-side filtering and search
2
+
3
+ **Status:** Approved
4
+ **Branch:** `cursor/datatable-server-side-filtering-191d`
5
+ **Owner:** —
6
+ **Created:** 2026-09-10
7
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1177 (this feature **closes** that issue; implementation PRs use `Fixes #1177`)
8
+ **Task list:** [datatable-server-side-filtering.md](../tasks/datatable-server-side-filtering.md)
9
+ **Depends on:** —
10
+ **RTK deprecation flag:** Partial — `@terreno/ui` stays data-layer agnostic; AdminModelTable keeps RTK `useListQuery`; syncdb is out of scope
11
+
12
+ ## Goal
13
+
14
+ `DataTable` grows optional, controlled filter and search chrome that emits a JavaScript object of [modelRouter](../how-to/create-a-model.md) list params (`queryFields` equality, nested `$in` / `$regex` / `$gte`/`$lte`, date `field_gte`/`field_lte`, search `$or`). Parents pass that object to RTK, `fetch`, or any client. `AdminModelTable` uses the same UI and drops `AdminFilterDrawer`.
15
+
16
+ ## Non-Goals
17
+
18
+ - Changing modelRouter list semantics or adding a new list query language.
19
+ - Changing admin `q` / `buildAdminPartialSearchFilter` (ObjectId match stays on the backend).
20
+ - Client-side filtering of the `data` prop.
21
+ - Nested `$and`/`$or` query-builder UI.
22
+ - Multi-select `$in` on admin `ref` (single ObjectId only).
23
+ - Syncdb `useQuery` list wiring.
24
+ - Making `Filter` itself universal (native uses a `Modal` sheet).
25
+
26
+ ## Decisions
27
+
28
+ | Question | Decision |
29
+ |----------|----------|
30
+ | Emission | Presentational `onQueryChange(params)` JS object. Page/sort stay the existing callbacks. Parent merges. |
31
+ | Operators | Text contains (`$regex` + `$options: "i"`, escaped); boolean equality; date `field_gte`/`field_lte`; number `{field: {$gte,$lte}}`; choice multi-select `{field: {$in: values}}`. |
32
+ | Search | Generic: `$or` of escaped `$regex` on caller `searchFields`. Admin: toolbar string → `q` only (do not send `$or`; parser rejects top-level operators). |
33
+ | Admin chrome | One surface: DataTable search + column filters. Remove `AdminFilterDrawer`. `ref` uses column `renderFilter`. |
34
+ | Native | One “Filters” `Modal`/`ActionSheet` with every column filter + search. Web: per-column `Filter` popovers. |
35
+ | Control | Filter/search state is controlled like `page` / `sortColumn`. Search debounce matches admin (existing delay). |
36
+ | Admin parser | Extend `parseAdminListFilters` for choice `$in` (allowed values only) and text `{ $regex, $options: "i" }`. Keep rejecting undeclared `$or`. |
37
+
38
+ ## Architecture
39
+
40
+ ```
41
+ DataTable (optional filter/search props)
42
+ web: header Filter popover per filterable column
43
+ native: one Filters sheet
44
+ → buildDataTableListQuery(state) → onQueryChange(params)
45
+
46
+ Parent
47
+ generic modelRouter: pass params to list GET (qs.stringify nested ops)
48
+ AdminModelTable: strip $or; set q from search; keep $in / ranges / equality; RTK useListQuery
49
+ ```
50
+
51
+ `@terreno/ui` must not import RTK, admin, or axios. Export `buildDataTableListQuery` and filter types next to DataTable.
52
+
53
+ ### Public types (sketch)
54
+
55
+ ```typescript
56
+ interface DataTableColumnFilterChoiceOption {
57
+ label: string;
58
+ value: string;
59
+ }
60
+
61
+ interface DataTableColumnFilter {
62
+ field: string;
63
+ kind: "text" | "boolean" | "numberRange" | "dateRange" | "choice";
64
+ options?: DataTableColumnFilterChoiceOption[]; // choice
65
+ renderFilter?: (args: {
66
+ field: string;
67
+ value: unknown;
68
+ onChange: (value: unknown) => void;
69
+ }) => React.ReactNode;
70
+ }
71
+
72
+ interface DataTableQueryParams {
73
+ [field: string]: unknown;
74
+ $or?: Array<Record<string, unknown>>;
75
+ }
76
+
77
+ interface DataTableProps {
78
+ // existing page / sort / data ...
79
+ search?: string;
80
+ searchFields?: string[];
81
+ onSearchChange?: (search: string) => void;
82
+ filterValues?: Record<string, unknown>;
83
+ onFilterValuesChange?: (next: Record<string, unknown>) => void;
84
+ onQueryChange?: (params: DataTableQueryParams) => void;
85
+ }
86
+ ```
87
+
88
+ `DataTableColumn` gains optional `filter?: DataTableColumnFilter`. Omit `filter` → no column control (today’s table). Omit search props → no search box.
89
+
90
+ `onQueryChange` fires when search (debounced) or filters change. It does **not** include `page`, `limit`, or `sort`.
91
+
92
+ ### Query object contract
93
+
94
+ | UI | Wire |
95
+ |----|------|
96
+ | Search (generic) | `$or: [{field: {$regex: escaped, $options: "i"}}, ...]` for `searchFields` |
97
+ | Text column | `{field: {$regex: escaped, $options: "i"}}` |
98
+ | Boolean | `{field: true \| false}`; unset omits the key |
99
+ | Date range | `field_gte` / `field_lte` ISO strings (modelRouter Date merge) |
100
+ | Number range | `{field: {$gte?: number, $lte?: number}}` |
101
+ | Choice (one or many) | `{field: {$in: string[]}}` even for a single value |
102
+ | Empty filter | key omitted |
103
+
104
+ Escape every user regex with the same rules as `escapeRegexLiteral` in `admin-backend/src/adminTextSearch.ts` (copy into ui; do not import admin-backend).
105
+
106
+ ### Native vs web
107
+
108
+ | Platform | Chrome |
109
+ |----------|--------|
110
+ | Web | Toolbar `TextField` search; per-column header icon opens existing `Filter` (Apply/Clear). Choice uses `MultiselectField`. |
111
+ | Native | Toolbar search + one “Filters” control opening `Modal` (or existing mobile sheet pattern from admin: `ADMIN_FILTER_MOBILE_BREAKPOINT`). Same `filterValues` / `onQueryChange`. |
112
+
113
+ ### Admin adoption
114
+
115
+ `AdminModelTable` maps `modelConfig.filters` onto `DataTableColumn.filter`:
116
+
117
+ | Admin kind | DataTable kind |
118
+ |------------|----------------|
119
+ | `text` | `text` (contains; documented behavior change from exact match) |
120
+ | `boolean` | `boolean` |
121
+ | `dateRange` | `dateRange` |
122
+ | `choice` | `choice` + `options` from `choices` |
123
+ | `ref` | `choice`-shaped slot with `renderFilter` wrapping `AdminRefField` (single id) |
124
+
125
+ `buildAdminListQueryParams` consumes DataTable state:
126
+
127
+ 1. Copy filter params except `$or`.
128
+ 2. If `searchFields.length && search.trim()`, set `q`.
129
+ 3. Keep `limit`, `page`, `sort`.
130
+
131
+ Delete `AdminFilterDrawer` usage from the table. Keep the module only if another screen still imports it; otherwise remove export after table tests prove the new path.
132
+
133
+ `parseAdminListFilters` today rejects objects on choice/text and any top-level `$` key. This slice:
134
+
135
+ - Parses `role: { $in: ["staff", "admin"] }` when every value is in `choices`.
136
+ - Parses text `{ $regex: string, $options: "i" }` (regex already escaped by the client).
137
+ - Still errors on top-level `$or` / `$and`.
138
+
139
+ ### Compatibility
140
+
141
+ Existing `DataTable` callers with no filter/search props are unchanged (no chrome, no callbacks).
142
+
143
+ ## Models
144
+
145
+ None.
146
+
147
+ ## APIs
148
+
149
+ No new HTTP routes. Consumers keep `GET` list with existing `queryFields`. Admin list still uses `q` for search.
150
+
151
+ ## Notifications
152
+
153
+ None.
154
+
155
+ ## UI
156
+
157
+ Demo story: filterable columns + search, mock `onQueryChange` log / JSON. Admin SPA / example admin: Todos or Users list — search, boolean, choice `$in`, date range, ref via custom renderer.
158
+
159
+ ## Phases
160
+
161
+ 1. **Tracer:** query helper + DataTable tests (no fetch).
162
+ 2. **Chrome:** web popovers + native sheet + demo story.
163
+ 3. **Admin parser + table:** `$in` / text regex; drop drawer.
164
+ 4. **Docs:** reference, how-to, seed links, generated component props.
165
+
166
+ ## Feature Flags & Migrations
167
+
168
+ No flag. Admin text filters become contains. Call out in CHANGELOG and admin how-to.
169
+
170
+ ## Activity Log & User Updates
171
+
172
+ - 2026-09-10: Grow approved; next Pick Task 1.1.
173
+
174
+ ## Not Included / Future Work
175
+
176
+ - Multi-select `$in` on `ref`.
177
+ - Client-side filter of `data`.
178
+ - Nested boolean query builder.
179
+ - Universal `Filter` popover on native.
180
+ - Syncdb collection queries.
181
+
182
+ ## Files to Create / Modify
183
+
184
+ | Path | Change |
185
+ |------|--------|
186
+ | `ui/src/Common.ts` | Filter types on `DataTableColumn` / `DataTableProps` |
187
+ | `ui/src/dataTableListQuery.ts` (new) | `buildDataTableListQuery`, regex escape |
188
+ | `ui/src/DataTable.tsx` | Search + column filters + native sheet |
189
+ | `ui/src/DataTable.test.tsx` | Query emission tests |
190
+ | `demo/stories/DataTable.stories.tsx` | Filter/search demo |
191
+ | `admin-backend/src/filterParser.ts` | Choice `$in`, text `$regex` |
192
+ | `admin-backend/src/filterParser.test.ts` | New cases |
193
+ | `admin-frontend/src/AdminModelTable.tsx` | Wire DataTable; remove drawer |
194
+ | `admin-frontend/src/adminModelListQueryParams.ts` | Map search → `q`; pass `$in` |
195
+ | `admin-frontend/src/AdminFilterDrawer.tsx` | Remove if unused |
196
+ | `docs/reference/ui.md` | DataTable filter contract |
197
+ | `docs/how-to/admin-add-model.md` | Filters live on the table; text is contains |
198
+ | `docs/reference/admin-frontend.md` | AdminModelTable |
199
+ | `docs/explanation/admin-interface.md` | Drop drawer as the list filter UI |
200
+ | `docs/explanation/roadmap-seed-issues.md` | IP/task links |
201
+ | `CHANGELOG.md` | Added |
202
+
203
+ Generated `docs/reference/components/` DataTable props via `ui` `bun run types` / `website:generate` in the docs task.
204
+
205
+ ## Task List
206
+
207
+ [datatable-server-side-filtering.md](../tasks/datatable-server-side-filtering.md)
208
+
209
+ ## Acceptance Criteria
210
+
211
+ - [ ] DataTable with no filter/search props matches current sort/page-only UI (unit test).
212
+ - [ ] `buildDataTableListQuery` emits escaped `$regex` `$or` for search and `{field: {$in}}` for multi choice (`bun test ui/src/dataTableListQuery.test.ts` or colocated).
213
+ - [ ] Interacting with web column Filter Apply calls `onQueryChange` with the contract table (`DataTable.test.tsx`).
214
+ - [ ] Native “Filters” sheet applies the same object (`DataTable.test.tsx` with platform mock or sheet testIDs).
215
+ - [ ] Admin list: search still hits `q`; choice multi-select reaches Mongo `$in`; `parseAdminListFilters` rejects top-level `$or` (`filterParser.test.ts` + `AdminModelTable.test.tsx`).
216
+ - [ ] `AdminFilterDrawer` is not rendered on `AdminModelTable`.
217
+ - [ ] Demo story shows search + at least text, boolean, date, and choice filters.
218
+ - [ ] Docs: `docs/reference/ui.md`, admin how-to/reference, generated component props, CHANGELOG.
219
+ - [ ] `bun run analyze:full` clean; frontend verification per `verify-ui-changes` (demo + admin list).