Skip to content

feat: support parent and wallet profiles#15

Merged
KazanderDad merged 3 commits intomainfrom
codex/update-frontend-for-multiple-wallet-profiles
Nov 11, 2025
Merged

feat: support parent and wallet profiles#15
KazanderDad merged 3 commits intomainfrom
codex/update-frontend-for-multiple-wallet-profiles

Conversation

@KazanderDad
Copy link
Member

Summary

  • add the parent/wallet identity schema migration with RPC helpers and policies
  • update the frontend store, profile services, and pages to manage wallet-scoped profiles
  • realign the vitest suite with the new profile API and add coverage for wallet flows

Testing

  • pnpm --filter frontend lint
  • pnpm --filter frontend test
  • pnpm --filter frontend build

Codex Task

Copilot AI review requested due to automatic review settings November 10, 2025 16:38
@vercel
Copy link

vercel bot commented Nov 10, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
peer-mapper-frontend Ready Ready Preview Comment Nov 11, 2025 5:54pm

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR rebuilds the identity schema to support a parent profile (email-based) with multiple wallet profiles (one per connected wallet). The migration adds new database tables for profiles, credentials, and Cubid assignments with appropriate RLS policies. The frontend refactors from a single user profile model to a parent/wallet profile architecture with active wallet selection.

Key changes:

  • New database schema with profiles, profile_credentials, and profiles_cubid tables
  • Frontend state management updated to track parent profile, wallet profiles array, and active wallet
  • All UI components and pages updated to work with the new multi-profile model

Reviewed Changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
supabase/migrations/20251110000100_rebuild_identity_schema_from_scratch.sql Defines new identity schema with parent/wallet profiles, credentials, Cubid timeline, views, RLS policies, and rollback logic
frontend/src/lib/store.ts Replaces single user profile with parent profile, wallet profiles array, active wallet ID, and address normalization
frontend/src/lib/profile.ts Adds functions to fetch profile bundles, create wallet profiles, and update wallet details
frontend/src/lib/onboarding.ts Updates onboarding checks to validate wallet profiles instead of single user
frontend/src/components/UserSessionSummary.tsx Displays active wallet profile info with fallback for empty wallet list
frontend/src/components/AuthProvider.tsx Fetches and sets parent and wallet profiles on auth state changes
frontend/src/components/AppHeader.tsx Shows active wallet profile display name and photo
frontend/src/app/vouch/page.tsx Uses active wallet profile address for vouching
frontend/src/app/signin/page.tsx Checks wallet profiles for onboarding completion
frontend/src/app/scan/my-qr/page.tsx Generates QR with active wallet profile's Cubid ID
frontend/src/app/scan/camera/page.tsx Uses active wallet profile for handshake completion
frontend/src/app/profile/page.tsx Displays linked wallets grid and form to create new wallet profiles
frontend/src/app/page.tsx Shows active wallet profile name on home page
frontend/src/app/new-user/page.tsx Creates wallet profile during onboarding instead of updating user
frontend/src/app/circle/page.tsx Fetches circle data using active wallet address
frontend/tests/*.test.tsx Updates test fixtures to use new profile structure
frontend/tests/profile.test.ts Rewrites tests for new profile service functions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return null;

const createdRow = Array.isArray(created) ? created[0] : created;
const profileId: string | undefined = createdRow?.id ?? createdRow?.profile_id;
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code attempts to handle both id and profile_id fields from the RPC response, but the SQL function create_profile_with_credential returns public.profiles type which only has an id field. The fallback to profile_id appears unnecessary and could cause confusion. Consider removing createdRow?.profile_id from line 149.

Suggested change
const profileId: string | undefined = createdRow?.id ?? createdRow?.profile_id;
const profileId: string | undefined = createdRow?.id;

Copilot uses AI. Check for mistakes.
setParentProfile: (profile) =>
set((state) => ({
parentProfile: profile,
// Preserve active wallet when clearing parent profile
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states 'Preserve active wallet when clearing parent profile' but the code actually clears the active wallet when the parent profile is null. The comment should read 'Clear active wallet when clearing parent profile' to match the implementation.

Suggested change
// Preserve active wallet when clearing parent profile
// Clear active wallet when clearing parent profile

Copilot uses AI. Check for mistakes.
setError("Cubid ID must match cubid_[a-z0-9]{4,32}");
return;
}
if (!walletProfiles.length && !walletAddress) {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition checks both !walletProfiles.length AND !walletAddress, but a user could have a connected wallet (walletAddress is set) without a saved profile yet. This would allow submission before the profile is actually created. The condition should be if (!walletProfiles.length) to ensure at least one wallet profile exists in the database.

Suggested change
if (!walletProfiles.length && !walletAddress) {
if (!walletProfiles.length) {

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 33
if (!isMounted) return;
setSession(session);
if (session) {
const profile = await fetchMyProfile();
const bundle = await fetchMyProfiles();
if (!isMounted) return;
setUser(profile);
setParentProfile(bundle.parent);
setWalletProfiles(bundle.wallets);
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The session is set before checking if the component is still mounted after the async fetchMyProfiles() call. If the component unmounts between setting the session and fetching profiles, the session will be set but profiles won't be. Consider moving setSession(session) after the mounted check on line 31, or wrapping all state updates in a single check.

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 51 to 66
setSession(session);
if (session) {
try {
const profile = await fetchMyProfile();
setUser(profile);
const bundle = await fetchMyProfiles();
setParentProfile(bundle.parent);
setWalletProfiles(bundle.wallets);
} catch (error) {
console.error("Failed to fetch Supabase profile", error);
setUser(null);
console.error("Failed to fetch Supabase profiles", error);
setParentProfile(null);
setWalletProfiles([]);
}
} else {
setUser(null);
setParentProfile(null);
setWalletProfiles([]);
}
setInitialised(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Clear wallet state on sign‑out

When the session is cleared, the provider only nulls the parent and wallet profile lists but leaves walletAddress untouched in the zustand store. Because setWalletProfiles([]) does not modify walletAddress, the previously connected wallet persists after logout and across subsequent logins. This stale address lets a fresh account skip the wallet-connection portion of onboarding (the New User page treats a non‑empty walletAddress as already connected) and can display or reuse the wrong wallet for the next user. The sign‑out paths should also call reset() or setWalletAddress(null) to avoid leaking wallet state between sessions.

Useful? React with 👍 / 👎.

@KazanderDad KazanderDad merged commit 79b19b7 into main Nov 11, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant