--- phase: 02-household-creation plan: 02 type: execute wave: 1 depends_on: [] files_modified: - lib/features/household/data/datasources/household_remote_datasource.dart - lib/features/household/domain/repositories/household_repository.dart - lib/features/household/data/repositories/household_repository_impl.dart - lib/features/household/domain/models/household_models.dart - lib/features/household/domain/entities/household_entity.dart autonomous: true must_haves: truths: - "Supabase database schema supports households, members, and invite codes with proper relationships" - "Row-Level Security policies isolate household data at database layer" - "Database constraints prevent duplicate members and invalid invite codes" - "Realtime subscriptions enable household member sync" artifacts: - path: "supabase/migrations/001_create_household_tables.sql" provides: "Database schema for household functionality" contains: "CREATE TABLE households", "CREATE TABLE household_members", "CREATE TABLE invite_codes" - path: "supabase/migrations/002_household_rls_policies.sql" provides: "Row-Level Security policies for household data isolation" contains: "CREATE POLICY", "ROW LEVEL SECURITY" - path: "supabase/migrations/003_household_indexes.sql" provides: "Performance indexes for household queries" contains: "CREATE INDEX", "household_id", "user_id" key_links: - from: "lib/features/household/data/repositories/household_repository_impl.dart" to: "supabase/migrations/001_create_household_tables.sql" via: "table operations" pattern: "from.*households" - from: "supabase/migrations/002_household_rls_policies.sql" to: "supabase/migrations/001_create_household_tables.sql" via: "security policies" pattern: "POLICY.*FOR.*households" --- Create Supabase database schema with proper household isolation, member relationships, and invite code management. Purpose: Establish database foundation that enforces multi-tenant security and supports real-time household synchronization requirements. Output: Complete database schema with tables, RLS policies, and indexes for household operations. @~/.opencode/get-shit-done/workflows/execute-plan.md @~/.opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/research/ARCHITECTURE.md # Database Architecture References @lib/features/authentication/data/repositories/auth_repository_impl.dart Create Household Tables Migration supabase/migrations/001_create_household_tables.sql Create database schema for household functionality: 1. households table: ```sql CREATE TABLE households ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, name TEXT NOT NULL CHECK (length(name) >= 1 AND length(name) <= 100), created_by UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now() NOT NULL, updated_at TIMESTAMPTZ DEFAULT now() NOT NULL ); CREATE TRIGGER households_updated_at BEFORE UPDATE ON households FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); ``` 2. household_members table: ```sql CREATE TABLE household_members ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, household_id UUID NOT NULL REFERENCES households(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, role TEXT NOT NULL CHECK (role IN ('owner', 'editor', 'viewer')), joined_at TIMESTAMPTZ DEFAULT now() NOT NULL, UNIQUE(household_id, user_id) ); ``` 3. invite_codes table: ```sql CREATE TABLE invite_codes ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, household_id UUID NOT NULL REFERENCES households(id) ON DELETE CASCADE, code TEXT NOT NULL UNIQUE CHECK (length(code) = 8), created_by UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now() NOT NULL, expires_at TIMESTAMPTZ NOT NULL, used_by UUID REFERENCES auth.users(id) ON DELETE SET NULL, used_at TIMESTAMPTZ, CONSTRAINT valid_invite_code CHECK ( (used_by IS NULL AND used_at IS NULL) OR (used_by IS NOT NULL AND used_at IS NOT NULL) ) ); ``` Follow Supabase migration patterns and include proper constraints. supabase db push --dry-run shows valid SQL syntax Household tables created with proper relationships and constraints Create Household RLS Policies supabase/migrations/002_household_rls_policies.sql Create Row-Level Security policies for household data isolation: 1. Enable RLS on all household tables: ```sql ALTER TABLE households ENABLE ROW LEVEL SECURITY; ALTER TABLE household_members ENABLE ROW LEVEL SECURITY; ALTER TABLE invite_codes ENABLE ROW LEVEL SECURITY; ``` 2. households table policies: ```sql -- Users can view households they belong to CREATE POLICY "Users can view their households" ON households FOR SELECT USING ( id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() ) ); -- Users can insert households (will be owner via member insertion) CREATE POLICY "Users can create households" ON households FOR INSERT WITH CHECK (created_by = auth.uid()); -- Only household owners can update households CREATE POLICY "Owners can update households" ON households FOR UPDATE USING ( id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() AND role = 'owner' ) ); ``` 3. household_members table policies: ```sql -- Users can view members of their households CREATE POLICY "Users can view household members" ON household_members FOR SELECT USING ( household_id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() ) ); -- Users can insert themselves as members (via join flow) CREATE POLICY "Users can join households" ON household_members FOR INSERT WITH CHECK (user_id = auth.uid()); -- Only owners can manage member roles and remove members CREATE POLICY "Owners can manage members" ON household_members FOR UPDATE USING ( household_id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() AND role = 'owner' ) ); -- Only owners can remove members (except themselves if last owner handled in app logic) CREATE POLICY "Owners can remove members" ON household_members FOR DELETE USING ( household_id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() AND role = 'owner' ) ); ``` 4. invite_codes table policies: ```sql -- Users can view invite codes for their households CREATE POLICY "Users can view household invite codes" ON invite_codes FOR SELECT USING ( household_id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() ) ); -- Only owners can create invite codes CREATE POLICY "Owners can create invite codes" ON invite_codes FOR INSERT WITH CHECK ( created_by = auth.uid() AND household_id IN ( SELECT household_id FROM household_members WHERE user_id = auth.uid() AND role = 'owner' ) ); -- Only owners can revoke invite codes CREATE POLICY "Owners can revoke invite codes" ON invite_codes FOR DELETE USING ( created_by = auth.uid() ); ``` Ensure policies enforce multi-tenant isolation at database layer. supabase db push --dry-run shows valid RLS policies Row-Level Security policies enforce household data isolation with proper role-based access Create Household Performance Indexes supabase/migrations/003_household_indexes.sql Create performance indexes for household operations: 1. households table indexes: ```sql -- For finding households by creator CREATE INDEX idx_households_created_by ON households(created_by); -- For household sorting by creation date CREATE INDEX idx_households_created_at ON households(created_at); ``` 2. household_members table indexes: ```sql -- For finding user's households (primary query) CREATE INDEX idx_household_members_user_id ON household_members(user_id); -- For finding household members (primary query) CREATE INDEX idx_household_members_household_id ON household_members(household_id); -- Composite index for member role queries CREATE INDEX idx_household_members_household_role ON household_members(household_id, role); -- For checking if user is member of household CREATE UNIQUE INDEX idx_household_members_unique ON household_members(household_id, user_id); ``` 3. invite_codes table indexes: ```sql -- For invite code lookup (primary query) CREATE UNIQUE INDEX idx_invite_codes_code ON invite_codes(code); -- For finding household's active invites CREATE INDEX idx_invite_codes_household_id ON invite_codes(household_id); -- For cleaning expired invites CREATE INDEX idx_invite_codes_expires_at ON invite_codes(expires_at); -- For finding unused invites CREATE INDEX idx_invite_codes_unused ON invite_codes(used_by) WHERE used_by IS NULL; ``` 4. Realtime function for household changes: ```sql -- Function to broadcast household member changes CREATE OR REPLACE FUNCTION broadcast_household_change() RETURNS TRIGGER AS $$ BEGIN -- This will be used by Supabase Realtime RETURN NEW; END; $$ LANGUAGE plpgsql; -- Trigger for household member changes CREATE TRIGGER household_members_broadcast AFTER INSERT OR UPDATE OR DELETE ON household_members FOR EACH ROW EXECUTE FUNCTION broadcast_household_change(); ``` Include indexes that support the most common household queries and real-time sync. supabase db push --dry-run shows valid index creation Performance indexes optimize household queries and support real-time synchronization Create Household Database Functions supabase/migrations/004_household_functions.sql Create database functions for household operations: 1. Generate unique invite code function: ```sql CREATE OR REPLACE FUNCTION generate_invite_code() RETURNS TEXT AS $$ DECLARE new_code TEXT; code_exists BOOLEAN; BEGIN LOOP -- Generate 8-character alphanumeric code new_code := upper(substring(encode(gen_random_bytes(4), 'hex'), 1, 8)); -- Check for collision SELECT EXISTS(SELECT 1 FROM invite_codes WHERE code = new_code AND used_by IS NULL) INTO code_exists; EXIT WHEN NOT code_exists; END LOOP; RETURN new_code; END; $$ LANGUAGE plpgsql; ``` 2. Get user's households with member info: ```sql CREATE OR REPLACE FUNCTION get_user_households(user_uuid UUID) RETURNS TABLE ( household_id UUID, household_name TEXT, user_role TEXT, member_count BIGINT, created_at TIMESTAMPTZ ) AS $$ BEGIN RETURN QUERY SELECT h.id, h.name, hm.role, (SELECT COUNT(*) FROM household_members WHERE household_id = h.id), h.created_at FROM households h JOIN household_members hm ON h.id = hm.household_id WHERE hm.user_id = user_uuid ORDER BY h.created_at DESC; END; $$ LANGUAGE plpgsql SECURITY DEFINER; ``` 3. Validate and consume invite code: ```sql CREATE OR REPLACE FUNCTION join_household_by_code( invite_code TEXT, user_uuid UUID ) RETURNS TABLE ( success BOOLEAN, household_id UUID, household_name TEXT, error_message TEXT ) AS $$ DECLARE invite_record RECORD; household_record RECORD; is_already_member BOOLEAN; BEGIN -- Find valid invite code SELECT ic.*, h.name as household_name INTO invite_record FROM invite_codes ic JOIN households h ON ic.household_id = h.id WHERE ic.code = upper(invite_code) AND ic.used_by IS NULL AND ic.expires_at > now(); IF NOT FOUND THEN RETURN QUERY SELECT false, NULL::UUID, NULL::TEXT, 'Invalid or expired invite code'::TEXT; RETURN; END IF; -- Check if already member SELECT EXISTS( SELECT 1 FROM household_members WHERE household_id = invite_record.household_id AND user_id = user_uuid ) INTO is_already_member; IF is_already_member THEN RETURN QUERY SELECT false, NULL::UUID, NULL::TEXT, 'Already a member of this household'::TEXT; RETURN; END IF; -- Add as member with editor role INSERT INTO household_members (household_id, user_id, role) VALUES (invite_record.household_id, user_uuid, 'editor'); -- Mark invite as used UPDATE invite_codes SET used_by = user_uuid, used_at = now() WHERE id = invite_record.id; -- Get household info SELECT id, name INTO household_record FROM households WHERE id = invite_record.household_id; RETURN QUERY SELECT true, household_record.id, household_record.name, NULL::TEXT; END; $$ LANGUAGE plpgsql SECURITY DEFINER; ``` Include proper SECURITY DEFINER settings and error handling. supabase db push --dry-run shows valid function creation Database functions provide efficient household operations with proper security 1. Database schema supports all household operations from SHARE-01 through SHARE-05 2. RLS policies enforce multi-tenant isolation at database layer 3. Performance indexes optimize common household queries 4. Database functions provide efficient invite code generation and validation 5. Realtime triggers support household member synchronization Supabase database schema is complete with household tables, security policies, indexes, and functions ready for application integration. After completion, create `.planning/phases/02-household-creation/02-02-SUMMARY.md` with database schema implementation summary