Summary
Automatically convert existing client-side project groups (stored in localStorage under t3code:ui-state:v1) to server-persisted Client entities on first run after upgrade.
Scope
- On app startup, detect: localStorage has
projectGroups data AND read model has zero Clients
- For each
ProjectGroup in localStorage: dispatch client.create with the group's name
- For each entry in
projectGroupIdByCwd: resolve the Project by matching workspaceRoot to the cwd key, then dispatch project.client.assign
- Preserve group ordering via
client.reorder commands matching projectGroupOrder
- Set
t3code:migration:groups-to-clients flag in localStorage to prevent re-migration
- Retain original group data for 30 days as rollback safety
Technical notes
- Groups are keyed by filesystem
cwd, not ProjectId. Path matching must normalize: strip trailing slashes, resolve symlinks where possible, handle case sensitivity
- Use deterministic
CommandId values derived from group IDs (e.g., uuid5(groupId)) for idempotency
- Handle partial migration (app crash mid-way): on next startup, detect some Clients exist but flag not set → replay only missing assignments
- Skip silently if a
cwd matches no existing Project (log a warning)
- Deduplicate group names with numeric suffix if needed
Key files to modify
apps/web/src/routes/__root.tsx — trigger migration check after snapshot sync
apps/web/src/uiStateStore.ts — read existing group data, set migration flag
- New file:
apps/web/src/migrations/groupsToClients.ts — migration logic
Dependencies
- F1 (Client CRUD), F2 (Client-Project binding)
Acceptance criteria
Summary
Automatically convert existing client-side project groups (stored in localStorage under
t3code:ui-state:v1) to server-persisted Client entities on first run after upgrade.Scope
projectGroupsdata AND read model has zero ClientsProjectGroupin localStorage: dispatchclient.createwith the group's nameprojectGroupIdByCwd: resolve the Project by matchingworkspaceRootto the cwd key, then dispatchproject.client.assignclient.reordercommands matchingprojectGroupOrdert3code:migration:groups-to-clientsflag in localStorage to prevent re-migrationTechnical notes
cwd, notProjectId. Path matching must normalize: strip trailing slashes, resolve symlinks where possible, handle case sensitivityCommandIdvalues derived from group IDs (e.g.,uuid5(groupId)) for idempotencycwdmatches no existing Project (log a warning)Key files to modify
apps/web/src/routes/__root.tsx— trigger migration check after snapshot syncapps/web/src/uiStateStore.ts— read existing group data, set migration flagapps/web/src/migrations/groupsToClients.ts— migration logicDependencies
Acceptance criteria