@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,429 +1,265 @@
|
|
|
1
|
-
# Task List: Admin
|
|
1
|
+
# Task List: Admin Improvements (post–Admin UI v2)
|
|
2
2
|
|
|
3
|
-
*
|
|
3
|
+
*Executable checklist for the gap after [Admin UI v2](./admin-ui-v2-django-parity.md). See [admin-improvements.md](../implementationPlans/admin-improvements.md).*
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Decisions (2026-08-20):** Full IP; bulk actions = v2 `bulk-patch` only (no `/actions/:name`); `home.slots`; static permissions; `filterParser`; widgets in `admin-frontend/src/widgets/`; atomic example migration; new roadmap issue.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Phase 0 — Admin UI v2 baseline (complete)
|
|
10
|
+
|
|
11
|
+
*Do not re-implement. Reference: `docs/implementationPlans/admin-ui-v2-django-parity.md`.*
|
|
12
|
+
|
|
13
|
+
- [x] **Task 0.1**: Config contract `schemaVersion: 2`, model meta, `home.slots`, scripts, customScreens
|
|
14
|
+
- Evidence: `admin-backend/src/adminApp.models.test.ts`
|
|
15
|
+
|
|
16
|
+
- [x] **Task 0.2**: `bulk-patch` + `background-tasks` + script runner
|
|
17
|
+
- Evidence: `admin-backend/src/adminApp.ts`, `admin-script-runner.md`
|
|
18
|
+
|
|
19
|
+
- [x] **Task 0.3**: `AdminShell`, `AdminHome`, list search/filters/bulk (inline), form fieldsets/readonly
|
|
20
|
+
- Evidence: `admin-frontend/src/AdminShell.tsx`, `AdminHome.tsx`, `AdminModelTable.tsx`, `AdminModelForm.tsx`
|
|
21
|
+
|
|
22
|
+
- [x] **Task 0.4**: Audit log + `recentActivity` widget
|
|
23
|
+
- Evidence: `example-backend` `AdminAuditLog`, `AdminHome.test.tsx`
|
|
24
|
+
|
|
25
|
+
- [x] **Task 0.5**: admin-spa + example v2 demo
|
|
26
|
+
- Evidence: `admin-spa/`, `example-backend/src/server.ts` v2 registrations
|
|
27
|
+
|
|
28
|
+
---
|
|
6
29
|
|
|
7
30
|
## Phase 1 — Core API surface (`@terreno/api`)
|
|
8
31
|
|
|
9
|
-
- [
|
|
10
|
-
-
|
|
11
|
-
- Files: `api/src/terrenoPlugin.ts`, `
|
|
12
|
-
-
|
|
13
|
-
- Acceptance: Existing tests pass unchanged. A new test verifies a plugin's `register` receives the `TerrenoApp` instance as the third arg. `_buildWithContext` is the public-internal API; `_buildWithOpenApi` no longer exists.
|
|
32
|
+
- [x] **Task 1.0**: Extend `TerrenoPlugin.register` additively
|
|
33
|
+
- `register(app, openApi?, terrenoApp?)`; `TerrenoApp.build()` passes `this`; rename `_buildWithOpenApi` → `_buildWithContext({openApi, terrenoApp})`; `setMaxListeners(50)`
|
|
34
|
+
- Files: `api/src/terrenoPlugin.ts`, `terrenoApp.ts`, `api.ts`
|
|
35
|
+
- Acceptance: Existing plugins compile; test receives `terrenoApp` as third arg.
|
|
14
36
|
|
|
15
|
-
- [
|
|
16
|
-
-
|
|
17
|
-
- Files: `api/src/adminTypes.ts`, `
|
|
18
|
-
-
|
|
19
|
-
- Acceptance: Types import successfully into `admin-backend`, `feature-flags`, and a new test file. No type errors across the monorepo (`bun run compile`).
|
|
37
|
+
- [x] **Task 1.1**: `api/src/adminTypes.ts`
|
|
38
|
+
- Export `AdminConfig`, `AdminFilter`, `AdminFieldset`, `AdminContribution`, `AdminModelContribution`, `AdminCustomScreen`, `AdminHomeWidgetContribution`, `AdminChangeEvent`, etc. (no `AdminAction.run` — bulk stays declarative v2 shape)
|
|
39
|
+
- Files: `api/src/adminTypes.ts`, `index.ts`
|
|
40
|
+
- Acceptance: `bun run compile` clean across monorepo.
|
|
20
41
|
|
|
21
|
-
- [
|
|
22
|
-
-
|
|
23
|
-
- Files: `api/src/api.ts`
|
|
42
|
+
- [x] **Task 1.2**: `admin?: AdminConfig` on `ModelRouterOptions`
|
|
43
|
+
- Files: `api/src/api.ts`
|
|
24
44
|
- Depends on: 1.1
|
|
25
|
-
- Acceptance: Existing example-backend compiles unchanged. Adding `admin: {displayName: "X", listDisplay: ["name"]}` to a `modelRouter` call typechecks.
|
|
26
45
|
|
|
27
|
-
- [
|
|
28
|
-
-
|
|
29
|
-
- Files: `api/src/terrenoApp.ts`, `api/src/terrenoApp.test.ts` (add accessor tests)
|
|
46
|
+
- [x] **Task 1.3**: `TerrenoApp.getRegistrations()` + `getPlugins()`
|
|
47
|
+
- Files: `api/src/terrenoApp.ts`, tests
|
|
30
48
|
- Depends on: none
|
|
31
|
-
- Acceptance: Test verifies `app.getRegistrations()` returns each registered router and `getPlugins()` returns each registered plugin.
|
|
32
49
|
|
|
33
|
-
- [
|
|
34
|
-
-
|
|
35
|
-
- Files: `api/src/terrenoPlugin.ts`
|
|
50
|
+
- [x] **Task 1.4**: `TerrenoPlugin.adminContribution?()`
|
|
51
|
+
- Files: `api/src/terrenoPlugin.ts`
|
|
36
52
|
- Depends on: 1.1
|
|
37
|
-
- Acceptance: Existing plugins (`FeatureFlagsApp`, `ConsentApp`, `DocumentStorageApp`, `LangfuseApp`, `BetterAuthApp`, `api-health`) compile unchanged.
|
|
38
53
|
|
|
39
|
-
- [
|
|
40
|
-
-
|
|
41
|
-
- Files: `api/src/terrenoApp.ts`, `api/src/terrenoApp.test.ts`
|
|
54
|
+
- [x] **Task 1.5**: Typed event bus (`admin:model.changed`)
|
|
55
|
+
- Files: `api/src/terrenoApp.ts`, tests
|
|
42
56
|
- Depends on: 1.1
|
|
43
|
-
- Acceptance: Tests verify (a) listeners receive emitted events, (b) `off` removes them, (c) typing prevents emitting unknown event names.
|
|
44
57
|
|
|
45
|
-
- [
|
|
46
|
-
-
|
|
47
|
-
- Files: `api/src/api.ts`, `api/src/scrubAdminFields.ts` (NEW), `api/src/terrenoApp.ts`, `api/src/api.test.ts`
|
|
48
|
-
- Depends on: 1.0, 1.2, 1.5
|
|
49
|
-
- Acceptance: Test with `admin: {realtime: true, excludeFields: ["hash"]}` on a User-like model verifies events fire and the emitted `document` payload contains no `hash`. With `realtime: false`, no event. Delete event omits `document`.
|
|
50
|
-
|
|
51
|
-
- [ ] **Task 1.6a (NEW)**: Shared scrub helper for excludeFields/hiddenFields with population
|
|
52
|
-
- Description: Build the `scrubAdminFields(value, model, adminConfig, allModelAdmins)` helper. Recursive: when scrubbing a populated ref, look up the referenced model in `allModelAdmins` and apply *its* exclude+hidden union. If the referenced model has no admin config, return populated value as-is. Used by Task 1.6 emit AND by AdminApp's response handler (replaces today's `removeHiddenFields` in admin-backend/src/adminApp.ts:132).
|
|
53
|
-
- Files: `api/src/scrubAdminFields.ts`, `api/src/scrubAdminFields.test.ts`
|
|
58
|
+
- [x] **Task 1.6**: `scrubAdminFields` helper + populated recursion
|
|
59
|
+
- Files: `api/src/scrubAdminFields.ts`, tests
|
|
54
60
|
- Depends on: 1.1
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
- Files: `admin-backend/src/adminApp.ts`,
|
|
66
|
-
- Depends on: 1.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- [ ] **Task 1.8**: `excludeFields` server-side enforcement
|
|
70
|
-
- Description: Treat `admin.excludeFields` as a superset of `hiddenFields`: stripped from POST + PATCH bodies AND from list + detail responses. Existing `hiddenFields` continues to work and merges with `excludeFields` (union).
|
|
71
|
-
- Files: `api/src/api.ts`, `api/src/api.test.ts`
|
|
72
|
-
- Depends on: 1.2
|
|
73
|
-
- Acceptance: A model with `excludeFields: ["hash"]` never includes `hash` in any admin response, and a POST/PATCH attempting to set `hash` does not persist it.
|
|
61
|
+
|
|
62
|
+
- [x] **Task 1.7**: Emit scrubbed `admin:model.changed` when `admin.realtime`
|
|
63
|
+
- Files: `api/src/api.ts`, tests
|
|
64
|
+
- Depends on: 1.0, 1.2, 1.5, 1.6
|
|
65
|
+
|
|
66
|
+
- [x] **Task 1.8**: `readonlyFields` / `excludeFields` enforcement on body-accepting routes
|
|
67
|
+
- Files: `api/src/api.ts`, tests
|
|
68
|
+
- Depends on: 1.0, 1.2, 1.6
|
|
69
|
+
|
|
70
|
+
- [x] **Task 1.9**: Wire `scrubAdminFields` into admin response paths (populated refs)
|
|
71
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
72
|
+
- Depends on: 1.6, 2.2
|
|
73
|
+
|
|
74
|
+
---
|
|
74
75
|
|
|
75
76
|
## Phase 2 — Admin backend aggregation
|
|
76
77
|
|
|
77
|
-
- [
|
|
78
|
-
-
|
|
79
|
-
- Files: `admin-backend/src/legacy.ts`, `admin-backend/src/legacy.test.ts`
|
|
78
|
+
- [x] **Task 2.1**: `legacy.ts` adapter + deprecation warnings
|
|
79
|
+
- Files: `admin-backend/src/legacy.ts`, tests
|
|
80
80
|
- Depends on: 1.1
|
|
81
|
-
- Acceptance: `convertLegacy({model, listFields: ['email']})` returns an equivalent `AdminModelContribution`. Same input twice → warning logged once. Both `listFields` and `defaultSort` map to `listDisplay` and `ordering`.
|
|
82
81
|
|
|
83
|
-
- [
|
|
84
|
-
-
|
|
85
|
-
- Files: `admin-backend/src/adminApp.ts`,
|
|
82
|
+
- [x] **Task 2.2**: Aggregate from modelRouter `admin:` + plugins + legacy `models`
|
|
83
|
+
- Precedence: registered router > plugin > legacy; throw on duplicate registered `routePath`
|
|
84
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
86
85
|
- Depends on: 1.3, 1.4, 2.1
|
|
87
|
-
- Acceptance: Test with a `TerrenoApp` that has (a) one modelRouter with `admin:`, (b) a plugin that returns `{models: [...]}` from `adminContribution()`, (c) an AdminApp with legacy `models: [...]`. `/admin/config` returns all three with no duplicates and the right precedence.
|
|
88
86
|
|
|
89
|
-
- [
|
|
90
|
-
-
|
|
91
|
-
- Files: `admin-backend/src/adminApp.ts`, `admin-backend/src/adminApp.test.ts`
|
|
87
|
+
- [x] **Task 2.3**: Merge `customScreens`, `homeWidgets` → `widgetIds`, plugin `scripts`
|
|
88
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
92
89
|
- Depends on: 2.2
|
|
93
|
-
- Acceptance: A plugin contributing `{customScreens: [{name: "x"}], homeWidgets: [{id: "w"}]}` causes `/admin/config` to include those entries. Host without `home.widgets: ["w"]` does *not* surface the widget by default.
|
|
94
90
|
|
|
95
|
-
- [
|
|
96
|
-
-
|
|
97
|
-
- Files: `admin-backend/src/adminApp.ts`, `admin-backend/src/adminApp.test.ts`
|
|
91
|
+
- [x] **Task 2.4**: Add `widgetIds`, `capabilities` to `/admin/config` (additive; v2 fields unchanged)
|
|
92
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
98
93
|
- Depends on: 2.2
|
|
99
|
-
- Acceptance: GET /admin/config returns the extended shape. Snapshot test covers the response. `listFields === listDisplay` and `defaultSort === ordering` for back-compat.
|
|
100
94
|
|
|
101
|
-
- [
|
|
102
|
-
-
|
|
103
|
-
- Files: `admin-backend/src/adminApp.ts
|
|
95
|
+
- [x] **Task 2.5**: Static `permissions` flags on config (v2 behavior — **no per-user eval**)
|
|
96
|
+
- Verify/document: flags reflect `adminPermissions` config, not runtime user
|
|
97
|
+
- Files: `admin-backend/src/adminApp.ts` (docs/tests only if already correct)
|
|
104
98
|
- Depends on: 2.4
|
|
105
|
-
- Acceptance: Two users with different permissions receive different `permissions` blocks. `Cache-Control: private, no-store` header present.
|
|
106
99
|
|
|
107
|
-
- [
|
|
108
|
-
-
|
|
109
|
-
- Files: `admin-backend/src/filterParser.ts`,
|
|
100
|
+
- [x] **Task 2.6**: `filterParser.ts` — strict per-type validation, injection hardening
|
|
101
|
+
- Accept v2-compatible query shapes (`field`, `field_gte`/`field_lte` for dateRange, etc.)
|
|
102
|
+
- Files: `admin-backend/src/filterParser.ts`, tests (matrix from original IP)
|
|
110
103
|
- Depends on: 1.1
|
|
111
|
-
- Acceptance: Test matrix covers:
|
|
112
|
-
- boolean: accepts `"true"`/`"false"`, rejects arrays / `"yes"` / objects
|
|
113
|
-
- text: accepts scalar string, rejects arrays / objects
|
|
114
|
-
- choice: accepts declared values, rejects unknown values / arrays / objects
|
|
115
|
-
- ref: accepts valid ObjectId, rejects non-ObjectId / arrays / objects
|
|
116
|
-
- date: accepts ISO string, rejects arrays / objects / malformed
|
|
117
|
-
- dateRange: accepts `{gte, lte}` only with optional keys, rejects scalars / arrays / extra keys / non-ISO values
|
|
118
|
-
- Operator injection: `filter[role][$ne]=admin`, `filter[role][$where]=...`, `filter[role][$regex]=...` all return 400
|
|
119
|
-
- Prototype pollution: `filter[__proto__][toString]=...`, `filter[constructor][prototype][toString]=...` dropped silently, warn-logged
|
|
120
|
-
- Undeclared field: `filter[ssn]=123` silently ignored, no 400
|
|
121
|
-
|
|
122
|
-
- [ ] **Task 2.7 (revised)**: Wire filter parser, `sortableFields`, and shared search helper
|
|
123
|
-
- Description: In the admin's internal modelRouter creation, the modelRouter's `queryFilter` becomes an async adapter that awaits `adminFilter(req)` and merges with the parsed filter object. Validate `?sort=` against `sortableFields` (400 on unknown). Build a single `runSearch(model, q, searchFields)` helper used by both the list endpoint (`?q=`) and the existing `/search` endpoint — the two no longer have separate implementations. The list endpoint inlines search-as-filter using `$or` over `searchFields` (or `_id` for valid ObjectIds), avoiding a separate round-trip.
|
|
124
|
-
- Files: `admin-backend/src/adminApp.ts`, `admin-backend/src/runSearch.ts` (NEW; extract from existing /search code), `admin-backend/src/adminApp.test.ts`
|
|
125
|
-
- Depends on: 2.6
|
|
126
|
-
- Acceptance: `GET /admin/users?filter[admin]=true&q=alice&sort=-created&pageSize=10` returns matching admin users named "alice", sorted newest first, 10 per page, with no extra DB round-trip beyond list + count. Unknown sort field → 400. `?filter[ssn]=...` (undeclared) ignored. `adminFilter` invoked once per request and properly awaited.
|
|
127
|
-
|
|
128
|
-
- [ ] **Task 2.8 (revised)**: Action runner endpoint with frozen `AdminActionContext`
|
|
129
|
-
- Description: Create `admin-backend/src/actionRunner.ts`. Mount `POST /admin/{routePath}/actions/:actionName` per model with declared actions. Validate body `{ids: string[]}` — reject `ids.length > MAX_ACTION_IDS` (default 1000) with HTTP 413. Look up action by name. Run `action.permissions` (or fall back to `adminPermissions.update`). Validate ids via ONE round-trip: `Model.find({_id: {$in: ids}, ...resolvedAdminFilter}).select("_id")`. Silently drop ids that don't pass; pass the survivors into `ctx.ids`. Build a frozen `AdminActionContext` (no live `req`). If `action.background: true`: persist the context onto a `BackgroundTask`, return `{taskId}`. Else invoke `action.run(ctx)` synchronously and return `{updatedIds?, message?, results?}`. Wrap errors → `APIError`.
|
|
130
|
-
- Files: `admin-backend/src/actionRunner.ts`, `admin-backend/src/actionRunner.test.ts`, `admin-backend/src/adminApp.ts` (mount routes)
|
|
131
|
-
- Depends on: 2.2, 2.8a
|
|
132
|
-
- Acceptance: Sync action: returns updated rows. Background action: returns `{taskId}`, runner picks it up later, `GET /admin/scripts/tasks/:id` reports progress. Permission denied → 403. `ids.length > 1000` → 413. ids outside `adminFilter` scope are silently excluded from `ctx.ids` (action sees fewer rows than the user selected — caller decides whether to warn). Background runner does NOT use the live `req`.
|
|
133
104
|
|
|
134
|
-
- [
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
- Depends on: 1.1
|
|
138
|
-
- Acceptance: A background action launched from request A and a background action launched from request B never see each other's context. Re-running `action.run` after the request closes does not crash (no `req.headers` access, etc.).
|
|
105
|
+
- [x] **Task 2.7**: Wire filterParser + `adminFilter` async + `sortableFields` enforcement
|
|
106
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
107
|
+
- Depends on: 2.6
|
|
139
108
|
|
|
140
|
-
- [
|
|
141
|
-
-
|
|
142
|
-
- Files: `admin-backend/src/adminApp.ts`, `admin-backend/src/adminApp.test.ts`
|
|
109
|
+
- [x] **Task 2.8**: `routePath` normalization + collision rules
|
|
110
|
+
- Files: `admin-backend/src/adminApp.ts`, tests
|
|
143
111
|
- Depends on: 2.2
|
|
144
|
-
- Acceptance: Two registered routers with `/users` → throw. Registered `/users` + plugin `/users` → registered wins, warn-logged. Plugin `/users` + legacy `/users` → plugin wins, warn-logged.
|
|
145
112
|
|
|
146
|
-
- [
|
|
147
|
-
- Description: Export `AdminApp`, `AdminContribution` (re-export from `api`), `AdminAction`, `AdminFilter`, `AdminFieldset` types from `admin-backend/src/index.ts`. Mark `AdminModelConfig` (legacy) and `AdminFieldOverride` for deprecation but keep exporting.
|
|
148
|
-
- Files: `admin-backend/src/index.ts`
|
|
113
|
+
- [x] **Task 2.9**: Export types from `admin-backend/src/index.ts`
|
|
149
114
|
- Depends on: 2.2
|
|
150
|
-
|
|
115
|
+
|
|
116
|
+
---
|
|
151
117
|
|
|
152
118
|
## Phase 3 — Admin frontend foundations
|
|
153
119
|
|
|
154
|
-
- [
|
|
155
|
-
-
|
|
156
|
-
- `FieldWidgetComponent<TValue>`: `{value, onChange, fieldMeta, disabled, errorText, testID}`
|
|
157
|
-
- `HomeWidgetComponent`: `{config?: unknown, modelMetas: AdminModelMeta[]}`
|
|
158
|
-
- `ScreenWidgetComponent`: `{name, displayName, params?: Record<string, string>}`
|
|
159
|
-
Provide `useAdminContext()` hook + sub-hooks `useFieldWidget(name)`, `useHomeWidget(name)`, `useScreenWidget(name)` that return a "MissingWidget" placeholder + one-time `console.warn` when the key isn't registered.
|
|
160
|
-
- Files: `admin-frontend/src/AdminProvider.tsx`, `admin-frontend/src/AdminProvider.test.tsx`, `admin-frontend/src/types.ts`
|
|
120
|
+
- [x] **Task 3.1**: `AdminProvider` + three-bucket widget registry + hooks
|
|
121
|
+
- Files: `admin-frontend/src/AdminProvider.tsx`, `types.ts`, tests
|
|
161
122
|
- Depends on: none
|
|
162
|
-
- Acceptance: All three sub-hooks return registered components when present; return a placeholder component when missing and warn exactly once per (bucket, name) pair. `useAdminContext` throws with helpful message outside provider.
|
|
163
123
|
|
|
164
|
-
- [
|
|
165
|
-
-
|
|
166
|
-
- Files: `admin-frontend/src/types.ts`
|
|
124
|
+
- [x] **Task 3.2**: Extend frontend types for `widgetIds`, `capabilities`, `autocompleteFields`, `excludeFields`
|
|
125
|
+
- Files: `admin-frontend/src/types.ts`
|
|
167
126
|
- Depends on: 2.4
|
|
168
|
-
- Acceptance: Types compile; `useAdminConfig` returns the extended shape.
|
|
169
127
|
|
|
170
|
-
- [
|
|
171
|
-
-
|
|
172
|
-
- Files: `admin-frontend/src/AdminScreenRouter.tsx`, `admin-frontend/src/AdminScreenRouter.test.tsx`
|
|
128
|
+
- [x] **Task 3.3**: `AdminScreenRouter`
|
|
129
|
+
- Files: `admin-frontend/src/AdminScreenRouter.tsx`, tests
|
|
173
130
|
- Depends on: 3.1, 3.2, 2.3
|
|
174
|
-
- Acceptance: Render with a model name → table appears. Render with a customScreen name + registered widget → widget appears. Unknown name → helpful error.
|
|
175
131
|
|
|
176
|
-
- [
|
|
177
|
-
-
|
|
178
|
-
- Files: `admin-frontend/src/AdminHome.tsx`, `
|
|
132
|
+
- [x] **Task 3.4**: Refactor `AdminHome` — slots + registry (built-ins + plugin ids)
|
|
133
|
+
- Extract widget renderers to `widgets/`; keep slot layout from v2
|
|
134
|
+
- Files: `admin-frontend/src/AdminHome.tsx`, `widgets/*`, tests
|
|
179
135
|
- Depends on: 3.1, 3.2
|
|
180
|
-
- Acceptance: With no `home` config → legacy grid renders. With `home.widgets: [{type:"modelStats", models:["User"]}, "feature-flags-overrides"]` → both render in order. Unknown widget id → console warning, skipped silently.
|
|
181
136
|
|
|
182
|
-
- [
|
|
183
|
-
-
|
|
184
|
-
- Files: `admin-frontend/src/widgets
|
|
185
|
-
- Depends on: 3.
|
|
186
|
-
- Acceptance: Renders all models with field counts. `group="Identity"` shows only Users in the example app.
|
|
187
|
-
|
|
188
|
-
- [ ] **Task 3.6**: Built-in `ModelStatsWidget`
|
|
189
|
-
- Description: For each model in `models` prop, run `useListQuery({pageSize: 1, page: 1})` and display the total count plus model display name + link. Loading shimmer state. Error fallback shows the model name with `—`.
|
|
190
|
-
- Files: `admin-frontend/src/widgets/ModelStatsWidget.tsx`, `admin-frontend/src/widgets/ModelStatsWidget.test.tsx`
|
|
191
|
-
- Depends on: 3.1, 3.2
|
|
192
|
-
- Acceptance: Renders counts for the configured models; empty models prop → renders nothing.
|
|
137
|
+
- [x] **Task 3.5**: Extract built-in widgets to `widgets/`
|
|
138
|
+
- `ModelsGridWidget`, `ModelStatsWidget`, `RecentActivityWidget`, `ScriptRunnerWidget`, `CustomScreensListWidget`, `VersionConfigWidget`
|
|
139
|
+
- Files: `admin-frontend/src/widgets/*.tsx`, tests
|
|
140
|
+
- Depends on: 3.4
|
|
193
141
|
|
|
194
|
-
- [
|
|
195
|
-
-
|
|
196
|
-
- Files: `admin-frontend/src/widgets/RecentActivityWidget.tsx`, `admin-frontend/src/widgets/RecentActivityWidget.test.tsx`
|
|
197
|
-
- Depends on: 3.1, 3.2
|
|
198
|
-
- Acceptance: With `limit: 5` and three models, shows 5 most-recently-updated items across the three.
|
|
199
|
-
|
|
200
|
-
- [ ] **Task 3.8**: Built-in `ScriptRunnerWidget`
|
|
201
|
-
- Description: Compact replacement for `AdminScriptList` on the home page: just the script name + a Run button that opens the existing `AdminScriptRunModal`.
|
|
202
|
-
- Files: `admin-frontend/src/widgets/ScriptRunnerWidget.tsx`, `admin-frontend/src/widgets/ScriptRunnerWidget.test.tsx`
|
|
142
|
+
- [x] **Task 3.6**: `AdminFieldRenderer` + form widget lookup from context
|
|
143
|
+
- Files: `AdminFieldRenderer.tsx`, `AdminModelForm.tsx`, tests
|
|
203
144
|
- Depends on: 3.1
|
|
204
|
-
- Acceptance: Renders the scripts from `/admin/config`; clicking Run opens the existing modal and the script executes.
|
|
205
|
-
|
|
206
|
-
- [ ] **Task 3.9**: Built-in `CustomScreensListWidget`
|
|
207
|
-
- Description: Renders one card per `customScreen` from `/admin/config`, navigating to `/admin/{name}`.
|
|
208
|
-
- Files: `admin-frontend/src/widgets/CustomScreensListWidget.tsx`, `admin-frontend/src/widgets/CustomScreensListWidget.test.tsx`
|
|
209
|
-
- Depends on: 3.2
|
|
210
|
-
- Acceptance: Renders DocumentStorage and any plugin-contributed custom screens.
|
|
211
145
|
|
|
212
|
-
- [
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
- Depends on: 3.1
|
|
216
|
-
- Acceptance: Registering `widgets={{fields: {markdown: MyMarkdownEditor}}}` causes a field with `widget: "markdown"` to use `MyMarkdownEditor`. Unregistered widget → falls back to default with a one-time `console.warn`.
|
|
146
|
+
- [x] **Task 3.7**: `AdminModelList` thin wrapper → `AdminHome` + deprecation for `customScreens` prop
|
|
147
|
+
- Files: `AdminModelList.tsx`
|
|
148
|
+
- Depends on: 3.4
|
|
217
149
|
|
|
218
|
-
- [
|
|
219
|
-
-
|
|
220
|
-
-
|
|
221
|
-
- Depends on: 3.4, 3.5, 3.8, 3.9
|
|
222
|
-
- Acceptance: Existing consumers (example-frontend's `app/admin/index.tsx`) render unchanged. Deprecation warning fires once if `customScreens` prop is set.
|
|
150
|
+
- [x] **Task 3.8**: Package exports (`AdminProvider`, `AdminScreenRouter`, `BUILT_IN_*_WIDGETS`)
|
|
151
|
+
- Files: `admin-frontend/src/index.tsx`
|
|
152
|
+
- Depends on: 3.1–3.7
|
|
223
153
|
|
|
224
|
-
|
|
225
|
-
- Description: Update `admin-frontend/src/index.tsx` to export: `AdminProvider`, `AdminScreenRouter`, `AdminHome`, all built-in widgets, the widget registry types, and a `BUILT_IN_WIDGETS` object so consumers can spread it: `widgets={{fields: {...BUILT_IN_FIELD_WIDGETS, ...mine}, home: {...BUILT_IN_HOME_WIDGETS, ...mine}}}`.
|
|
226
|
-
- Files: `admin-frontend/src/index.tsx`
|
|
227
|
-
- Depends on: 3.1, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10
|
|
228
|
-
- Acceptance: `import {AdminProvider, AdminHome, AdminScreenRouter, BUILT_IN_FIELD_WIDGETS} from "@terreno/admin-frontend"` works.
|
|
154
|
+
---
|
|
229
155
|
|
|
230
156
|
## Phase 4 — Admin frontend feature lift
|
|
231
157
|
|
|
232
|
-
- [
|
|
233
|
-
-
|
|
234
|
-
- Files: `
|
|
235
|
-
- Depends on: 2.7, 3.2
|
|
236
|
-
- Acceptance: Typing in the search box waits 250ms, fires one request with `?q=`. Empty box hides search hits. Clearing → resets to unsearched list. `getByTestId("admin-table-search")` works.
|
|
237
|
-
|
|
238
|
-
- [ ] **Task 4.2 (revised)**: `AdminFilterDrawer`
|
|
239
|
-
- Description: Right-side collapsible drawer rendered when `modelMeta.filters.length > 0`. Renders one input per filter type:
|
|
240
|
-
- `boolean` → BooleanField (toggle) — `testID="admin-filter-{field}"`
|
|
241
|
-
- `text` → TextField — `testID="admin-filter-{field}"`
|
|
242
|
-
- `choice` → SelectField — `testID="admin-filter-{field}"`
|
|
243
|
-
- `ref` → AdminRefField in autocomplete mode — `testID="admin-filter-{field}"`
|
|
244
|
-
- `date` → DateTimeField (single) — `testID="admin-filter-{field}"`
|
|
245
|
-
- `dateRange` → two DateTimeFields — `testID="admin-filter-{field}-gte"` / `"admin-filter-{field}-lte"`
|
|
246
|
-
State serialized as `filter[k]=v` (range as `filter[k][gte]=` / `[lte]=`). Apply button (`testID="admin-filter-apply"`) updates the list query. On mobile (`<md`) → bottom-sheet via existing `ActionSheet` pattern (`testID="admin-filter-sheet"`). Drawer root `testID="admin-filter-drawer"`.
|
|
247
|
-
- Files: `admin-frontend/src/AdminFilterDrawer.tsx`, `admin-frontend/src/AdminFilterDrawer.test.tsx`, `admin-frontend/src/AdminModelTable.tsx` (mount)
|
|
158
|
+
- [x] **Task 4.1**: `AdminFilterDrawer` — replace inline filters in `AdminModelTable`
|
|
159
|
+
- Mobile sheet; testIDs per original spec
|
|
160
|
+
- Files: `AdminFilterDrawer.tsx`, `AdminModelTable.tsx`, tests
|
|
248
161
|
- Depends on: 3.2
|
|
249
|
-
- Acceptance: Selecting "admin: true" in the drawer narrows the list. Combining filters AND-narrows server-side. Drawer collapses/expands via header toggle. Mobile viewport → sheet. All testIDs accessible.
|
|
250
162
|
|
|
251
|
-
- [
|
|
252
|
-
-
|
|
253
|
-
-
|
|
254
|
-
- Depends on: none
|
|
255
|
-
- Acceptance: Selecting 3 rows shows "3 selected". Header checkbox toggles current page. Filter / search / sort change clears selection. testIDs queryable.
|
|
163
|
+
- [x] **Task 4.2**: Extract `AdminActionMenu` — still uses `bulk-patch` / `background-tasks`
|
|
164
|
+
- Files: `AdminActionMenu.tsx`, `AdminModelTable.tsx`, tests
|
|
165
|
+
- Depends on: none (v2 logic move)
|
|
256
166
|
|
|
257
|
-
- [
|
|
258
|
-
-
|
|
259
|
-
-
|
|
260
|
-
- Depends on: 2.8, 4.3
|
|
261
|
-
- Acceptance: Selecting 2 rows and running "Activate" → POST fires with both ids, success toast, list refetches. Selecting a background action → modal opens with progress. Confirmation modal renders `action.confirm` text. `allowed: false` action does not render.
|
|
167
|
+
- [x] **Task 4.3**: Bulk selection polish — clear on filter/search/sort change (verify v2)
|
|
168
|
+
- Files: `AdminModelTable.tsx`, tests
|
|
169
|
+
- Depends on: 4.1
|
|
262
170
|
|
|
263
|
-
- [
|
|
264
|
-
-
|
|
265
|
-
-
|
|
266
|
-
- Depends on: 3.2
|
|
267
|
-
- Acceptance: Click on a non-sortable column header is a no-op (cursor: default). Page size defaults to `modelMeta.pageSize`.
|
|
171
|
+
- [x] **Task 4.4**: `sortableFields` + `pageSize` UI enforcement (verify/complete v2)
|
|
172
|
+
- Files: `AdminModelTable.tsx`, tests
|
|
173
|
+
- Depends on: 2.7
|
|
268
174
|
|
|
269
|
-
- [
|
|
270
|
-
-
|
|
271
|
-
- Files: `admin-frontend/src/AdminModelForm.tsx`, `admin-frontend/src/AdminModelForm.test.tsx`
|
|
175
|
+
- [x] **Task 4.5**: `autocompleteFields` async ref picker
|
|
176
|
+
- Files: `AdminRefField.tsx`, `AdminModelForm.tsx`, tests
|
|
272
177
|
- Depends on: 3.2
|
|
273
|
-
- Acceptance: A model with 3 fieldsets renders 3 collapsible groups in the configured order. Fields outside any fieldset render in an "Other" section at the bottom.
|
|
274
178
|
|
|
275
|
-
- [
|
|
276
|
-
-
|
|
277
|
-
-
|
|
278
|
-
- Depends on: 3.2
|
|
279
|
-
- Acceptance: `readonlyFields: ["created"]` → the `created` field is visible but disabled with the badge.
|
|
280
|
-
|
|
281
|
-
- [ ] **Task 4.8**: Autocomplete refs (`autocompleteFields`)
|
|
282
|
-
- Description: When a ref field is listed in `modelMeta.autocompleteFields`, render `AdminRefField` in async-search mode (debounced query against `/search?q=&fields=...` on the referenced model). Default behavior (fetch-all-and-dropdown) is preserved for refs not in the list.
|
|
283
|
-
- Files: `admin-frontend/src/AdminRefField.tsx`, `admin-frontend/src/AdminRefField.test.tsx`
|
|
284
|
-
- Depends on: 2.7, 3.2
|
|
285
|
-
- Acceptance: With `autocompleteFields: ["organizationId"]`, typing fires `/search` requests; results render in the dropdown. Without it, the field uses a full prefetch dropdown as today.
|
|
179
|
+
- [x] **Task 4.6**: Static permission UI — hide create/delete/actions when flags false
|
|
180
|
+
- Files: `AdminModelTable.tsx`, `AdminModelForm.tsx`, `AdminActionMenu.tsx`
|
|
181
|
+
- Depends on: 2.5, 4.2
|
|
286
182
|
|
|
287
|
-
|
|
288
|
-
- Description: Honor `modelMeta.permissions.{create,update,delete}` booleans from `/admin/config`. Hide "Create New" if `permissions.create === false`. Hide actions whose `allowed === false`. Hide row delete if `permissions.delete === false`.
|
|
289
|
-
- Files: `admin-frontend/src/AdminModelTable.tsx`, `admin-frontend/src/AdminModelForm.tsx`, `admin-frontend/src/AdminActionMenu.tsx`
|
|
290
|
-
- Depends on: 2.5, 4.4
|
|
291
|
-
- Acceptance: A user without create permission sees no "Create New" button in the table.
|
|
183
|
+
---
|
|
292
184
|
|
|
293
185
|
## Phase 5 — Pre-built admin migrations
|
|
294
186
|
|
|
295
|
-
- [
|
|
296
|
-
-
|
|
297
|
-
- Files: `docs/explanation/admin-plugin-frontend.md` (NEW)
|
|
187
|
+
- [x] **Task 5.1**: Document plugin widget location (`docs/explanation/admin-plugin-frontend.md`)
|
|
188
|
+
- Decision: widgets live in `admin-frontend/src/widgets/`
|
|
298
189
|
- Depends on: none
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
-
|
|
302
|
-
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
- Files:
|
|
310
|
-
- Depends on:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
-
|
|
314
|
-
- Description: Implement `adminContribution()` on `ConsentApp` to return ConsentForm and ConsentResponse admins (currently configured in `example-backend/src/server.ts`). Include `widgetComponents` field-widgets: `locale-content`, `locale-default`, `checkbox-list` (the components already exist in `admin-frontend/src` — re-export them under known keys).
|
|
315
|
-
- Files: wherever `ConsentApp` lives in `api/src/` (likely `api/src/consent/consentApp.ts`), `admin-frontend/src/widgets/consentWidgets.ts` (NEW, re-export existing editors), `admin-frontend/src/index.tsx`, plus tests
|
|
316
|
-
- Depends on: 1.4, 2.2, 3.10
|
|
317
|
-
- Acceptance: Registering `ConsentApp` causes both consent admins to appear in `/admin/config`. Form-side widgets resolve via the registry without consumer changes.
|
|
318
|
-
|
|
319
|
-
- [ ] **Task 5.4**: `DocumentStorageApp.adminContribution()`
|
|
320
|
-
- Description: Convert `DocumentStorageApp` from "parallel admin" to a proper plugin contribution: keep its `register()` (mounts the documents endpoints), but additionally return `customScreens: [{name: "documents", displayName: "Documents", icon: "folder"}]` and a frontend widget keyed `"documents"` rendering the existing `DocumentStorageBrowser`. Remove the consumer's hand-roll of the route in `example-frontend`.
|
|
321
|
-
- Files: `admin-backend/src/documentStorageApp.ts`, `admin-frontend/src/widgets/DocumentsScreenWidget.tsx` (NEW, wraps existing `DocumentStorageBrowser`), tests
|
|
190
|
+
|
|
191
|
+
- [x] **Task 5.2**: `FeatureFlagsApp.adminContribution()` + deprecate `featureFlagAdminConfig`
|
|
192
|
+
- Files: `feature-flags/src/featureFlagsApp.ts`, tests
|
|
193
|
+
- Depends on: 1.4, 2.2
|
|
194
|
+
|
|
195
|
+
- [x] **Task 5.3**: `FeatureFlagOverridesWidget` in `admin-frontend/src/widgets/`
|
|
196
|
+
- Files: `widgets/FeatureFlagOverridesWidget.tsx`, tests, exports
|
|
197
|
+
- Depends on: 3.1, 5.2
|
|
198
|
+
|
|
199
|
+
- [x] **Task 5.4**: `ConsentApp.adminContribution()` + consent field widgets registry
|
|
200
|
+
- Files: consent app, `widgets/consentWidgets.ts`, tests
|
|
201
|
+
- Depends on: 1.4, 2.2, 3.6
|
|
202
|
+
|
|
203
|
+
- [x] **Task 5.5**: `DocumentStorageApp.adminContribution()` + `DocumentsScreenWidget`
|
|
204
|
+
- Files: `documentStorageApp.ts`, `widgets/DocumentsScreenWidget.tsx`, tests
|
|
322
205
|
- Depends on: 1.4, 2.3, 3.3
|
|
323
|
-
- Acceptance: `new DocumentStorageApp(...)` registered → `/admin/documents` route works in the new screen router with no host wiring.
|
|
324
206
|
|
|
325
|
-
- [
|
|
326
|
-
-
|
|
327
|
-
- Files: `ai/src/aiAdminApp.ts` (NEW), `admin-frontend/src/widgets/AIRequestsScreenWidget.tsx` (NEW; uses existing aggregation endpoint), tests
|
|
207
|
+
- [x] **Task 5.6**: `AIAdminApp` plugin + `AIRequestsScreenWidget`
|
|
208
|
+
- Files: `ai/src/aiAdminApp.ts`, `widgets/AIRequestsScreenWidget.tsx`, tests
|
|
328
209
|
- Depends on: 1.4, 2.3
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
-
|
|
343
|
-
-
|
|
344
|
-
|
|
345
|
-
- [
|
|
346
|
-
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
- Acceptance: `bun run frontend:web` runs. Admin home renders configured widgets. Navigating to `/admin/users`, `/admin/feature-flags`, `/admin/documents`, `/admin/ai-requests` all work via the screen router.
|
|
350
|
-
|
|
351
|
-
- [ ] **Task 6.3**: How-to doc — Add an admin to your model
|
|
352
|
-
- Description: Cookbook walking through adding `admin: {...}` to a `modelRouter` call, listing the most-used fields with one-line each, then showing the final `/admin/users` UI. Link from the admin-backend README.
|
|
353
|
-
- Files: `docs/how-to/admin-add-model.md`
|
|
354
|
-
- Depends on: 6.1
|
|
355
|
-
- Acceptance: Doc walks a reader through adding admin to a new model in under 5 minutes.
|
|
356
|
-
|
|
357
|
-
- [ ] **Task 6.4**: How-to doc — Custom field widget
|
|
358
|
-
- Description: Cookbook for building a custom field widget: declare the widget name in `fieldOverrides`, write the component implementing the `AdminWidgetComponent` interface, register it in the provider. Use a `RichTextEditor` example.
|
|
359
|
-
- Files: `docs/how-to/admin-custom-widget.md`
|
|
360
|
-
- Depends on: 6.2
|
|
361
|
-
- Acceptance: Doc shows a working example.
|
|
362
|
-
|
|
363
|
-
- [ ] **Task 6.5**: How-to doc — Customize the admin home page
|
|
364
|
-
- Description: Walk through `home.widgets` with each built-in widget type, plugin-contributed widgets, and an ad-hoc component.
|
|
365
|
-
- Files: `docs/how-to/admin-custom-home.md`
|
|
366
|
-
- Depends on: 6.2
|
|
367
|
-
- Acceptance: Doc demonstrates every widget type.
|
|
368
|
-
|
|
369
|
-
- [ ] **Task 6.6**: How-to doc — Import pre-built admins
|
|
370
|
-
- Description: Show how to register `ConsentApp`, `FeatureFlagsApp`, `DocumentStorageApp`, `AIAdminApp` and surface their admins. Each section is ~5 lines of code.
|
|
371
|
-
- Files: `docs/how-to/admin-import-prebuilt.md`
|
|
372
|
-
- Depends on: 6.1
|
|
373
|
-
- Acceptance: Doc covers all four plugins.
|
|
374
|
-
|
|
375
|
-
- [ ] **Task 6.7**: Reference doc — `AdminConfig`
|
|
376
|
-
- Description: Full table of `AdminConfig` fields with Django equivalents in a sidebar column. One-line description per field. Include a small "migration from legacy shape" section.
|
|
377
|
-
- Files: `docs/reference/admin-config.md`
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Phase 6 — Examples, docs, E2E (single atomic PR)
|
|
214
|
+
|
|
215
|
+
- [x] **Task 6.1**: Audit consent custom screens — `docs/explanation/admin-consent-migration.md`
|
|
216
|
+
- Depends on: 5.4
|
|
217
|
+
|
|
218
|
+
- [x] **Task 6.2**: **Atomic** migrate `example-backend` — `admin:` on modelRouters, plugins only, one legacy `models[]` entry, `home.slots`
|
|
219
|
+
- Files: `example-backend/src/server.ts`, `api/todos.ts`, `api/users.ts`
|
|
220
|
+
- Depends on: 5.2, 5.4, 5.5, 5.6
|
|
221
|
+
|
|
222
|
+
- [x] **Task 6.3**: **Atomic** migrate `example-frontend` + `admin-spa` — `AdminProvider`, `AdminHome`, `AdminScreenRouter`
|
|
223
|
+
- Files: `example-frontend/app/admin/**`, `admin-spa/app/**`
|
|
224
|
+
- Depends on: 3.8, 5.3, 5.5, 5.6
|
|
225
|
+
|
|
226
|
+
- [x] **Task 6.4**: How-to: `admin-add-model.md`, `admin-custom-widget.md`, `admin-custom-home.md`, `admin-import-prebuilt.md`
|
|
227
|
+
- Depends on: 6.2, 6.3
|
|
228
|
+
|
|
229
|
+
- [x] **Task 6.5**: Reference: `docs/reference/admin-config.md`
|
|
378
230
|
- Depends on: 1.1
|
|
379
|
-
|
|
231
|
+
|
|
232
|
+
- [x] **Task 6.6**: Playwright E2E (split by feature file)
|
|
233
|
+
- `admin-home.spec.ts`, `admin-table-search-filter.spec.ts`, `admin-table-bulk-actions.spec.ts`, `admin-form.spec.ts`, `admin-custom-screens.spec.ts`
|
|
234
|
+
- Depends on: 6.3
|
|
235
|
+
|
|
236
|
+
---
|
|
380
237
|
|
|
381
238
|
## Phase 7 — Deprecations & polish
|
|
382
239
|
|
|
383
|
-
- [ ] **Task 7.1**: Update
|
|
384
|
-
-
|
|
385
|
-
- Files: `.claude/rules/admin-backend/00-admin-backend.md`, `.claude/rules/admin-frontend/00-admin-frontend.md`
|
|
386
|
-
- Depends on: all
|
|
387
|
-
- Acceptance: Rule files show `admin:` on modelRouter, `AdminProvider`, `AdminScreenRouter`, widget registry, and the legacy shape as deprecated.
|
|
240
|
+
- [ ] **Task 7.1**: Update admin-backend + admin-frontend rule files
|
|
241
|
+
- Files: `.cursor/rules/admin-*/`, `.claude/rules/admin-*/`
|
|
388
242
|
|
|
389
|
-
- [ ] **Task 7.2**: MCP
|
|
390
|
-
-
|
|
391
|
-
- Files: `mcp-server/src/tools.ts`, `mcp-server/src/prompts.ts`
|
|
392
|
-
- Depends on: 6.7
|
|
393
|
-
- Acceptance: `generate_route` output includes an `admin: {...}` block.
|
|
243
|
+
- [ ] **Task 7.2**: MCP `generate_route` emits `admin:` block; optional `generate_admin_widget`
|
|
244
|
+
- Files: `mcp-server/src/tools.ts`, `prompts.ts`
|
|
394
245
|
|
|
395
|
-
- [ ] **Task 7.3**: CHANGELOG + version bump
|
|
396
|
-
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
-
|
|
400
|
-
|
|
401
|
-
- [ ] **Task 7.
|
|
402
|
-
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
- `admin-table-bulk-actions.spec.ts` — multi-select, sync action, background action via run modal, confirmation modal
|
|
406
|
-
- `admin-form.spec.ts` — fieldsets collapse/expand, readonly field disabled, autocomplete ref picker, validation error
|
|
407
|
-
- `admin-custom-screens.spec.ts` — Documents browser navigation + upload, AI Requests explorer
|
|
408
|
-
- All testIDs already added in Phase 4 tasks (4.1-4.4) and Phase 5. `loginAs(page)` used in `beforeEach`.
|
|
409
|
-
- Files: 5 new specs under `example-frontend/e2e/`
|
|
410
|
-
- Depends on: 6.2
|
|
411
|
-
- Acceptance: All five specs pass locally; CI runs them in parallel.
|
|
412
|
-
|
|
413
|
-
- [ ] **Task 7.5**: Cross-package compile + lint pass
|
|
414
|
-
- Description: Run `bun run compile && bun run lint` across the monorepo, fix anything that breaks from the new types or renamed exports. Re-run `bun run test`.
|
|
415
|
-
- Files: monorepo
|
|
246
|
+
- [ ] **Task 7.3**: CHANGELOG + minor version bump note
|
|
247
|
+
- Files: package CHANGELOGs
|
|
248
|
+
|
|
249
|
+
- [ ] **Task 7.4**: `docs/how-to/admin-migrate.md` for downstream consumers
|
|
250
|
+
- Depends on: 6.3
|
|
251
|
+
|
|
252
|
+
- [ ] **Task 7.5**: Structured admin telemetry logs (config size, filter errors, deprecation warnings)
|
|
253
|
+
- Files: `admin-backend/src/adminApp.ts`, `filterParser.ts`, `legacy.ts`
|
|
254
|
+
|
|
255
|
+
- [ ] **Task 7.6**: Monorepo compile + lint + test green
|
|
416
256
|
- Depends on: all
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
-
|
|
426
|
-
- Description: Add structured log lines (via `logger.info` with stable shape) for: (1) `/admin/config` response time + size, (2) action invocation: `{actionName, modelName, idCount, userId, durationMs, outcome: "ok"|"error"|"forbidden"|"rejected"}`, (3) filter parse errors: `{modelName, filterName, error}`, (4) deprecation warnings (legacy shape, legacy export, legacy customScreens prop): emit each once-per-process. No new dashboards; downstream consumers can scrape from logs.
|
|
427
|
-
- Files: `admin-backend/src/adminApp.ts`, `admin-backend/src/actionRunner.ts`, `admin-backend/src/filterParser.ts`, `admin-backend/src/legacy.ts`
|
|
428
|
-
- Depends on: 2.4, 2.6, 2.8
|
|
429
|
-
- Acceptance: A `grep "level":"info","event":"admin.action"` over the log stream during the E2E run shows entries for every action invocation with the documented fields.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Removed from scope (per decisions)
|
|
261
|
+
|
|
262
|
+
- ~~`actionRunner.ts` / `POST .../actions/:name`~~ → use v2 `bulk-patch`
|
|
263
|
+
- ~~`AdminActionContext` / frozen action context~~ → not needed without custom action runners
|
|
264
|
+
- ~~Per-user `/admin/config` permission booleans~~ → static flags; see RBAC IP
|
|
265
|
+
- ~~`home.widgets` typed layout~~ → `home.slots` only
|