Problem
AUTH-GUEST-001 (issue #33) deliberately deferred guest-to-wallet migration -- when a guest connects a wallet, their practice history (orders/positions/risk limits/analytics) currently stays under the guest identity rather than merging into the newly-connected wallet identity. This issue tracks doing that migration safely.
Repository evidence
server/src/auth/users.ts's createGuestUser() and findOrCreateUser() are currently independent paths with no migration/merge logic between them. users.kind ('wallet' | 'guest') distinguishes the two but nothing transitions a row from one to the other.
Risk
P2 -- valuable for guest retention/conversion, not release-blocking. The real risk this issue exists to manage is data-integrity: an unsafe migration could duplicate orders, double-count P&L, or merge two unrelated accounts' data.
Scope
- Design and implement a transactional migration: when an authenticated guest connects and verifies a wallet, move (not copy) their orders/fills/positions/risk_limits rows to the wallet's
users.id, then either delete or permanently mark the guest row as migrated (never leave it independently usable again).
- Must be idempotent -- retrying a partially-failed migration must not duplicate rows.
- Must handle the case where the connecting wallet already has its own existing history (decide and document: reject the migration, or merge -- merging two non-empty histories is a real design decision, not a default).
- Add explicit tests for: successful migration, retry-after-partial-failure, migration-target-already-has-history, concurrent migration attempts (two requests racing to migrate the same guest).
Non-goals
- Not migrating guest identities between two different guest sessions.
- Not building a UI flow beyond what's needed to trigger the migration (e.g. a "Save your progress" prompt) -- that can be minimal.
Dependencies
AUTH-GUEST-001 (issue #33) and WALLET-001 (issue #32), both must be merged first.
Proposed implementation
A single DB transaction reassigning userId foreign keys across orders/fills/positions/risk_limits/any analytics tables, gated by an explicit confirmation step, with the guest row itself marked non-reusable afterward (e.g. a migratedTo column or immediate deletion once confirmed safe).
Acceptance criteria
A guest with real paper-trading history who then connects and verifies a wallet ends up with that same history now owned by the wallet identity, verified by direct DB/API inspection; no duplicate rows; the old guest session can no longer be used to access the migrated data.
Definition of done
Server tests cover every scenario in Scope above; reviewer PASS with explicit sign-off on the transactional-safety properties (idempotency, no duplication, no cross-account bleed).
Test plan
Migration success, idempotent retry, existing-history-on-target-wallet, concurrent-migration race, guest row becomes unusable post-migration.
Security review
This is the highest-risk part of the whole guest-session feature -- ownership/ID reassignment logic needs the same rigor as the existing cross-user ownership tests in paperEngine.test.ts, and then some (a bug here doesn't just leak data across users, it could silently corrupt financial history).
Accessibility review
Whatever UI trigger is added should be keyboard-accessible and clearly worded (this is an irreversible action once confirmed).
Observability requirements
Log every migration attempt/success/failure with both user IDs involved (never log wallet signatures or session tokens).
Performance considerations
Should be a single transaction, not N sequential round-trips per row type.
Rollback plan
Since this can move real (paper) trading history, a failed/rolled-back migration must leave the guest identity's data fully intact and usable, not partially moved.
Documentation requirements
Extend docs/architecture/wallet-and-identity.md's guest-session section.
Completion evidence
(added on merge)
Reviewer verdict
(pending)
Problem
AUTH-GUEST-001(issue #33) deliberately deferred guest-to-wallet migration -- when a guest connects a wallet, their practice history (orders/positions/risk limits/analytics) currently stays under the guest identity rather than merging into the newly-connected wallet identity. This issue tracks doing that migration safely.Repository evidence
server/src/auth/users.ts'screateGuestUser()andfindOrCreateUser()are currently independent paths with no migration/merge logic between them.users.kind('wallet' | 'guest') distinguishes the two but nothing transitions a row from one to the other.Risk
P2 -- valuable for guest retention/conversion, not release-blocking. The real risk this issue exists to manage is data-integrity: an unsafe migration could duplicate orders, double-count P&L, or merge two unrelated accounts' data.
Scope
users.id, then either delete or permanently mark the guest row as migrated (never leave it independently usable again).Non-goals
Dependencies
AUTH-GUEST-001(issue #33) andWALLET-001(issue #32), both must be merged first.Proposed implementation
A single DB transaction reassigning
userIdforeign keys acrossorders/fills/positions/risk_limits/any analytics tables, gated by an explicit confirmation step, with the guest row itself marked non-reusable afterward (e.g. amigratedTocolumn or immediate deletion once confirmed safe).Acceptance criteria
A guest with real paper-trading history who then connects and verifies a wallet ends up with that same history now owned by the wallet identity, verified by direct DB/API inspection; no duplicate rows; the old guest session can no longer be used to access the migrated data.
Definition of done
Server tests cover every scenario in Scope above; reviewer PASS with explicit sign-off on the transactional-safety properties (idempotency, no duplication, no cross-account bleed).
Test plan
Migration success, idempotent retry, existing-history-on-target-wallet, concurrent-migration race, guest row becomes unusable post-migration.
Security review
This is the highest-risk part of the whole guest-session feature -- ownership/ID reassignment logic needs the same rigor as the existing cross-user ownership tests in
paperEngine.test.ts, and then some (a bug here doesn't just leak data across users, it could silently corrupt financial history).Accessibility review
Whatever UI trigger is added should be keyboard-accessible and clearly worded (this is an irreversible action once confirmed).
Observability requirements
Log every migration attempt/success/failure with both user IDs involved (never log wallet signatures or session tokens).
Performance considerations
Should be a single transaction, not N sequential round-trips per row type.
Rollback plan
Since this can move real (paper) trading history, a failed/rolled-back migration must leave the guest identity's data fully intact and usable, not partially moved.
Documentation requirements
Extend
docs/architecture/wallet-and-identity.md's guest-session section.Completion evidence
(added on merge)
Reviewer verdict
(pending)