@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.
- package/LICENSE +21 -0
- package/dist/bootstrap.js +7 -7
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
- package/dist/docs/templates/tools/model.template.md +4 -2
- package/dist/docs/upgrades/0.31.0.md +60 -0
- package/dist/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/dist/docs/versioned/next/README.md +1 -0
- package/dist/docs/versioned/next/explanation/README.md +7 -1
- package/dist/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
- package/dist/docs/versioned/next/explanation/deployment-baseline.md +78 -0
- package/dist/docs/versioned/next/explanation/positioning.md +164 -0
- package/dist/docs/versioned/next/explanation/repository-settings.md +44 -0
- package/dist/docs/versioned/next/explanation/roadmap-process.md +330 -0
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
- package/dist/docs/versioned/next/how-to/README.md +8 -0
- package/dist/docs/versioned/next/how-to/build-for-web.md +69 -0
- package/dist/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
- package/dist/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
- package/dist/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
- package/dist/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
- package/dist/docs/versioned/next/implementationPlans/README.md +56 -30
- package/dist/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
- package/dist/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
- package/dist/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
- package/dist/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
- package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/dist/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/dist/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
- package/dist/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
- package/dist/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
- package/dist/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
- package/dist/docs/versioned/next/reference/README.md +5 -0
- package/dist/docs/versioned/next/reference/admin-spa.md +130 -0
- package/dist/docs/versioned/next/reference/ai.md +519 -0
- package/dist/docs/versioned/next/reference/comms.md +132 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +229 -382
- package/dist/docs/versioned/next/reference/test.md +108 -0
- package/dist/docs/versioned/next/roadmap.md +9 -0
- package/dist/docs/versioned/next/tasks/README.md +42 -0
- package/dist/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
- package/dist/docs/versioned/next/tasks/billing-stripe.md +75 -0
- package/dist/docs/versioned/next/tasks/comms-abstraction.md +90 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
- package/dist/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
- package/dist/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/dist/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
- package/dist/docs/versioned/next/tasks/deployment-foundation.md +12 -12
- package/dist/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
- package/dist/docs/versioned/next/tasks/infra-mcp.md +43 -0
- package/dist/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/dist/docs/versioned/next/tasks/native-module-baseline.md +42 -0
- package/dist/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
- package/dist/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
- package/dist/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
- package/dist/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
- package/dist/docs/versioned/next/tasks/public-roadmap-github.md +15 -15
- package/package.json +4 -3
- package/src/docs/templates/bootstrap/backend/types/models/userTypes.template.md +5 -4
- package/src/docs/templates/tools/model.template.md +4 -2
- package/src/docs/upgrades/0.31.0.md +60 -0
- package/src/docs/upgrades/56.0.0-beta.2.md +59 -0
- package/src/docs/versioned/next/README.md +1 -0
- package/src/docs/versioned/next/explanation/README.md +7 -1
- package/src/docs/versioned/next/explanation/deployment-architecture-gcp.md +65 -0
- package/src/docs/versioned/next/explanation/deployment-baseline.md +78 -0
- package/src/docs/versioned/next/explanation/positioning.md +164 -0
- package/src/docs/versioned/next/explanation/repository-settings.md +44 -0
- package/src/docs/versioned/next/explanation/roadmap-process.md +330 -0
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +887 -0
- package/src/docs/versioned/next/how-to/README.md +8 -0
- package/src/docs/versioned/next/how-to/build-for-web.md +69 -0
- package/src/docs/versioned/next/how-to/deploy-backend-to-cloud-run.md +115 -0
- package/src/docs/versioned/next/how-to/deploy-to-gcp.md +20 -228
- package/src/docs/versioned/next/how-to/deploy-web-to-gcs-cdn.md +183 -0
- package/src/docs/versioned/next/implementationPlans/PLAN_INDEX.md +31 -0
- package/src/docs/versioned/next/implementationPlans/README.md +56 -30
- package/src/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +2 -1
- package/src/docs/versioned/next/implementationPlans/ai-dev-loop-boost.md +1 -0
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +115 -0
- package/src/docs/versioned/next/implementationPlans/billing-stripe.md +158 -0
- package/src/docs/versioned/next/implementationPlans/build-terreno-app-validation.md +1 -0
- package/src/docs/versioned/next/implementationPlans/comms-abstraction.md +323 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-expo-push.md +107 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +157 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-sms.md +155 -0
- package/src/docs/versioned/next/implementationPlans/comms-adapter-twilio-verify.md +99 -0
- package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +180 -0
- package/src/docs/versioned/next/implementationPlans/deploy-to-gcp.md +1 -0
- package/src/docs/versioned/next/implementationPlans/deploy-to-vercel.md +1 -0
- package/src/docs/versioned/next/implementationPlans/deployment-foundation.md +1 -0
- package/src/docs/versioned/next/implementationPlans/docs-reference-coverage.md +1 -0
- package/src/docs/versioned/next/implementationPlans/docs-tutorials-ai-first.md +1 -0
- package/src/docs/versioned/next/implementationPlans/examples-demo-coverage.md +1 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp-research.md +188 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp.md +269 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +126 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +269 -0
- package/src/docs/versioned/next/implementationPlans/native-module-baseline.md +105 -0
- package/src/docs/versioned/next/implementationPlans/orgs-and-teams.md +158 -0
- package/src/docs/versioned/next/implementationPlans/oss-governance-baseline.md +1 -0
- package/src/docs/versioned/next/implementationPlans/password-reset-and-email-verification.md +147 -0
- package/src/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -0
- package/src/docs/versioned/next/implementationPlans/public-roadmap-github.md +1 -0
- package/src/docs/versioned/next/implementationPlans/upgrade-guides-and-skill.md +1 -0
- package/src/docs/versioned/next/implementationPlans/web-ssr-and-admin-spa.md +1 -0
- package/src/docs/versioned/next/reference/README.md +5 -0
- package/src/docs/versioned/next/reference/admin-spa.md +130 -0
- package/src/docs/versioned/next/reference/ai.md +519 -0
- package/src/docs/versioned/next/reference/comms.md +132 -0
- package/src/docs/versioned/next/reference/environment-variables.md +229 -382
- package/src/docs/versioned/next/reference/test.md +108 -0
- package/src/docs/versioned/next/roadmap.md +9 -0
- package/src/docs/versioned/next/tasks/README.md +42 -0
- package/src/docs/versioned/next/tasks/agentic-sdlc-plugin.md +5 -5
- package/src/docs/versioned/next/tasks/billing-stripe.md +75 -0
- package/src/docs/versioned/next/tasks/comms-abstraction.md +90 -0
- package/src/docs/versioned/next/tasks/comms-adapter-expo-push.md +29 -0
- package/src/docs/versioned/next/tasks/comms-adapter-sendgrid.md +39 -0
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-sms.md +39 -0
- package/src/docs/versioned/next/tasks/comms-adapter-twilio-verify.md +19 -0
- package/src/docs/versioned/next/tasks/comms-admin-dashboard.md +52 -0
- package/src/docs/versioned/next/tasks/deploy-to-gcp.md +11 -11
- package/src/docs/versioned/next/tasks/deployment-foundation.md +12 -12
- package/src/docs/versioned/next/tasks/docs-reference-coverage.md +4 -4
- package/src/docs/versioned/next/tasks/infra-mcp.md +43 -0
- package/src/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +215 -0
- package/src/docs/versioned/next/tasks/native-module-baseline.md +42 -0
- package/src/docs/versioned/next/tasks/orgs-and-teams.md +70 -0
- package/src/docs/versioned/next/tasks/oss-governance-baseline.md +18 -18
- package/src/docs/versioned/next/tasks/password-reset-and-email-verification.md +60 -0
- package/src/docs/versioned/next/tasks/positioning-django-rails-universal.md +4 -4
- 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
|
|
@@ -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`.
|