@terreno/mcp 56.0.0-beta.0 → 56.0.0-beta.2

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 (154) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bootstrap.js +7 -7
  3. package/dist/bootstrap.js.map +1 -1
  4. package/dist/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
  5. package/dist/docs/templates/tools/model.template.md +4 -2
  6. package/dist/docs/upgrades/0.31.0.md +60 -0
  7. package/dist/docs/upgrades/56.0.0-beta.2.md +59 -0
  8. package/dist/docs/versioned/next/README.md +1 -0
  9. package/dist/docs/versioned/next/explanation/README.md +7 -1
  10. package/dist/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
  11. package/dist/docs/versioned/next/explanation/deployment-baseline.md +78 -0
  12. package/dist/docs/versioned/next/explanation/positioning.md +164 -0
  13. package/dist/docs/versioned/next/explanation/repository-settings.md +44 -0
  14. package/dist/docs/versioned/next/explanation/roadmap-process.md +330 -0
  15. package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
  16. package/dist/docs/versioned/next/how-to/README.md +8 -0
  17. package/dist/docs/versioned/next/how-to/build-for-web.md +69 -0
  18. package/dist/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
  19. package/dist/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
  20. package/dist/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
  21. package/dist/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
  22. package/dist/docs/versioned/next/implementationPlans/README.md +56 -30
  23. package/dist/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
  24. package/dist/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
  25. package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
  26. package/dist/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
  27. package/dist/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
  28. package/dist/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
  29. package/dist/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
  30. package/dist/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
  31. package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
  32. package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
  33. package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
  34. package/dist/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
  35. package/dist/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
  36. package/dist/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
  37. package/dist/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
  38. package/dist/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
  39. package/dist/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
  40. package/dist/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
  41. package/dist/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
  42. package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
  43. package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
  44. package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
  45. package/dist/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
  46. package/dist/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
  47. package/dist/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
  48. package/dist/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
  49. package/dist/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
  50. package/dist/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
  51. package/dist/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
  52. package/dist/docs/versioned/next/reference/README.md +5 -0
  53. package/dist/docs/versioned/next/reference/admin-spa.md +130 -0
  54. package/dist/docs/versioned/next/reference/ai.md +519 -0
  55. package/dist/docs/versioned/next/reference/comms.md +132 -0
  56. package/dist/docs/versioned/next/reference/environment-variables.md +229 -382
  57. package/dist/docs/versioned/next/reference/test.md +108 -0
  58. package/dist/docs/versioned/next/roadmap.md +9 -0
  59. package/dist/docs/versioned/next/tasks/README.md +42 -0
  60. package/dist/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
  61. package/dist/docs/versioned/next/tasks/billing-stripe.md +75 -0
  62. package/dist/docs/versioned/next/tasks/comms-abstraction.md +90 -0
  63. package/dist/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
  64. package/dist/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
  65. package/dist/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
  66. package/dist/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
  67. package/dist/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
  68. package/dist/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
  69. package/dist/docs/versioned/next/tasks/deployment-foundation.md +12 -12
  70. package/dist/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
  71. package/dist/docs/versioned/next/tasks/infra-mcp.md +43 -0
  72. package/dist/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
  73. package/dist/docs/versioned/next/tasks/native-module-baseline.md +42 -0
  74. package/dist/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
  75. package/dist/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
  76. package/dist/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
  77. package/dist/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
  78. package/dist/docs/versioned/next/tasks/public-roadmap-github.md +15 -15
  79. package/package.json +4 -3
  80. package/src/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
  81. package/src/docs/templates/tools/model.template.md +4 -2
  82. package/src/docs/upgrades/0.31.0.md +60 -0
  83. package/src/docs/upgrades/56.0.0-beta.2.md +59 -0
  84. package/src/docs/versioned/next/README.md +1 -0
  85. package/src/docs/versioned/next/explanation/README.md +7 -1
  86. package/src/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
  87. package/src/docs/versioned/next/explanation/deployment-baseline.md +78 -0
  88. package/src/docs/versioned/next/explanation/positioning.md +164 -0
  89. package/src/docs/versioned/next/explanation/repository-settings.md +44 -0
  90. package/src/docs/versioned/next/explanation/roadmap-process.md +330 -0
  91. package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
  92. package/src/docs/versioned/next/how-to/README.md +8 -0
  93. package/src/docs/versioned/next/how-to/build-for-web.md +69 -0
  94. package/src/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
  95. package/src/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
  96. package/src/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
  97. package/src/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
  98. package/src/docs/versioned/next/implementationPlans/README.md +56 -30
  99. package/src/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
  100. package/src/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
  101. package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
  102. package/src/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
  103. package/src/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
  104. package/src/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
  105. package/src/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
  106. package/src/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
  107. package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
  108. package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
  109. package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
  110. package/src/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
  111. package/src/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
  112. package/src/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
  113. package/src/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
  114. package/src/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
  115. package/src/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
  116. package/src/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
  117. package/src/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
  118. package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
  119. package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
  120. package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
  121. package/src/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
  122. package/src/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
  123. package/src/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
  124. package/src/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
  125. package/src/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
  126. package/src/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
  127. package/src/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
  128. package/src/docs/versioned/next/reference/README.md +5 -0
  129. package/src/docs/versioned/next/reference/admin-spa.md +130 -0
  130. package/src/docs/versioned/next/reference/ai.md +519 -0
  131. package/src/docs/versioned/next/reference/comms.md +132 -0
  132. package/src/docs/versioned/next/reference/environment-variables.md +229 -382
  133. package/src/docs/versioned/next/reference/test.md +108 -0
  134. package/src/docs/versioned/next/roadmap.md +9 -0
  135. package/src/docs/versioned/next/tasks/README.md +42 -0
  136. package/src/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
  137. package/src/docs/versioned/next/tasks/billing-stripe.md +75 -0
  138. package/src/docs/versioned/next/tasks/comms-abstraction.md +90 -0
  139. package/src/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
  140. package/src/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
  141. package/src/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
  142. package/src/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
  143. package/src/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
  144. package/src/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
  145. package/src/docs/versioned/next/tasks/deployment-foundation.md +12 -12
  146. package/src/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
  147. package/src/docs/versioned/next/tasks/infra-mcp.md +43 -0
  148. package/src/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
  149. package/src/docs/versioned/next/tasks/native-module-baseline.md +42 -0
  150. package/src/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
  151. package/src/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
  152. package/src/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
  153. package/src/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
  154. package/src/docs/versioned/next/tasks/public-roadmap-github.md +15 -15
@@ -0,0 +1,147 @@
1
+ # Implementation Plan: Password reset and email verification
2
+
3
+ **Status:** Draft
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1023
5
+ **Priority:** High
6
+ **Effort:** Big batch
7
+ **Owner:** unassigned
8
+ **Created:** 2026-08-09
9
+ **Program:** [B2B platform](b2b-platform-program.md)
10
+ **Depends on:** [comms-abstraction](comms-abstraction.md), [comms-adapter-sendgrid](comms-adapter-sendgrid.md)
11
+ **RTK deprecation flag:** None — the RTK client's existing `resetPassword` endpoint gets a
12
+ backend at last; new client work is a thin screen pair noted in UI
13
+
14
+ ## Goal
15
+
16
+ The JWT auth path has no way to recover an account or verify an email address: the
17
+ `@terreno/rtk` client ships a `resetPassword` mutation with **no backend route**, and
18
+ nothing sets or checks email verification. This IP adds forgot/reset password and email
19
+ verification flows to `@terreno/api`'s JWT auth, wires the Better Auth equivalents to the
20
+ same mail templates, and sends everything through `@terreno/comms`.
21
+
22
+ ## Non-Goals
23
+
24
+ - MFA / step-up auth (`mfa-step-up-auth` item).
25
+ - Magic-link login.
26
+ - SMS-based recovery (possible later via the Twilio Verify adapter).
27
+ - Account lockout / brute-force throttling beyond token single-use + expiry
28
+ (`rate-limiting` item hardens the endpoints).
29
+
30
+ ## Decisions
31
+
32
+ | Question | Decision |
33
+ |----------|----------|
34
+ | Token design | 32-byte crypto-random token, stored **hashed** (sha256) with expiry (`1h` reset / `24h` verify) and single-use consumption; separate `AuthToken` collection rather than fields on User |
35
+ | Enumeration safety | `POST /auth/forgotPassword` always returns 202 regardless of whether the email exists |
36
+ | Password set mechanism | `passport-local-mongoose`'s `setPassword` on the user document, then invalidate all refresh tokens |
37
+ | RTK client compatibility | The existing RTK `resetPassword` endpoint's path/shape is the contract — verify at implementation time and alias if it differs from `/auth/resetPassword` |
38
+ | Verification gating | Opt-in `requireEmailVerification` auth option: unverified users get 403 with code `email-not-verified` on login; default off (non-breaking) |
39
+ | Better Auth path | Enable Better Auth's built-in reset/verification, providing `sendResetPassword` / `sendVerificationEmail` hooks that call the same comms templates so both auth paths send identical mail |
40
+ | Link targets | Deep-link/URL base from a new `authOptions.publicAppUrl`; web route examples in example-frontend |
41
+
42
+ ## Architecture
43
+
44
+ ```
45
+ api/src/authTokens.ts # AuthToken model + issue/consume helpers
46
+ api/src/authRecovery.ts # forgot/reset/verify routes + options
47
+ # registered by addAuthRoutes when comms is available
48
+ comms templates # resetPassword + verifyEmail templates (subject/text/html)
49
+ ```
50
+
51
+ Flow (reset): `POST /auth/forgotPassword {email}` → 202 always; if user exists, issue
52
+ token, send mail with `${publicAppUrl}/resetPassword?token=...` → `POST
53
+ /auth/resetPassword {token, password}` → validate + consume token, `setPassword`,
54
+ invalidate refresh tokens, 200.
55
+
56
+ Flow (verify): token issued on signup (and via `POST /auth/sendVerification` for
57
+ re-sends, authenticated); `POST /auth/verifyEmail {token}` sets `user.emailVerified =
58
+ true`.
59
+
60
+ ## Models
61
+
62
+ **AuthToken** — `userId` (ref User, required, indexed), `tokenHash` (string, unique),
63
+ `type` ("passwordReset" | "emailVerification"), `expiresAt` (date, TTL-indexed),
64
+ `consumedAt` (date, optional). Statics: `issueFor(user, type)`, `consume(token, type)`
65
+ (atomic findOneAndUpdate guarding single-use).
66
+
67
+ **User** — adds `emailVerified` (boolean, default false) via a small
68
+ `emailVerificationPlugin` so existing user schemas opt in without breaking.
69
+
70
+ ## APIs
71
+
72
+ | Method | Path | Permissions | Notes |
73
+ |---|---|---|---|
74
+ | POST | `/auth/forgotPassword` | anonymous | `{email}` → always 202 |
75
+ | POST | `/auth/resetPassword` | anonymous | `{token, password}`; path/shape matched to the RTK client contract |
76
+ | POST | `/auth/sendVerification` | IsAuthenticated | Re-send verification mail |
77
+ | POST | `/auth/verifyEmail` | anonymous | `{token}` |
78
+
79
+ All registered by `addAuthRoutes` when a mail-capable `CommsApp` is present; without one,
80
+ routes 501 in production and console-send in development (inherited comms behavior).
81
+
82
+ ## Notifications
83
+
84
+ Two mail templates (`resetPassword`, `verifyEmail`) shipped in `@terreno/comms` templates
85
+ with app-override hooks.
86
+
87
+ ## UI
88
+
89
+ example-frontend: `/resetPassword` (token from URL, new-password form using the existing
90
+ RTK `resetPassword` mutation) and a "verify your email" banner + re-send button on the
91
+ profile screen. `LoginScreen` gains an optional `onForgotPassword` link prop in
92
+ `@terreno/ui`.
93
+
94
+ ## Phases
95
+
96
+ 1. **Token infrastructure:** AuthToken model, issue/consume, `emailVerificationPlugin`,
97
+ unit tests.
98
+ 2. **JWT routes + mail:** four routes, templates, refresh-token invalidation,
99
+ enumeration-safety + single-use/expiry test suite.
100
+ 3. **Better Auth parity:** wire `sendResetPassword`/`sendVerificationEmail` hooks to the
101
+ same templates; parity tests.
102
+ 4. **Client + docs:** example-frontend screens, `@terreno/ui` login link prop, SDK regen,
103
+ `docs/how-to/password-reset.md`, env/reference docs.
104
+
105
+ ## Feature Flags & Migrations
106
+
107
+ `requireEmailVerification` defaults off; enabling it for an existing app is documented
108
+ (backfill `emailVerified: true` for existing users or accept re-verification). No schema
109
+ migration otherwise.
110
+
111
+ ## Activity Log & User Updates
112
+
113
+ Token issue/consume and verification events logged via `logger` and `CommsMessage`
114
+ rows; no user-facing activity feed.
115
+
116
+ ## Not Included / Future Work
117
+
118
+ - Password strength policy hooks (exists via `PasswordRequirements` UI; server policy is
119
+ future work).
120
+ - Admin-triggered forced resets (admin panel action — future).
121
+ - Endpoint rate limiting (`rate-limiting` item).
122
+
123
+ ## Files to Create / Modify
124
+
125
+ - `api/src/authTokens.ts`, `api/src/authRecovery.ts` (new), `api/src/auth.ts`,
126
+ `api/src/plugins.ts` (emailVerificationPlugin), `api/src/index.ts`
127
+ - `comms/src/templates.ts` — two templates
128
+ - `example-frontend/app/resetPassword.tsx`, profile banner, SDK regen
129
+ - `ui/src/login/LoginScreen.tsx` — `onForgotPassword` prop
130
+ - `docs/how-to/password-reset.md`, `docs/reference/environment-variables.md`
131
+
132
+ ## Task List
133
+
134
+ See [docs/tasks/password-reset-and-email-verification.md](../tasks/password-reset-and-email-verification.md).
135
+
136
+ ## Acceptance Criteria
137
+
138
+ - [ ] `POST /auth/forgotPassword` returns 202 for existing and non-existing emails alike,
139
+ sending mail only for existing ones.
140
+ - [ ] A reset token works exactly once, fails after expiry, and a successful reset
141
+ invalidates outstanding refresh tokens.
142
+ - [ ] The unmodified RTK client `resetPassword` mutation completes the flow end to end.
143
+ - [ ] With `requireEmailVerification` on, an unverified user gets 403 code
144
+ `email-not-verified` on login and can complete verification to proceed.
145
+ - [ ] Better Auth mode sends the same two templates through comms.
146
+ - [ ] example-frontend can complete forgot → email link (console adapter output in dev) →
147
+ reset → login with the new password; UI verification evidence attached to the PR.
@@ -1,6 +1,7 @@
1
1
  # Implementation Plan: Positioning — "Django/Rails for TypeScript, with Universal Apps"
2
2
 
3
3
  **Status:** Draft — blocking questions open
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1008
4
5
  **Priority:** High
5
6
  **Effort:** Small batch
6
7
  **Owner:** unassigned
@@ -1,6 +1,7 @@
1
1
  # Implementation Plan: Public Roadmap on GitHub
2
2
 
3
3
  **Status:** Approved — decisions recorded (2026-07-29)
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1004
4
5
  **Priority:** High
5
6
  **Effort:** Small batch
6
7
  **Owner:** unassigned
@@ -1,6 +1,7 @@
1
1
  # Implementation Plan: Upgrade Guides and the `upgrading-terreno` Skill
2
2
 
3
3
  **Status:** Draft — blocked on PR #869
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1013
4
5
  **Priority:** High
5
6
  **Effort:** Big batch
6
7
  **Owner:** unassigned
@@ -1,6 +1,7 @@
1
1
  # Implementation Plan: Server-Side Rendering for Universal Web (and Admin SPA)
2
2
 
3
3
  **Status:** Draft — blocking questions open
4
+ **Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1017
4
5
  **Priority:** Medium
5
6
  **Effort:** Epic
6
7
  **Owner:** unassigned
@@ -8,10 +8,15 @@ Technical reference for Terreno packages and APIs. Information-oriented, precise
8
8
  - [@terreno/ui](ui.md) — Components, theming, layout
9
9
  - [@terreno/rtk](rtk.md) — Auth slice, SDK codegen, token handling
10
10
  - [@terreno/syncdb](syncdb.md) — Local-first data layer (reads, writes, offline sync)
11
+ - [@terreno/ai](ai.md) — AI service, GPT routes, Langfuse integration
11
12
  - [@terreno/admin-backend](admin-backend.md) — Auto-generated admin CRUD endpoints
12
13
  - [@terreno/admin-frontend](admin-frontend.md) — Admin panel UI components
14
+ - [@terreno/admin-spa](admin-spa.md) — Standalone admin SPA + Express serve plugin
15
+ - [@terreno/api-health](api-health.md) — Health check TerrenoPlugin
16
+ - [@terreno/comms](comms.md) — Pluggable mail, SMS, push, and verification providers
13
17
  - [@terreno/feature-flags](feature-flags.md) — Feature flags and A/B testing plugin
14
18
  - [@terreno/mcp](mcp-server.md) — AI coding assistant integration (MCP)
19
+ - [@terreno/test](test.md) — Bun test helpers and in-memory MongoDB
15
20
 
16
21
  ## Configuration
17
22
 
@@ -0,0 +1,130 @@
1
+ # @terreno/admin-spa
2
+
3
+ Standalone Expo Router admin web SPA plus an Express plugin (`AdminSpaServeApp`) that serves the pre-built static export from a Terreno backend on the same origin.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Install](#install)
8
+ - [Commands](#commands)
9
+ - [Architecture](#architecture)
10
+ - [AdminSpaServeApp](#adminspaserveapp)
11
+ - [App config](#app-config)
12
+ - [Serving and caching](#serving-and-caching)
13
+ - [Mount path constraint](#mount-path-constraint)
14
+ - [Standalone SPA vs embedded admin-frontend](#standalone-spa-vs-embedded-admin-frontend)
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ bun add @terreno/admin-spa @terreno/api
20
+ ```
21
+
22
+ `@terreno/api` is a peer dependency (TerrenoPlugin registration).
23
+
24
+ ## Commands
25
+
26
+ From the `@terreno/admin-spa` package directory:
27
+
28
+ ```bash
29
+ bun run compile # Compile the server plugin (src/ -> src/dist)
30
+ bun run build:web # Expo static export into dist/
31
+ bun run dev # expo start --web --port 8083
32
+ bun run test:ci # Serve-plugin unit tests
33
+ bun run smoke # Smoke test over built dist/
34
+ bun run test:e2e # Playwright e2e over built dist/
35
+ ```
36
+
37
+ ## Architecture
38
+
39
+ ```
40
+ admin-spa/
41
+ src/
42
+ serve.ts # AdminSpaServeApp TerrenoPlugin
43
+ appConfig.ts # AdminSpaAppConfig defaults + merge helper
44
+ index.ts # Public exports
45
+ app/ # Expo Router SPA (Better Auth + admin screens)
46
+ store/ # Redux + Better Auth client
47
+ dist/ # Pre-built static export (produced by build:web)
48
+ ```
49
+
50
+ Boot flow in the SPA: `AppConfigGate` fetches `${basePath}/app-config.json` → `StoreProvider` builds Better Auth + Redux → `AdminGate` redirects anonymous users to `/login` and non-admins to `/forbidden`.
51
+
52
+ ## AdminSpaServeApp
53
+
54
+ `AdminSpaServeApp` implements `TerrenoPlugin`. Register it on `TerrenoApp` alongside `AdminApp` and auth plugins:
55
+
56
+ ```typescript
57
+ import {AdminSpaServeApp} from "@terreno/admin-spa";
58
+ import {AdminApp} from "@terreno/admin-backend";
59
+ import {BetterAuthApp, TerrenoApp} from "@terreno/api";
60
+
61
+ new TerrenoApp({userModel: User})
62
+ .register(new BetterAuthApp({config: betterAuthConfig, userModel: User}))
63
+ .register(new AdminApp({models: [...]}))
64
+ .register(
65
+ new AdminSpaServeApp({
66
+ basePath: "/console",
67
+ appConfig: {brandName: "Acme Admin", providers: ["email", "google"]},
68
+ devProxyTarget: process.env.ADMIN_SPA_DEV_PROXY,
69
+ })
70
+ )
71
+ .start();
72
+ ```
73
+
74
+ `example-backend` registers the plugin when `ADMIN_SPA_ENABLED=true`, with optional `ADMIN_SPA_DEV_PROXY` and `ADMIN_SPA_DIST_DIR` overrides.
75
+
76
+ ### AdminSpaServeOptions
77
+
78
+ | Option | Default | Description |
79
+ |--------|---------|-------------|
80
+ | `basePath` | `"/console"` | URL prefix where the SPA is mounted. Admin API stays at `/admin`. |
81
+ | `appConfig` | see [App config](#app-config) | Partial config merged over defaults; served at `${basePath}/app-config.json`. |
82
+ | `distDir` | `<package>/dist` | Directory containing the pre-built static export (tests/custom builds). |
83
+ | `devProxyTarget` | — | When set, proxy all SPA paths to a running `expo start --web` server (e.g. `http://localhost:8083`). `app-config.json` is still served by the plugin. |
84
+
85
+ ### Utility exports
86
+
87
+ - `rewriteIndexHtml(html, basePath)` — Rewrites absolute `/_expo/` and `/assets/` refs for sub-path mounts.
88
+ - `injectBaseGlobal(html, basePath)` — Injects `window.__ADMIN_SPA_BASE__` before `</head>`.
89
+ - `resolveAppConfig(overrides?)` — Merge partial config with `DEFAULT_APP_CONFIG`.
90
+ - `DEFAULT_APP_CONFIG` — Default `app-config.json` values.
91
+
92
+ ## App config
93
+
94
+ `AdminSpaAppConfig` fields (from `appConfig.ts`):
95
+
96
+ | Field | Default | Description |
97
+ |-------|---------|-------------|
98
+ | `brandName` | `"Terreno Admin"` | Header brand name |
99
+ | `logoUrl` | — | Optional logo URL (absolute or relative) |
100
+ | `primaryColor` | `"#2563EB"` | Primary brand color (hex) |
101
+ | `providers` | `["email"]` | Login providers: `"email"`, `"google"`, `"github"`, `"apple"` |
102
+ | `authBasePath` | `"/api/auth"` | Better Auth routes on this origin |
103
+ | `adminApiBasePath` | `"/admin"` | Admin API base path on this origin |
104
+
105
+ ## Serving and caching
106
+
107
+ **Production (no `devProxyTarget`):**
108
+
109
+ 1. `${basePath}/_expo` and `${basePath}/assets` — `express.static` with `maxAge: 365d`, `immutable: true`.
110
+ 2. `${basePath}/app-config.json` — `Cache-Control: no-store`.
111
+ 3. `${basePath}` and `${basePath}/*splat` — SPA fallback returns rewritten `index.html` with `Cache-Control: no-store`.
112
+
113
+ `index.html` is read once at startup; asset paths are rewritten to `${basePath}/...` and `window.__ADMIN_SPA_BASE__` is injected for deep-link config fetches.
114
+
115
+ **Development (`devProxyTarget` set):**
116
+
117
+ - `${basePath}/app-config.json` served locally (no cache).
118
+ - All other `${basePath}/*` requests proxied to the Expo dev server (WebSocket enabled).
119
+
120
+ If no bundle exists at `distDir/index.html`, the plugin logs a warning suggesting `bun run --filter '@terreno/admin-spa' build:web` or `devProxyTarget`.
121
+
122
+ ## Mount path constraint
123
+
124
+ The default web export is built with `experiments.baseUrl: "/console"`, so `basePath` must match. To mount elsewhere, rebuild with a matching base (e.g. `EXPO_BASE_URL=/admin-ui bun run build:web`) and set `basePath` accordingly. Mounting at `/` requires a root-base build and `basePath: "/"`.
125
+
126
+ ## Standalone SPA vs embedded admin-frontend
127
+
128
+ Use **`@terreno/admin-spa`** when you want a complete admin UI served from the API process (same-origin Better Auth cookies, no separate static deploy). The backend image stays lean until you opt in by registering `AdminSpaServeApp`.
129
+
130
+ Use **`@terreno/admin-frontend`** when admin screens live inside your main Expo app (e.g. `example-frontend/app/admin/*`). You bring your own routing, auth, and deploy; the package supplies reusable list/table/form components and hooks against `/admin` CRUD routes from `@terreno/admin-backend`.