mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
docs(plans): Phase 1 audit — space-scoped migration
Audit of every Dexie table in apps/mana/apps/web/src/lib/data/database.ts + crypto registry finds no blockers for Phase 2, with two scope adjustments to fold in: 1. Add agentKontextDocs (v22) to the to-migrate list. Per-agent context docs reference the aiAgents table; migration order must be agents first, then backfill agentKontextDocs.spaceId via parent-agent lookup. 2. The 46 already-space-scoped tables from the Spaces-Foundation sprint all still carry userId alongside spaceId. To hit the "no table has both userId and spaceId" invariant, Phase 2 extends from just the 7 newly-migrated tables to a ~53-table sweep dropping userId everywhere. Mechanically identical per table, so the extra scope is cheap. Also confirmed: - All 19 junction tables have space-scoped parents — no dangling refs. Safe to migrate parents. - Actor columns (__lastActor / __fieldActors) stamped everywhere by the Dexie creating hook — userId can be dropped confidently. - userContext (v23 profile hub) is distinct from kontextDoc (AI planner injection). userContext stays user-level; kontextDoc moves per-Space. No collision. - 10 user-level singleton tables correctly identified to stay user-level (userSettings, newsPreferences, meditateSettings, …). - 10 internal/infra tables (_pendingChanges, _events, _aiDebugLog, …) get per-table treatment; mostly no spaceId needed. Phase 2 can proceed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
129971ffc3
commit
9db044178c
1 changed files with 118 additions and 4 deletions
|
|
@ -60,15 +60,28 @@ them):
|
|||
|
||||
### In scope (become Space-scoped)
|
||||
|
||||
Confirmed by Phase 1 audit (see appendix at bottom of this doc):
|
||||
|
||||
- `globalTags` + `tagGroups` — add `spaceId`, drop `userId`, encrypt
|
||||
`name` + `icon`.
|
||||
- `workbenchScenes` — add `spaceId`. Layout + `scopeTagIds` stay.
|
||||
Encrypt `title`.
|
||||
- `aiAgents` — add `spaceId`. Bootstrap runs per Space.
|
||||
- `aiMissions` — add `spaceId`. Follows agents.
|
||||
- `kontextDoc` (the planner-injected user bio singleton) — becomes
|
||||
per-Space: each Space has at most one `kontextDoc`. Keyed off
|
||||
`[spaceId, type: 'kontextDoc']`.
|
||||
- Anything else Phase 1's audit turns up.
|
||||
- `kontextDoc` — reshape from user-level singleton to per-Space
|
||||
(one per Space, keyed `[spaceId, type: 'kontextDoc']`).
|
||||
- `agentKontextDocs` (v22, per-agent context docs — added by audit)
|
||||
— add `spaceId` via agent FK lookup. Ordered: migrate `aiAgents`
|
||||
first, then backfill `agentKontextDocs.spaceId` from the parent.
|
||||
|
||||
### Also in scope: drop `userId` across all already-migrated tables
|
||||
|
||||
The Phase 1 audit found that **all 46 previously-migrated
|
||||
space-scoped tables still carry `userId`** (redundant with Actor
|
||||
attribution). To satisfy the "no table has both `userId` and
|
||||
`spaceId`" invariant, Phase 2 drops `userId` from every data-record
|
||||
table, not just the 7 newly-migrated ones. This is a ~53-table
|
||||
sweep, mechanically identical per table, so the work scales cheaply.
|
||||
|
||||
### Stays user-level (identity / preferences)
|
||||
|
||||
|
|
@ -445,3 +458,104 @@ and the `userId` → Actor attribution cleanup).
|
|||
- **Deprecated** by this doc:
|
||||
[`per-space-vs-user-global-tags.md`](./per-space-vs-user-global-tags.md)
|
||||
— delete in Phase 8.
|
||||
|
||||
---
|
||||
|
||||
## Appendix — Phase 1 audit results (2026-04-22)
|
||||
|
||||
Source: full audit of `apps/mana/apps/web/src/lib/data/database.ts`,
|
||||
`crypto/registry.ts`, `crypto/plaintext-allowlist.ts`. Conclusion:
|
||||
**no surprises that block Phase 2**, with the two scope adjustments
|
||||
already folded into the In-scope section above.
|
||||
|
||||
### To-migrate (7 tables)
|
||||
|
||||
| Table | Current columns | Needs Actor? | Notes |
|
||||
|---|---|---|---|
|
||||
| `globalTags` | id, name, groupId, color, icon, sortOrder, **userId**, NO spaceId | ✗ — stamping needed | Add `spaceId`. Drop `userId`. Encrypt `name` + `icon`. |
|
||||
| `tagGroups` | id, name, color, **userId**, NO spaceId | ✗ — stamping needed | Add `spaceId`. Drop `userId`. Encrypt `name`. |
|
||||
| `workbenchScenes` | id, title, layout, scopeTagIds?, order, **userId**, NO spaceId | ✗ — stamping needed | Add `spaceId`. Drop `userId`. Encrypt `title`. |
|
||||
| `aiAgents` | id, name, state, systemPrompt🔒, memory🔒, **userId**, NO spaceId | ✗ — stamping needed | Add `spaceId`. Drop `userId`. Name stays plaintext (display key). |
|
||||
| `aiMissions` | id, state, createdAt, nextRunAt, **userId**, NO spaceId | ✗ — stamping needed | Add `spaceId`. Drop `userId`. |
|
||||
| `kontextDoc` | id (singleton), content🔒 | ✗ — stamping needed | **Reshape**: `[spaceId, type: 'kontextDoc']` PK. Pre-migration singleton becomes Personal-Space's kontextDoc. Other Spaces start without one. |
|
||||
| `agentKontextDocs` | id, agentId, content🔒, NO spaceId | ✗ — stamping needed | Added by audit. Backfill `spaceId` via parent-agent lookup. Not in original plan. |
|
||||
|
||||
Legend: 🔒 = already encrypted in crypto registry.
|
||||
|
||||
### Already space-scoped (46 tables) — userId cleanup sweep
|
||||
|
||||
All 46 tables migrated during the Spaces-Foundation sprint carry
|
||||
**both** `spaceId` and `userId`. Phase 2 drops the redundant
|
||||
`userId` — the migration helper runs over every table in this set
|
||||
mechanically.
|
||||
|
||||
Sample (full list derived at implementation time from the Dexie
|
||||
schema registry): `tasks`, `events`, `notes`, `contacts`,
|
||||
`conversations`, `documents`, `dreams`, `memos`, `meditations`,
|
||||
`images`, `files`, `skills`, `plants`, `songs`, `ccLocations`,
|
||||
`places`, `presiDecks`, `cardDecks`, `articles` (v33), …
|
||||
|
||||
The creating-hook in `database.ts` is updated to stop stamping
|
||||
`userId` on these tables (Phase 2). Attribution reads from
|
||||
`__lastActor` everywhere.
|
||||
|
||||
### User-level (10 existing + 1 new) — NO change
|
||||
|
||||
| Table | Purpose |
|
||||
|---|---|
|
||||
| `userSettings` | user-wide UI defaults (theme, locale) |
|
||||
| `userContext` | profile hub (about, interests, routine, goals, social) |
|
||||
| `newsPreferences` | feed subscriptions + learned weights |
|
||||
| `meditateSettings` | meditation prefs |
|
||||
| `sleepSettings` | sleep-tracking prefs |
|
||||
| `moodSettings` | mood-logging prefs |
|
||||
| `timeSettings` | time-tracking prefs |
|
||||
| `invoiceSettings` | sender profile (legal address, IBAN) |
|
||||
| `broadcastSettings` | newsletter sender defaults |
|
||||
| `wetterSettings` | weather prefs |
|
||||
| `userTagPresets` *(new in Phase 2)* | user-level templates for Space-seeding |
|
||||
|
||||
`userContext` is **not** the same as `kontextDoc` — the former is
|
||||
the user's profile hub (identity-level bio/interests), the latter
|
||||
is the AI-planner-injected context (moves per-Space). They serve
|
||||
different roles. No collision.
|
||||
|
||||
### Junction tables (19) — all parents space-scoped ✓
|
||||
|
||||
No dangling references. Every junction inherits `spaceId` from its
|
||||
parent once parents are migrated.
|
||||
|
||||
`taskLabels` · `eventTags` · `contactTags` · `conversationTags` ·
|
||||
`documentTags` · `imageTags` · `fileTags` · `photoMediaTags` ·
|
||||
`memoTags` · `mealTags` · `plantTags` · `songTags` · `skillTags` ·
|
||||
`ccLocationTags` · `placeTags` · `presiDeckTags` · `deckTags` ·
|
||||
`articleTags` · `noteTags` · `timeBlockTags`
|
||||
|
||||
(`taskLabels` points at `globalTags` — after `globalTags` gets
|
||||
`spaceId`, the junction's `[taskId+labelId]` pair is implicitly
|
||||
within-Space via the parent task's spaceId.)
|
||||
|
||||
### Internal / infrastructure (10) — special handling
|
||||
|
||||
| Table | Handling |
|
||||
|---|---|
|
||||
| `_pendingChanges` | Add `spaceId` column from pending-change payload so sync routes know the partition. |
|
||||
| `_syncMeta` | Infra-level; no spaceId. |
|
||||
| `_activity` | Deprecated, superseded by `_events`. Leave read-only. |
|
||||
| `_events` | Local-only domain event store. Event metadata already carries `appId` + `recordId`; no spaceId needed at event layer (materialized downstream). |
|
||||
| `_eventsTombstones` | Sync tombstones; no spaceId (appId+collection+recordId sufficient). |
|
||||
| `_memory`, `_nudgeOutcomes` | Companion-brain local memory; never synced. No spaceId. |
|
||||
| `_byokKeys` | BYOK master-key storage. Device-local, encrypted. User-level by nature. |
|
||||
| `_aiDebugLog` | Per-iteration LLM debug capture. Capped. **Never synced** (leaks decrypted content). No spaceId. |
|
||||
| `_streakState` | Companion engagement tracker. Local-only. |
|
||||
| `_serverIterationExecutions` | Idempotency marker for server-source AI iterations. Local-only. |
|
||||
|
||||
### Scope summary
|
||||
|
||||
- **To-migrate**: 7 tables (add `spaceId` + drop `userId` + encrypt as noted)
|
||||
- **userId sweep**: 46 already-space-scoped tables (drop `userId` only)
|
||||
- **User-level**: 10 existing + 1 new (`userTagPresets`) — no change to these
|
||||
- **Junctions**: 19 — all parents space-scoped, no action needed
|
||||
- **Internal/infra**: 10 — handled per table-type, mostly no action
|
||||
|
||||
**No blockers.** Phase 2 can proceed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue