diff --git a/apps/api/src/lib/helpers.ts b/apps/api/src/lib/helpers.ts index b3ecac7..660adea 100644 --- a/apps/api/src/lib/helpers.ts +++ b/apps/api/src/lib/helpers.ts @@ -83,6 +83,37 @@ export async function createHouseholdWithDefaults( return { id: household!.id, name: household!.name }; } +/** När en användare går med i ett annat hushåll: ta bort deras auto-skapade + * sol-hushåll (enda ägaren, inget lager) så det delade blir aktivt. */ +export async function discardEmptySoloHouseholds( + db: Database, + userId: string, + keepHouseholdId: string, +): Promise { + const memberships = await db + .select({ + householdId: schema.householdMembers.householdId, + role: schema.householdMembers.role, + }) + .from(schema.householdMembers) + .where(eq(schema.householdMembers.userId, userId)); + for (const m of memberships) { + if (m.householdId === keepHouseholdId || m.role !== "owner") continue; + const members = await db + .select({ userId: schema.householdMembers.userId }) + .from(schema.householdMembers) + .where(eq(schema.householdMembers.householdId, m.householdId)); + if (members.length !== 1) continue; // inte ensam medlem → rör inte + const [inv] = await db + .select({ id: schema.inventoryItems.id }) + .from(schema.inventoryItems) + .where(eq(schema.inventoryItems.householdId, m.householdId)) + .limit(1); + if (inv) continue; // har lager → rör inte + await db.delete(schema.households).where(eq(schema.households.id, m.householdId)); // cascade städar medlem + platser + } +} + /** Hämta användarens aktiva hushåll (första medlemskapet) eller null. */ export async function getActiveHouseholdId(db: Database, userId: string): Promise { const [member] = await db diff --git a/apps/api/src/routes/households.ts b/apps/api/src/routes/households.ts index f572c34..b349fe2 100644 --- a/apps/api/src/routes/households.ts +++ b/apps/api/src/routes/households.ts @@ -16,6 +16,7 @@ import { errors, parse } from "../lib/errors.js"; import { audit, createHouseholdWithDefaults, + discardEmptySoloHouseholds, emitEvent, generateInviteCode, requireMembership, @@ -142,6 +143,8 @@ export async function householdRoutes(app: FastifyInstance) { .values({ householdId: household.id, userId: req.userId, role: "adult" }) .onConflictDoNothing(); + await discardEmptySoloHouseholds(app.db, req.userId, household.id); + await emitEvent(app.db, { type: "HOUSEHOLD_MEMBER_ADDED", payload: { householdId: household.id, newUserId: req.userId, role: "adult" }, diff --git a/apps/api/src/routes/onboarding.ts b/apps/api/src/routes/onboarding.ts index 3920453..96f7825 100644 --- a/apps/api/src/routes/onboarding.ts +++ b/apps/api/src/routes/onboarding.ts @@ -4,7 +4,12 @@ import { z } from "zod"; import { schema } from "@app/database"; import { quickStartInputSchema, onboardingInputSchema } from "@app/validation"; import { errors, parse } from "../lib/errors.js"; -import { audit, createHouseholdWithDefaults, getActiveHouseholdId } from "../lib/helpers.js"; +import { + audit, + createHouseholdWithDefaults, + discardEmptySoloHouseholds, + getActiveHouseholdId, +} from "../lib/helpers.js"; import { t } from "../lib/i18n.js"; import { KNOWN_FLAGS } from "@app/feature-flags"; @@ -171,6 +176,7 @@ export async function onboardingRoutes(app: FastifyInstance) { .insert(schema.householdMembers) .values({ householdId: household.id, userId: req.userId, role: "adult" }) .onConflictDoNothing(); + await discardEmptySoloHouseholds(app.db, req.userId, household.id); householdId = household.id; }