@terreno/mcp 57.0.0 → 57.1.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.
- package/dist/bootstrap.d.ts +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +381 -191
- package/dist/bootstrap.js.map +1 -1
- package/dist/docs/guidelines/api/skills/mongoose-schema-safety/SKILL.md +8 -0
- package/dist/docs/resources/overview.md +6 -1
- package/dist/docs/resources/rtk.md +3 -1
- package/dist/docs/resources/syncdb.md +43 -0
- package/dist/docs/upgrades/56.0.0-beta.2.md +34 -0
- package/dist/docs/upgrades/57.1.0.md +126 -0
- package/dist/docs/versioned/next/README.md +15 -3
- package/dist/docs/versioned/next/explanation/README.md +3 -0
- package/dist/docs/versioned/next/explanation/admin-consent-migration.md +15 -0
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +12 -0
- package/dist/docs/versioned/next/explanation/announcements/rtk-deprecation.md +29 -0
- package/dist/docs/versioned/next/explanation/authentication.md +51 -58
- package/dist/docs/versioned/next/explanation/local-first-data.md +52 -0
- package/dist/docs/versioned/next/explanation/loop-engineering.md +117 -0
- package/dist/docs/versioned/next/explanation/repository-settings.md +8 -0
- package/dist/docs/versioned/next/explanation/roadmap-process.md +22 -9
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +39 -0
- package/dist/docs/versioned/next/how-to/README.md +3 -0
- package/dist/docs/versioned/next/how-to/admin-add-model.md +41 -0
- package/dist/docs/versioned/next/how-to/admin-custom-home.md +31 -0
- package/dist/docs/versioned/next/how-to/admin-custom-widget.md +42 -0
- package/dist/docs/versioned/next/how-to/admin-import-prebuilt.md +25 -0
- package/dist/docs/versioned/next/how-to/circleci.md +173 -0
- package/dist/docs/versioned/next/how-to/configure-better-auth.md +13 -10
- package/dist/docs/versioned/next/how-to/expose-mcp-tools.md +194 -0
- package/dist/docs/versioned/next/how-to/install-agent-skills.md +46 -0
- package/dist/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +26 -1
- package/dist/docs/versioned/next/how-to/websocket-integration.md +2 -1
- package/dist/docs/versioned/next/implementationPlans/ModularAPI.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/README.md +31 -17
- package/dist/docs/versioned/next/implementationPlans/admin-improvements-research.md +136 -0
- package/dist/docs/versioned/next/implementationPlans/admin-improvements.md +157 -527
- package/dist/docs/versioned/next/implementationPlans/admin-only-research.md +4 -0
- package/dist/docs/versioned/next/implementationPlans/admin-only.md +3 -1
- package/dist/docs/versioned/next/implementationPlans/admin-script-runner.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/admin-ui-v2-django-parity.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +160 -130
- package/dist/docs/versioned/next/implementationPlans/apierror-standard-error-redesign.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +5 -4
- package/dist/docs/versioned/next/implementationPlans/comms-abstraction-research.md +48 -0
- package/dist/docs/versioned/next/implementationPlans/comms-abstraction.md +152 -62
- package/dist/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +9 -9
- package/dist/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/consent-forms.md +4 -0
- package/dist/docs/versioned/next/implementationPlans/design-blend-skill.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/docs-site-and-versioning.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/feature-flags-openfeature.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/feature-flags.md +4 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp-research.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/infra-mcp.md +3 -3
- package/dist/docs/versioned/next/implementationPlans/mcp-boost-parity.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +2 -2
- package/dist/docs/versioned/next/implementationPlans/model-router-actions.md +4 -0
- package/dist/docs/versioned/next/implementationPlans/model-router-mcp.md +5 -4
- package/dist/docs/versioned/next/implementationPlans/offline-mode.md +3 -1
- package/dist/docs/versioned/next/implementationPlans/oss-launch-program.md +11 -2
- package/dist/docs/versioned/next/implementationPlans/pluggable-database-sqlite-research.md +150 -0
- package/dist/docs/versioned/next/implementationPlans/pluggable-database-sqlite.md +247 -0
- package/dist/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/public-roadmap-github.md +2 -2
- package/dist/docs/versioned/next/implementationPlans/rbac-permissions.md +52 -15
- package/dist/docs/versioned/next/implementationPlans/rtk-to-syncdb-migration-docs.md +13 -12
- package/dist/docs/versioned/next/implementationPlans/syncdb-codegen-research.md +137 -0
- package/dist/docs/versioned/next/implementationPlans/syncdb-codegen.md +63 -59
- package/dist/docs/versioned/next/implementationPlans/syncdb-local-first.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/syncdb-phase-c-design.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-syncdb-2.md +1 -0
- package/dist/docs/versioned/next/implementationPlans/upgrade-banner.md +4 -0
- package/dist/docs/versioned/next/reference/README.md +6 -1
- package/dist/docs/versioned/next/reference/admin-config.md +51 -0
- package/dist/docs/versioned/next/reference/ai.md +15 -1
- package/dist/docs/versioned/next/reference/api.md +18 -0
- package/dist/docs/versioned/next/reference/comms.md +88 -7
- package/dist/docs/versioned/next/reference/environment-variables.md +9 -1
- package/dist/docs/versioned/next/reference/{rtk.md → legacy/rtk.md} +11 -7
- package/dist/docs/versioned/next/reference/lifecycle-plugin.md +54 -0
- package/dist/docs/versioned/next/reference/mcp-server.md +7 -0
- package/dist/docs/versioned/next/reference/syncdb.md +30 -3
- package/dist/docs/versioned/next/tasks/README.md +21 -10
- package/dist/docs/versioned/next/tasks/admin-improvements.md +189 -353
- package/dist/docs/versioned/next/tasks/admin-only.md +2 -0
- package/dist/docs/versioned/next/tasks/agentic-sdlc-plugin.md +54 -160
- package/dist/docs/versioned/next/tasks/comms-abstraction.md +30 -24
- package/dist/docs/versioned/next/tasks/comms-adapter-sendgrid.md +4 -4
- package/dist/docs/versioned/next/tasks/consent-forms.md +2 -0
- package/dist/docs/versioned/next/tasks/feature-flags.md +2 -0
- package/dist/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +14 -10
- package/dist/docs/versioned/next/tasks/model-router-actions.md +2 -0
- package/dist/docs/versioned/next/tasks/model-router-mcp.md +27 -27
- package/dist/docs/versioned/next/tasks/offline-mode.md +2 -0
- package/dist/docs/versioned/next/tasks/pluggable-database-sqlite.md +44 -0
- package/dist/docs/versioned/next/tasks/public-roadmap-github.md +1 -1
- package/dist/docs/versioned/next/tasks/rtk-to-syncdb-migration-docs.md +15 -15
- package/dist/docs/versioned/next/tasks/syncdb-codegen.md +37 -31
- package/dist/docs/versioned/next/tasks/upgrade-banner.md +2 -0
- package/dist/index.js +24 -55
- package/dist/index.js.map +1 -1
- package/dist/local/localServer.d.ts.map +1 -1
- package/dist/local/localServer.js +9 -8
- package/dist/local/localServer.js.map +1 -1
- package/dist/local/localTools.d.ts +1 -1
- package/dist/local/localTools.d.ts.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +44 -45
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +9 -2
- package/dist/resources.js.map +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +4 -2
- package/dist/tools.js.map +1 -1
- package/package.json +7 -3
- package/src/docs/guidelines/api/skills/mongoose-schema-safety/SKILL.md +8 -0
- package/src/docs/resources/overview.md +6 -1
- package/src/docs/resources/rtk.md +3 -1
- package/src/docs/resources/syncdb.md +43 -0
- package/src/docs/upgrades/56.0.0-beta.2.md +34 -0
- package/src/docs/upgrades/57.1.0.md +126 -0
- package/src/docs/versioned/next/README.md +15 -3
- package/src/docs/versioned/next/explanation/README.md +3 -0
- package/src/docs/versioned/next/explanation/admin-consent-migration.md +15 -0
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +12 -0
- package/src/docs/versioned/next/explanation/announcements/rtk-deprecation.md +29 -0
- package/src/docs/versioned/next/explanation/authentication.md +51 -58
- package/src/docs/versioned/next/explanation/local-first-data.md +52 -0
- package/src/docs/versioned/next/explanation/loop-engineering.md +117 -0
- package/src/docs/versioned/next/explanation/repository-settings.md +8 -0
- package/src/docs/versioned/next/explanation/roadmap-process.md +22 -9
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +39 -0
- package/src/docs/versioned/next/how-to/README.md +3 -0
- package/src/docs/versioned/next/how-to/admin-add-model.md +41 -0
- package/src/docs/versioned/next/how-to/admin-custom-home.md +31 -0
- package/src/docs/versioned/next/how-to/admin-custom-widget.md +42 -0
- package/src/docs/versioned/next/how-to/admin-import-prebuilt.md +25 -0
- package/src/docs/versioned/next/how-to/circleci.md +173 -0
- package/src/docs/versioned/next/how-to/configure-better-auth.md +13 -10
- package/src/docs/versioned/next/how-to/expose-mcp-tools.md +194 -0
- package/src/docs/versioned/next/how-to/install-agent-skills.md +46 -0
- package/src/docs/versioned/next/how-to/migrate-rtk-to-syncdb.md +26 -1
- package/src/docs/versioned/next/how-to/websocket-integration.md +2 -1
- package/src/docs/versioned/next/implementationPlans/ModularAPI.md +1 -0
- package/src/docs/versioned/next/implementationPlans/README.md +31 -17
- package/src/docs/versioned/next/implementationPlans/admin-improvements-research.md +136 -0
- package/src/docs/versioned/next/implementationPlans/admin-improvements.md +157 -527
- package/src/docs/versioned/next/implementationPlans/admin-only-research.md +4 -0
- package/src/docs/versioned/next/implementationPlans/admin-only.md +3 -1
- package/src/docs/versioned/next/implementationPlans/admin-script-runner.md +1 -0
- package/src/docs/versioned/next/implementationPlans/admin-ui-v2-django-parity.md +1 -0
- package/src/docs/versioned/next/implementationPlans/agentic-sdlc-plugin.md +160 -130
- package/src/docs/versioned/next/implementationPlans/apierror-standard-error-redesign.md +1 -0
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +5 -4
- package/src/docs/versioned/next/implementationPlans/comms-abstraction-research.md +48 -0
- package/src/docs/versioned/next/implementationPlans/comms-abstraction.md +152 -62
- package/src/docs/versioned/next/implementationPlans/comms-adapter-sendgrid.md +9 -9
- package/src/docs/versioned/next/implementationPlans/comms-admin-dashboard.md +1 -1
- package/src/docs/versioned/next/implementationPlans/consent-forms.md +4 -0
- package/src/docs/versioned/next/implementationPlans/design-blend-skill.md +1 -0
- package/src/docs/versioned/next/implementationPlans/docs-site-and-versioning.md +1 -0
- package/src/docs/versioned/next/implementationPlans/feature-flags-openfeature.md +1 -0
- package/src/docs/versioned/next/implementationPlans/feature-flags.md +4 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp-research.md +1 -0
- package/src/docs/versioned/next/implementationPlans/infra-mcp.md +3 -3
- package/src/docs/versioned/next/implementationPlans/mcp-boost-parity.md +1 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci-research.md +1 -0
- package/src/docs/versioned/next/implementationPlans/migrate-cicd-to-circleci.md +2 -2
- package/src/docs/versioned/next/implementationPlans/model-router-actions.md +4 -0
- package/src/docs/versioned/next/implementationPlans/model-router-mcp.md +5 -4
- package/src/docs/versioned/next/implementationPlans/offline-mode.md +3 -1
- package/src/docs/versioned/next/implementationPlans/oss-launch-program.md +11 -2
- package/src/docs/versioned/next/implementationPlans/pluggable-database-sqlite-research.md +150 -0
- package/src/docs/versioned/next/implementationPlans/pluggable-database-sqlite.md +247 -0
- package/src/docs/versioned/next/implementationPlans/positioning-django-rails-universal.md +1 -1
- package/src/docs/versioned/next/implementationPlans/public-roadmap-github.md +2 -2
- package/src/docs/versioned/next/implementationPlans/rbac-permissions.md +52 -15
- package/src/docs/versioned/next/implementationPlans/rtk-to-syncdb-migration-docs.md +13 -12
- package/src/docs/versioned/next/implementationPlans/syncdb-codegen-research.md +137 -0
- package/src/docs/versioned/next/implementationPlans/syncdb-codegen.md +63 -59
- package/src/docs/versioned/next/implementationPlans/syncdb-local-first.md +1 -0
- package/src/docs/versioned/next/implementationPlans/syncdb-phase-c-design.md +1 -0
- package/src/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -0
- package/src/docs/versioned/next/implementationPlans/terreno-syncdb-2.md +1 -0
- package/src/docs/versioned/next/implementationPlans/upgrade-banner.md +4 -0
- package/src/docs/versioned/next/reference/README.md +6 -1
- package/src/docs/versioned/next/reference/admin-config.md +51 -0
- package/src/docs/versioned/next/reference/ai.md +15 -1
- package/src/docs/versioned/next/reference/api.md +18 -0
- package/src/docs/versioned/next/reference/comms.md +88 -7
- package/src/docs/versioned/next/reference/environment-variables.md +9 -1
- package/src/docs/versioned/next/reference/{rtk.md → legacy/rtk.md} +11 -7
- package/src/docs/versioned/next/reference/lifecycle-plugin.md +54 -0
- package/src/docs/versioned/next/reference/mcp-server.md +7 -0
- package/src/docs/versioned/next/reference/syncdb.md +30 -3
- package/src/docs/versioned/next/tasks/README.md +21 -10
- package/src/docs/versioned/next/tasks/admin-improvements.md +189 -353
- package/src/docs/versioned/next/tasks/admin-only.md +2 -0
- package/src/docs/versioned/next/tasks/agentic-sdlc-plugin.md +54 -160
- package/src/docs/versioned/next/tasks/comms-abstraction.md +30 -24
- package/src/docs/versioned/next/tasks/comms-adapter-sendgrid.md +4 -4
- package/src/docs/versioned/next/tasks/consent-forms.md +2 -0
- package/src/docs/versioned/next/tasks/feature-flags.md +2 -0
- package/src/docs/versioned/next/tasks/migrate-cicd-to-circleci.md +14 -10
- package/src/docs/versioned/next/tasks/model-router-actions.md +2 -0
- package/src/docs/versioned/next/tasks/model-router-mcp.md +27 -27
- package/src/docs/versioned/next/tasks/offline-mode.md +2 -0
- package/src/docs/versioned/next/tasks/pluggable-database-sqlite.md +44 -0
- package/src/docs/versioned/next/tasks/public-roadmap-github.md +1 -1
- package/src/docs/versioned/next/tasks/rtk-to-syncdb-migration-docs.md +15 -15
- package/src/docs/versioned/next/tasks/syncdb-codegen.md +37 -31
- package/src/docs/versioned/next/tasks/upgrade-banner.md +2 -0
- package/dist/docs/versioned/next/implementationPlans/PLAN_INDEX.md +0 -73
- package/dist/docs/versioned/next/implementationPlans/syncdb-api-inventory.md +0 -303
- package/src/docs/versioned/next/implementationPlans/PLAN_INDEX.md +0 -73
- package/src/docs/versioned/next/implementationPlans/syncdb-api-inventory.md +0 -303
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
# Configure Better Auth
|
|
2
2
|
|
|
3
|
-
Set up Better Auth as
|
|
3
|
+
Set up Better Auth as the **default** authentication provider for new Terreno apps — session-based auth with built-in social OAuth and first-class `@terreno/syncdb` integration.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
Better Auth is
|
|
7
|
+
Better Auth is the recommended authentication system for new Terreno frontends. Register `BetterAuthApp` on the backend, set `AUTH_PROVIDER=better-auth`, and wire `createBetterAuthClient` + `generateBetterAuthSlice` on the client. Pair with `betterAuthAdapter` when using `@terreno/syncdb`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
JWT/Passport remains available for legacy deployments (`AUTH_PROVIDER=jwt`). Both can run in parallel during migration.
|
|
10
|
+
|
|
11
|
+
**Choose Better Auth for:**
|
|
12
|
+
- New apps and greenfield screens
|
|
10
13
|
- Social login (Google, GitHub, Apple)
|
|
11
|
-
- Session-based authentication
|
|
12
|
-
-
|
|
14
|
+
- Session-based authentication with `@terreno/syncdb`
|
|
15
|
+
- Socket.io sync via `RealtimeApp` bearer sessions
|
|
13
16
|
|
|
14
|
-
**
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
17
|
+
**Stay on JWT only when:**
|
|
18
|
+
- You have an existing JWT deployment and are mid-migration
|
|
19
|
+
- You require a fully stateless token contract with no session cookies
|
|
20
|
+
- You have custom JWT payload requirements Better Auth cannot satisfy
|
|
18
21
|
|
|
19
22
|
## Backend Setup
|
|
20
23
|
|
|
@@ -292,5 +295,5 @@ Better Auth runs **in parallel** with JWT auth. You don't need to migrate existi
|
|
|
292
295
|
|
|
293
296
|
- [Authentication Architecture](../explanation/authentication.md)
|
|
294
297
|
- [@terreno/api Reference](../reference/api.md#better-auth)
|
|
295
|
-
- [@terreno/rtk Reference](../reference/rtk.md#better-auth)
|
|
298
|
+
- [@terreno/rtk Reference (legacy)](../reference/legacy/rtk.md#better-auth)
|
|
296
299
|
- [Better Auth Documentation](https://better-auth.com/)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Expose Model Context Protocol Tools
|
|
2
|
+
|
|
3
|
+
Turn a `modelRouter` model into Model Context Protocol (MCP) tools that an LLM can call, reusing the permissions, query filters, population, and lifecycle hooks you already declared for REST.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- A working Terreno backend using `TerrenoApp`
|
|
8
|
+
- At least one model registered with `modelRouter`
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
### 1. Add an `mcp` config to a model router
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import {modelRouter, OwnerQueryFilter, Permissions} from "@terreno/api";
|
|
16
|
+
|
|
17
|
+
export const todoRouter = modelRouter("/todos", Todo, {
|
|
18
|
+
mcp: {
|
|
19
|
+
excludeFields: ["internalNote"],
|
|
20
|
+
maxLimit: 25,
|
|
21
|
+
methods: ["list", "read", "create", "update", "delete"],
|
|
22
|
+
},
|
|
23
|
+
permissions: {
|
|
24
|
+
create: [Permissions.IsAuthenticated],
|
|
25
|
+
delete: [Permissions.IsOwner],
|
|
26
|
+
list: [Permissions.IsAuthenticated],
|
|
27
|
+
read: [Permissions.IsOwner],
|
|
28
|
+
update: [Permissions.IsOwner],
|
|
29
|
+
},
|
|
30
|
+
queryFields: ["completed", "title"],
|
|
31
|
+
queryFilter: OwnerQueryFilter,
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`methods` defaults to `["list", "read"]`, and `maxLimit` defaults to 50. A method whose `permissions` array is empty is never exposed as a tool, so REST and MCP cannot drift apart.
|
|
36
|
+
|
|
37
|
+
### 2. Start the server
|
|
38
|
+
|
|
39
|
+
`TerrenoApp` mounts `POST /mcp` automatically as soon as any model has an `mcp` config. Every other verb on `/mcp` returns a JSON-RPC 405. No extra registration is needed.
|
|
40
|
+
|
|
41
|
+
Tools are named `{prefix}_{method}` — `todos_list`, `todos_read`, and so on.
|
|
42
|
+
|
|
43
|
+
The endpoint speaks the `2026-07-28` MCP revision through the TypeScript SDK v2
|
|
44
|
+
`createMcpHandler`. It is stateless: every request carries its protocol version,
|
|
45
|
+
client identity, and capabilities, so requests can land on any backend instance.
|
|
46
|
+
The SDK's stateless legacy fallback remains enabled, so 2025-era clients continue
|
|
47
|
+
to work while clients migrate.
|
|
48
|
+
|
|
49
|
+
### 3. Call the tools
|
|
50
|
+
|
|
51
|
+
Point any MCP client at `POST /mcp` with the user's `Authorization: Bearer <token>` header. Both JWT and Better Auth sessions are accepted; the resolved user is what the permission checks run against, so an LLM can never see more than that user could see over REST.
|
|
52
|
+
|
|
53
|
+
Authentication is required by default, matching REST. A tool call with no resolvable user is refused before any permission check unless the model router sets `allowAnonymous: true` — the same flag REST passes to `authenticateMiddleware`. That matters for read-only helpers like `IsAuthenticatedOrReadOnly`, which would otherwise pass for an anonymous `list`. Disabled accounts are refused too, as they are over HTTP.
|
|
54
|
+
|
|
55
|
+
To run the same tools in-process (for example inside a chat route), use `getMCPTools`:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import {getMCPTools} from "@terreno/ai";
|
|
59
|
+
|
|
60
|
+
const tools = getMCPTools(req.user);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`useMCPTools()` from `@terreno/rtk` uses the official MCP v2 client with automatic
|
|
64
|
+
version negotiation. It no longer constructs JSON-RPC or parses SSE responses by
|
|
65
|
+
hand; the SDK supplies the `2026-07-28` `_meta` envelope and required
|
|
66
|
+
`Mcp-Method` / `Mcp-Name` routing headers.
|
|
67
|
+
|
|
68
|
+
## Naming tools
|
|
69
|
+
|
|
70
|
+
The default prefix is the lowercase model name run through a simple pluralizer: `Todo` → `todos`, `Category` → `categories`, `Status` → `statuses`. Irregular nouns need an explicit prefix:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
mcp: {toolPrefix: "people"} // person_list -> people_list
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Filtering list results
|
|
77
|
+
|
|
78
|
+
Only fields listed in `queryFields` can be filtered, exactly as in REST. A filter value may be an exact value or an operator object:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{"completed": false, "title": {"$in": ["Buy milk", "Walk dog"]}}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Allowed operators are `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$all`, `$size`, `$exists`, and `$regex` (with `$options`). Operators that can execute code or ignore indexes — `$where`, `$expr`, `$function`, `$accumulator`, `$jsonSchema`, `$text` — are rejected with an error rather than silently dropped, so the model can correct itself.
|
|
85
|
+
|
|
86
|
+
Filters can be combined with top-level `$and` / `$or`, whose branches are validated against `queryFields` too:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{"$or": [{"completed": true}, {"title": {"$regex": "^Urgent"}}]}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`queryFilter` still runs after the filter is built, so an `OwnerQueryFilter` keeps scoping results to the calling user no matter what the LLM sends.
|
|
93
|
+
|
|
94
|
+
## Populating references
|
|
95
|
+
|
|
96
|
+
Population comes from the model router's `populatePaths`, exactly as it does over REST. A tool may pass `populate` to request a **subset** of those declared paths — it can never introduce a new one, so the `fields` allowlist on each declared path always applies and a caller cannot pull back a whole referenced document:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
populatePaths: [{fields: ["name", "email"], path: "ownerId"}],
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`{"populate": "ownerId"}` is accepted; anything undeclared is refused with an error listing the allowed paths. Models with no `populatePaths` don't get a `populate` parameter at all.
|
|
103
|
+
|
|
104
|
+
## Hiding fields
|
|
105
|
+
|
|
106
|
+
`excludeFields` removes fields from both the generated tool schemas and the responses:
|
|
107
|
+
|
|
108
|
+
- A bare name (`"hash"`) is removed at **every depth**, including inside arrays and populated refs, so a redacted name cannot leak through a nested document.
|
|
109
|
+
- A dot path (`"metadata.secretKey"`) removes exactly that location, following arrays of subdocuments element-wise.
|
|
110
|
+
|
|
111
|
+
## Customizing responses
|
|
112
|
+
|
|
113
|
+
`mcpResponseHandler` shapes MCP responses independently of the REST `responseHandler`, which is useful for returning compact summaries to an LLM:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
mcp: {
|
|
117
|
+
mcpResponseHandler: async (value, method) => {
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
return value.map((todo) => ({id: String(todo._id), title: todo.title}));
|
|
120
|
+
}
|
|
121
|
+
return {id: String(value._id), title: value.title};
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`excludeFields` is applied after your handler runs.
|
|
127
|
+
|
|
128
|
+
## Lifecycle hooks
|
|
129
|
+
|
|
130
|
+
`preCreate`, `postCreate`, `preUpdate`, `postUpdate`, `preDelete`, and `postDelete` all run for MCP calls. An MCP tool call is JSON-RPC rather than HTTP, so `createMCPRequest` builds a stub Express-shaped `request` (`MCPRequest`):
|
|
131
|
+
|
|
132
|
+
- `user` — the authenticated MCP user
|
|
133
|
+
- `body` — the hook-stage payload after write denylist + transform, not the raw tool args (on delete, `id` is in `body`, not `params`)
|
|
134
|
+
- `headers` / `query` / `params` — always `{}` (MCP does not forward HTTP headers)
|
|
135
|
+
- `isMCPRequest` — `true`
|
|
136
|
+
|
|
137
|
+
REST `responseHandler` gets the same stub with an empty `body`.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import type {MCPRequest} from "@terreno/api";
|
|
141
|
+
|
|
142
|
+
preCreate: (body, req) => {
|
|
143
|
+
if ((req as unknown as MCPRequest).isMCPRequest) {
|
|
144
|
+
// e.g. tag records created by an assistant
|
|
145
|
+
return {...body, source: "assistant"};
|
|
146
|
+
}
|
|
147
|
+
return body;
|
|
148
|
+
},
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
A hook that reads `req.headers` or `req.query` gets an empty object instead of a crash, but anything genuinely HTTP-specific (cookies, IP address) is unavailable — branch on `isMCPRequest` when that matters.
|
|
152
|
+
|
|
153
|
+
## Logging and error reporting
|
|
154
|
+
|
|
155
|
+
Every generated tool call emits a structured backend audit log with stable
|
|
156
|
+
`mcpTool`, `mcpMethod`, and `mcpModel` labels plus the active Terreno request
|
|
157
|
+
context (`requestId`, `userId`, and trace fields when present):
|
|
158
|
+
|
|
159
|
+
- successful calls log at `info` with `durationMs`
|
|
160
|
+
- expected refusals (permissions, not found, invalid filters) log at `warn`
|
|
161
|
+
- caught database, transform, and lifecycle-hook failures log at `error`
|
|
162
|
+
|
|
163
|
+
When `USE_SENTRY_LOGGING=true`, expected failures are mirrored as Sentry logs.
|
|
164
|
+
Unexpected exceptions and caught internal causes are also captured with
|
|
165
|
+
`Sentry.captureException`, preserving their original stack. The client still
|
|
166
|
+
receives the stable MCP error text — internal exceptions and stack traces stay
|
|
167
|
+
server-side. Tool arguments are not logged.
|
|
168
|
+
|
|
169
|
+
## Custom tools
|
|
170
|
+
|
|
171
|
+
CRUD tools cover one model at a time. For a query that spans models, register a custom tool with `registerMCPTool`. It shows up on `POST /mcp` and in `getMCPTools` next to the generated CRUD tools:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import {registerMCPTool} from "@terreno/api";
|
|
175
|
+
import {z} from "zod";
|
|
176
|
+
|
|
177
|
+
registerMCPTool({
|
|
178
|
+
name: "users_todo_statuses",
|
|
179
|
+
description: "List every user with each of their todos and completed status. Admin only.",
|
|
180
|
+
zodSchema: z.object({}).strict(),
|
|
181
|
+
handler: async (_args, user) => {
|
|
182
|
+
if (!user?.admin) {
|
|
183
|
+
return {
|
|
184
|
+
content: [{type: "text", text: JSON.stringify({error: "Permission denied: admin required"})}],
|
|
185
|
+
isError: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// load users + todos and return JSON text
|
|
189
|
+
return {content: [{type: "text", text: JSON.stringify({users: []})}]};
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The example backend registers this as `users_todo_statuses` from `example-backend/src/api/usersTodoStatus.ts`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Install agent skills
|
|
2
|
+
|
|
3
|
+
Install Terreno's agent skills into another repo or agent with the skills CLI.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx skills add FlourishHealth/terreno
|
|
7
|
+
npx skills add FlourishHealth/terreno --skill terreno-1-grow
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
That copies the committed `skills/` tree: lifecycle stages (Grow, Pick, Roast, Brew,
|
|
11
|
+
Taste), repository skills, and published package skills.
|
|
12
|
+
|
|
13
|
+
## What you get
|
|
14
|
+
|
|
15
|
+
| Group | Skills |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| Lifecycle | `terreno-1-grow` … `terreno-5-taste` |
|
|
18
|
+
| Terreno apps | backend, UI, data, schema, SDK |
|
|
19
|
+
| Docs | `update-docs`, `update-agent-docs`, architecture skills |
|
|
20
|
+
| GitHub | commit, PR, review, verify, release, deploy |
|
|
21
|
+
|
|
22
|
+
`skills.sh.json` at the repo root groups those names on [skills.sh](https://skills.sh).
|
|
23
|
+
|
|
24
|
+
## Keep copies in sync (Terreno maintainers)
|
|
25
|
+
|
|
26
|
+
Canonical sources:
|
|
27
|
+
|
|
28
|
+
1. `.rulesync/skills/` — repository skills (`bun run rules` generates agent copies)
|
|
29
|
+
2. `plugins/terreno-planning/skills/` — portable lifecycle stages
|
|
30
|
+
3. `<package>/.ai/skills/` — published package skills; these overlay the repo copies
|
|
31
|
+
|
|
32
|
+
Regenerate the installable tree:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bun run skills:sync
|
|
36
|
+
bun run check:lifecycle-skills
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Do not hand-edit `skills/`.
|
|
40
|
+
|
|
41
|
+
## Write human docs with the skills
|
|
42
|
+
|
|
43
|
+
Skills read architecture docs before changing code. After a user-visible or architectural
|
|
44
|
+
change, update `docs/` in the same slice using `update-docs`. See
|
|
45
|
+
[lifecycle plugin](../reference/lifecycle-plugin.md) and the
|
|
46
|
+
[documentation contract](https://github.com/FlourishHealth/terreno/blob/master/plugins/terreno-planning/references/documentation-contract.md).
|
|
@@ -21,6 +21,8 @@ This guide is **AI-context-first**: it is written for an agent (or human) perfor
|
|
|
21
21
|
|
|
22
22
|
The example app completed both steps; todos are syncdb-only while profile/admin still use generated RTK hooks.
|
|
23
23
|
|
|
24
|
+
**Validation (Task 3.5):** The profile screen (`example-frontend/app/(tabs)/profile.tsx`) was reviewed against this guide. `useGetMeQuery` / `usePatchMeMutation` are **non-synced** custom SDK routes — the guide §8 explicitly says to keep them on RTK. No profile migration is required; the guide is sufficient for that case.
|
|
25
|
+
|
|
24
26
|
Reference: [`docs/reference/syncdb.md`](../reference/syncdb.md), and the package [`syncdb/README.md`](https://github.com/flourishhealth/terreno/blob/release-56.0.0/syncdb/README.md).
|
|
25
27
|
|
|
26
28
|
## 2. Install and configure
|
|
@@ -318,6 +320,18 @@ Required for Better Auth socket sessions. Legacy JWT sockets continue to work wi
|
|
|
318
320
|
|
|
319
321
|
## 8. Codegen
|
|
320
322
|
|
|
323
|
+
Synced collections use `bun run sync-sdk`, which runs `terreno-syncdb-codegen` from
|
|
324
|
+
`@terreno/syncdb`. It reads `/openapi.json`, finds list operations tagged
|
|
325
|
+
`x-terreno-sync`, and writes `store/syncDbSdk.ts` (`SYNC_COLLECTIONS` plus friendly
|
|
326
|
+
hooks such as `useTodos` / `useTodo` / `useCreateTodo`). Do not edit that file.
|
|
327
|
+
Custom collections call `createCollectionHooks` in a sibling file. Names are chosen
|
|
328
|
+
so they do not collide with RTK `openApiSdk.ts` during dual-stack migration.
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Backend running on port 4000
|
|
332
|
+
cd example-frontend && bun run sync-sdk
|
|
333
|
+
```
|
|
334
|
+
|
|
321
335
|
### Does `bun run sdk` still work?
|
|
322
336
|
|
|
323
337
|
**Yes.** `example-frontend/package.json` still defines:
|
|
@@ -332,7 +346,7 @@ It runs `@rtk-query/codegen-openapi` against `openapi-config.ts` and writes `sto
|
|
|
332
346
|
|
|
333
347
|
| Still generated | Stop using for migrated collections |
|
|
334
348
|
|-----------------|-------------------------------------|
|
|
335
|
-
| Auth routes, `GET /auth/me`, admin, AI explorer, version config, feature flags |
|
|
349
|
+
| Auth routes, `GET /auth/me`, admin, AI explorer, version config, feature flags | Collection CRUD — import from `store/syncDbSdk.ts` instead |
|
|
336
350
|
| Custom REST / RPC endpoints | Todo `realtimeList` / `realtimeDocument` wiring in `store/sdk.ts` |
|
|
337
351
|
|
|
338
352
|
Keep running `bun run sdk` after backend route changes — non-synced screens still import from `store/sdk.ts`.
|
|
@@ -342,8 +356,19 @@ Workflow:
|
|
|
342
356
|
```bash
|
|
343
357
|
# Backend running on port 4000
|
|
344
358
|
cd example-frontend && bun run sdk
|
|
359
|
+
cd example-frontend && bun run sync-sdk
|
|
345
360
|
```
|
|
346
361
|
|
|
362
|
+
### Syncdb hooks codegen
|
|
363
|
+
|
|
364
|
+
For collections with `sync` enabled on the backend, generate local-first hooks from the same OpenAPI spec:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
cd example-frontend && bun run sync-sdk
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
This writes `store/syncDbSdk.ts` with friendly hooks (`useTodos`, `useCreateTodo`, …) that intentionally differ from RTK names so both SDKs can coexist during migration. Import synced screens from `@/store/syncDbSdk`, not `store/sdk.ts`.
|
|
371
|
+
|
|
347
372
|
## 9. Feature flags
|
|
348
373
|
|
|
349
374
|
Post-migration, feature flags stay on `@terreno/rtk` + OpenFeature — **not** on syncdb.
|
|
@@ -411,6 +411,7 @@ This logs:
|
|
|
411
411
|
|
|
412
412
|
## Related Documentation
|
|
413
413
|
|
|
414
|
-
- [@terreno/
|
|
414
|
+
- [@terreno/syncdb Reference](../reference/syncdb.md) — Local-first data layer (replaces RTK for synced collections)
|
|
415
|
+
- [@terreno/rtk Reference (legacy)](../reference/legacy/rtk.md) — RTK Query utilities during the support window
|
|
415
416
|
- [Authentication Architecture](../explanation/authentication.md) — JWT system deep-dive
|
|
416
417
|
- [Socket.io Documentation](https://socket.io/docs/v4/) — Official Socket.io docs
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Modular API Implementation Plan
|
|
2
2
|
|
|
3
|
+
**Roadmap issue:** https://github.com/FlourishHealth/terreno/issues/1084
|
|
3
4
|
## Overview
|
|
4
5
|
|
|
5
6
|
This document outlines the implementation plan for a new modular API design in `@terreno/api`. The goal is to create a `TerrenoApp` class that provides a cleaner, more flexible interface for building APIs while maintaining backward compatibility with the existing `setupServer` function.
|
|
@@ -7,7 +7,7 @@ An implementation plan (IP) is one half of a two-file pair:
|
|
|
7
7
|
|
|
8
8
|
| File | Holds | Path |
|
|
9
9
|
| ---- | ----- | ---- |
|
|
10
|
-
| **IP** | Design goals, architecture, models/APIs, phases, acceptance criteria | `docs/implementationPlans/<slug>.md` |
|
|
10
|
+
| **IP** | Design goals, architecture, models/APIs, testing decisions, phases, acceptance criteria | `docs/implementationPlans/<slug>.md` |
|
|
11
11
|
| **Task list** | The bot-consumable execution checklist for that IP | `docs/tasks/<slug>.md` |
|
|
12
12
|
|
|
13
13
|
The IP is the source of truth for *what and why*; the task list is the source of truth
|
|
@@ -15,11 +15,12 @@ for *the concrete steps*. External trackers (a GitHub roadmap issue, a Linear is
|
|
|
15
15
|
discussion thread) link **to** these files — they never replace them. See
|
|
16
16
|
[`docs/tasks/README.md`](../tasks/README.md) for the task-file shape.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Status lives on each IP
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
There is no shared `PLAN_INDEX.md`. That file caused merge conflicts the same way a
|
|
21
|
+
shared changelog Unreleased section did. Status is the `**Status:**` line in each
|
|
22
|
+
`docs/implementationPlans/<slug>.md` (and in `archive/` after close). List those
|
|
23
|
+
directories to see what exists; this README explains the process.
|
|
23
24
|
|
|
24
25
|
## When to write an IP
|
|
25
26
|
|
|
@@ -35,34 +36,47 @@ Substantial work is planned before coding. Quick rule (full table in
|
|
|
35
36
|
|
|
36
37
|
## How a plan gets written and built
|
|
37
38
|
|
|
38
|
-
The [`terreno-planning` plugin](../../plugins/README.md) drives the pipeline
|
|
39
|
+
The [`terreno-planning` plugin](../../plugins/README.md) drives the pipeline.
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
**Grow** interviews in grilling rounds (one frontier of decisions per message, recommended
|
|
42
|
+
answers, then wait). After the user confirms shared understanding it writes the two files
|
|
43
|
+
and ends with a **15-line verify table** — destination, in/out, tracer, task graph, test
|
|
44
|
+
seam — so a human can check the plan without rereading the IP.
|
|
45
|
+
|
|
46
|
+
For a small feature, an outer loop may use the plugin's **feature profile**: a compact
|
|
47
|
+
approved task contract, one fresh Pick invocation per frontier task, independent Roast,
|
|
48
|
+
then Brew and bounded Taste iterations. This preserves the former Grind behavior without
|
|
49
|
+
putting orchestration inside a lifecycle skill.
|
|
50
|
+
|
|
51
|
+
1. **Grow** (`terreno-1-grow`) — grill, then write the IP + tracer-bullet task list; end with the 15-line verify table.
|
|
52
|
+
2. **Pick** (`terreno-2-pick`) — implement one approved slice via TDD.
|
|
53
|
+
3. **Roast** (`terreno-3-roast`) — independently verify the implementation against the IP.
|
|
54
|
+
4. **Brew** (`terreno-4-brew`) — commit, push, open the PR.
|
|
55
|
+
5. **Taste** (`terreno-5-taste`) — react once to current CI, mergeability, and review state.
|
|
56
|
+
|
|
57
|
+
The outer loop owns stage selection, execution-state persistence, waiting, retries, and
|
|
58
|
+
human/external escalation. Each stage emits the common machine-readable result described
|
|
59
|
+
in [`plugins/terreno-planning/references/lifecycle-contract.md`](../../plugins/terreno-planning/references/lifecycle-contract.md).
|
|
45
60
|
|
|
46
61
|
You can also author an IP directly with the `ip` skill; both produce the same two files.
|
|
47
62
|
|
|
48
63
|
### Roadmap handoff (roadmap-enabled repos only)
|
|
49
64
|
|
|
50
65
|
In repos that run a public roadmap (Discussions + a roadmap Project — currently Terreno),
|
|
51
|
-
|
|
66
|
+
Grow hands off to `roadmap-item` once the IP is **Approved** to create or update the
|
|
52
67
|
public tracking issue, and the IP header records the `Discussion:` and `Roadmap issue:`
|
|
53
68
|
links. See [`docs/explanation/roadmap-process.md`](../explanation/roadmap-process.md) for
|
|
54
69
|
the full IP ↔ roadmap lifecycle.
|
|
55
70
|
|
|
56
71
|
In repos with **no** roadmap board (Flourish, most consumer apps), the pipeline is
|
|
57
|
-
identical minus that handoff: the IP + task list
|
|
58
|
-
|
|
72
|
+
identical minus that handoff: the IP + task list are the source of truth, and Linear
|
|
73
|
+
tracks execution via the IP header `Linear:` link.
|
|
59
74
|
|
|
60
75
|
## Lifecycle
|
|
61
76
|
|
|
62
|
-
1. **Draft** → **Approved** — IP written and reviewed (status lives in the IP header
|
|
63
|
-
`PLAN_INDEX.md`).
|
|
77
|
+
1. **Draft** → **Approved** — IP written and reviewed (status lives in the IP header).
|
|
64
78
|
2. **In progress** → **Complete** — implemented, verified, merged.
|
|
65
|
-
3. **Archive** — completed IPs move to `docs/implementationPlans/archive
|
|
79
|
+
3. **Archive** — completed IPs move to `docs/implementationPlans/archive/`.
|
|
66
80
|
|
|
67
81
|
Plans that are fully implemented and now describe shipped architecture should be migrated
|
|
68
82
|
to `docs/explanation/` as reference documentation.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Research: Admin Improvements (post–Admin UI v2 gap)
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-20
|
|
4
|
+
**PRD:** Implement what did not ship in Admin UI v2 — finish the `admin-improvements` architectural overhaul on top of the landed `admin-ui-v2-django-parity` work.
|
|
5
|
+
|
|
6
|
+
## Scope investigated
|
|
7
|
+
|
|
8
|
+
- Existing IPs: `docs/implementationPlans/admin-improvements.md`, `docs/implementationPlans/admin-ui-v2-django-parity.md`, `docs/tasks/admin-improvements.md`, `docs/tasks/admin-ui-v2-django-parity.md`
|
|
9
|
+
- Packages: `api/`, `admin-backend/`, `admin-frontend/`, `admin-spa/`, `feature-flags/`, `example-backend/`, `example-frontend/`
|
|
10
|
+
- Roadmap: `.github/roadmap-fields.yml` present → roadmap handoff applies after IP approval
|
|
11
|
+
|
|
12
|
+
## What Admin UI v2 already shipped
|
|
13
|
+
|
|
14
|
+
`admin-ui-v2-django-parity` is marked **Implemented** with all task phases complete. Evidence in-repo:
|
|
15
|
+
|
|
16
|
+
| Area | Shipped |
|
|
17
|
+
|------|---------|
|
|
18
|
+
| Config | `schemaVersion: 2`, extended model meta, `home.slots` (`navGlobal`, `contentTop`, `main`, `sidebar`) |
|
|
19
|
+
| Backend routes | `POST .../bulk-patch` (≤1000 ids), `POST /admin/background-tasks` |
|
|
20
|
+
| Scripts | `/admin/scripts/*`, `scripts[]` in config (see `admin-script-runner.md`) |
|
|
21
|
+
| Shell / home | `AdminShell`, `AdminHome` with built-in widget ids (`modelsGrid`, `scriptRunner`, `recentActivity`, `versionConfig`, …) |
|
|
22
|
+
| List | `AdminModelTable`: debounced search, inline typed filters, row select, declarative `actions` → bulk-patch or background enqueue |
|
|
23
|
+
| Form | `AdminModelForm`: fieldsets, readonly (server strips PATCH body) |
|
|
24
|
+
| Audit | `AdminAuditLog` + `onAdminAudit` + `recentActivity` widget (sidebar, last) |
|
|
25
|
+
| Integration | `admin-spa`, `example-backend` v2 demo registrations, Playwright e2e |
|
|
26
|
+
|
|
27
|
+
## What `admin-improvements` planned but did NOT ship
|
|
28
|
+
|
|
29
|
+
All tasks in `docs/tasks/admin-improvements.md` remain **unchecked**. High-level gaps:
|
|
30
|
+
|
|
31
|
+
### `@terreno/api` (Phase 1) — none landed
|
|
32
|
+
|
|
33
|
+
- No `api/src/adminTypes.ts` (`AdminConfig`, `AdminContribution`, `AdminAction`, …)
|
|
34
|
+
- No `admin?: AdminConfig` on `ModelRouterOptions`
|
|
35
|
+
- `TerrenoPlugin.register` still `(app, openApi?)` — no `terrenoApp` third arg
|
|
36
|
+
- No `getRegistrations()` / `getPlugins()` on `TerrenoApp`
|
|
37
|
+
- No `adminContribution?()` on `TerrenoPlugin`
|
|
38
|
+
- No typed `admin:model.changed` event bus on `TerrenoApp`
|
|
39
|
+
- No shared `scrubAdminFields` with populated-doc recursion
|
|
40
|
+
- `readonlyFields` / `excludeFields` enforcement lives in `admin-backend` only, not in `modelRouter` hooks
|
|
41
|
+
|
|
42
|
+
### `@terreno/admin-backend` (Phase 2) — partial overlap with v2, architecture gap remains
|
|
43
|
+
|
|
44
|
+
| Planned | Status |
|
|
45
|
+
|---------|--------|
|
|
46
|
+
| Aggregate admin from modelRouter `admin:` + plugin contributions + legacy `models[]` | **Not done** — still `AdminApp({ models: [...] })` only |
|
|
47
|
+
| `legacy.ts` adapter + deprecation warnings | **Not done** |
|
|
48
|
+
| `filterParser.ts` (strict per-type `filter[k]=v`) | **Not done** — list uses `queryFields`-compatible filters directly |
|
|
49
|
+
| `actionRunner.ts` + `POST .../actions/:name` + frozen `AdminActionContext` | **Not done** — v2 uses `bulk-patch` + `background-tasks` with `patchKeys` |
|
|
50
|
+
| Per-user permission booleans in `/admin/config` | **Partial** — `permissions` are static config flags (`create/update/delete !== false`), not evaluated per requesting user |
|
|
51
|
+
| `adminFilter` async row scoping | **Not done** (only `queryFilter` on `AdminModelConfig`) |
|
|
52
|
+
| `capabilities`, `widgetIds` top-level config | **Not done** |
|
|
53
|
+
| `Cache-Control: private, no-store` on config | **Not verified** |
|
|
54
|
+
|
|
55
|
+
### `@terreno/admin-frontend` (Phases 3–4) — v2 UI exists, provider/registry pattern missing
|
|
56
|
+
|
|
57
|
+
| Planned | Status |
|
|
58
|
+
|---------|--------|
|
|
59
|
+
| `AdminProvider` + three-bucket widget registry (`fields`, `home`, `screens`) | **Not done** |
|
|
60
|
+
| `AdminScreenRouter` | **Not done** — `example-frontend` still uses string-switch in `[model]/index.tsx` |
|
|
61
|
+
| Widget modules under `widgets/` | **Not done** — widgets inline in `AdminHome.tsx` |
|
|
62
|
+
| `AdminFilterDrawer` (right rail / mobile sheet) | **Not done** — filters inline in `AdminModelTable` |
|
|
63
|
+
| `AdminActionMenu` component | **Not done** — bulk UI inline in table |
|
|
64
|
+
| `AdminFieldRenderer` reads widgets from context | **Not done** — hardcoded switch |
|
|
65
|
+
| Plugin home widgets via registry (`feature-flags-overrides`) | **Warn-only** in `AdminHome` — no injectable component |
|
|
66
|
+
|
|
67
|
+
### Pre-built plugin migrations (Phase 5) — not started
|
|
68
|
+
|
|
69
|
+
- `FeatureFlagsApp.adminContribution()` — still exports `featureFlagAdminConfig` passed manually in `example-backend`
|
|
70
|
+
- `ConsentApp.adminContribution()` — consent admins wired manually in server
|
|
71
|
+
- `DocumentStorageApp` / AI explorer — custom screens hand-rolled in example-frontend (`ADMIN_CUSTOM_SCREENS`, `AIAdminScreen`)
|
|
72
|
+
|
|
73
|
+
### Docs / examples (Phase 6–7) — not started
|
|
74
|
+
|
|
75
|
+
- No `docs/how-to/admin-*.md` or `docs/reference/admin-config.md`
|
|
76
|
+
- Example apps not migrated to `admin:` on modelRouter / `AdminProvider` / `AdminScreenRouter`
|
|
77
|
+
- MCP `generate_route` still emits legacy patterns
|
|
78
|
+
|
|
79
|
+
## Contract tensions (v2 vs original admin-improvements IP)
|
|
80
|
+
|
|
81
|
+
These need product decisions before rewriting the IP:
|
|
82
|
+
|
|
83
|
+
1. **Bulk actions API**
|
|
84
|
+
- **v2:** declarative `actions[]` with `patchKeys` → `POST .../bulk-patch` or `background-tasks`
|
|
85
|
+
- **admin-improvements:** imperative `AdminAction.run(ctx)` → `POST .../actions/:name`
|
|
86
|
+
- Both can coexist or one can subsume the other.
|
|
87
|
+
|
|
88
|
+
2. **Home layout config**
|
|
89
|
+
- **v2:** `home.slots` (Django template regions) with string widget ids
|
|
90
|
+
- **admin-improvements:** `home.widgets` array of typed specs (`{type:"modelStats"}`, plugin id strings, React components)
|
|
91
|
+
- Shipped contract is `slots`; IP must align to v2 unless breaking.
|
|
92
|
+
|
|
93
|
+
3. **Filter wire format**
|
|
94
|
+
- **v2:** filters map to existing `queryFields` query params (kind-specific UI in table)
|
|
95
|
+
- **admin-improvements:** strict `filter[field]=value` parser module with injection hardening
|
|
96
|
+
- May be additive hardening on top of v2, or a new encoding.
|
|
97
|
+
|
|
98
|
+
4. **Config field names**
|
|
99
|
+
- **v2:** kept `listFields`, `defaultSort`
|
|
100
|
+
- **admin-improvements:** originally considered `listDisplay` / `ordering` aliases — v2 added `listDisplay` alongside `listFields` in model meta
|
|
101
|
+
|
|
102
|
+
5. **Per-user `/admin/config`**
|
|
103
|
+
- **admin-improvements:** evaluate permissions per request (uncacheable)
|
|
104
|
+
- **v2:** static permission flags on model config
|
|
105
|
+
|
|
106
|
+
## Candidate delivery options (not chosen — for Step 3)
|
|
107
|
+
|
|
108
|
+
| Option | Scope | Tradeoff |
|
|
109
|
+
|--------|-------|----------|
|
|
110
|
+
| **A. Architecture-only** | Phases 1–2 + 5 + 6 (api types, aggregation, plugin contributions, docs); keep v2 UI/components as-is | Fastest path to “admin on modelRouter”; least UI churn |
|
|
111
|
+
| **B. Full original IP** | All phases including AdminProvider, ScreenRouter, filterParser, `/actions/:name`, drawer, docs, E2E | Largest diff; some v2 work duplicated or replaced |
|
|
112
|
+
| **C. Incremental slices** | Ship A first, then provider/registry (Phase 3), then optional hardening (filterParser, per-user config) | Lower risk; longer calendar time |
|
|
113
|
+
|
|
114
|
+
## Decisions recorded (2026-08-20)
|
|
115
|
+
|
|
116
|
+
| # | Choice |
|
|
117
|
+
|---|--------|
|
|
118
|
+
| 1 | **B** — Full IP (provider, screen router, drawer, filterParser, plugins, docs, E2E) |
|
|
119
|
+
| 2 | **A** — Bulk actions: v2 `bulk-patch` only; no `/actions/:name` |
|
|
120
|
+
| 3 | **A** — `home.slots` canonical |
|
|
121
|
+
| 4 | **B** — Static permission flags on config |
|
|
122
|
+
| 5 | **A** — `filterParser` with v2-compatible wire shape |
|
|
123
|
+
| 6 | **A** — Plugin widgets in `admin-frontend/src/widgets/` |
|
|
124
|
+
| 7 | **A** — Atomic example-backend + frontend + admin-spa migration |
|
|
125
|
+
| 8 | **B** — New roadmap tracking issue |
|
|
126
|
+
|
|
127
|
+
IP and task list updated: `admin-improvements.md`, `docs/tasks/admin-improvements.md`.
|
|
128
|
+
|
|
129
|
+
## References
|
|
130
|
+
|
|
131
|
+
- `docs/implementationPlans/admin-improvements.md` — original full IP (pre–v2)
|
|
132
|
+
- `docs/implementationPlans/admin-ui-v2-django-parity.md` — shipped v2 IP
|
|
133
|
+
- `docs/tasks/admin-improvements.md` — unchecked task list
|
|
134
|
+
- `example-backend/src/server.ts` — still uses `AdminApp({ models: [featureFlagAdminConfig, …] })`
|
|
135
|
+
- `example-frontend/app/admin/[model]/index.tsx` — manual screen routing
|
|
136
|
+
- `admin-frontend/src/AdminHome.tsx` — inline widgets, no `AdminProvider`
|