diff --git a/CLAUDE.md b/CLAUDE.md index c4d9d80..2632325 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -499,6 +499,50 @@ export async function submitOrderToXAPI(payload: XAPIOrderPayload) { ## Role-based Product Visibility Patterns (MVP) +### Auto-Assignment of 'private' Role (MVP) + +**Requirement**: All users must have at least one role to see products. New users automatically receive the `private` role on first login. + +**Implementation** in `server/api/auth/login.post.ts`: + +```typescript +if (!user) { + // First time login - create user profile + const [newUser] = await db.insert(users).values({ + experimentaId: cidaasUser.sub, + email: cidaasUser.email, + firstName: cidaasUser.given_name || '', + lastName: cidaasUser.family_name || '', + }).returning() + + user = newUser + + // Auto-assign 'private' role on first login + await assignRoleToUser(newUser.id, 'private', { + adminNotes: 'Auto-assigned on first login', + }) +} else { + // Update last login timestamp + await db.update(users) + .set({ updatedAt: new Date() }) + .where(eq(users.id, user.id)) + + // Safety check: If existing user has no roles, assign 'private' role + const userRoleCodes = await getUserApprovedRoleCodes(user.id) + if (userRoleCodes.length === 0) { + await assignRoleToUser(user.id, 'private', { + adminNotes: 'Auto-assigned for existing user without roles', + }) + } +} +``` + +**Key Points:** +- ✅ New users → `private` role automatically assigned +- ✅ Existing users without roles → `private` role assigned (safety check) +- ✅ Status always `approved` (no approval workflow in MVP) +- ✅ Admin notes track auto-assignment source + ### Role-based Filtering Pattern ```typescript diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index ab5904a..393584d 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1544,6 +1544,11 @@ try { - **user_roles**: Many-to-Many User ↔ Rollen mit Antrags-Workflow (vorbereitet für Phase 2/3) - **product_role_visibility**: Many-to-Many Produkt ↔ Rollen (Sichtbarkeitssteuerung) +**Automatische Rollen-Zuweisung (MVP):** +- Neue User erhalten bei erster Anmeldung automatisch die Rolle `private` (Status: `approved`) +- Implementierung in `server/api/auth/login.post.ts` nach User-Profile-Erstellung +- Safety-Check: Bestehende User ohne Rollen erhalten ebenfalls `private` Rolle + **Opt-in Sichtbarkeit:** - Produkte OHNE `product_role_visibility` Einträge sind für NIEMANDEN sichtbar - Produkte MIT Einträgen sind nur für User mit passender `approved` Rolle sichtbar diff --git a/docs/PRD.md b/docs/PRD.md index 90236b5..d36c451 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -143,10 +143,14 @@ Das System nutzt ein rollenbasiertes Modell zur Steuerung der Produktsichtbarkei #### 3.3.3 Rollenzuweisung (MVP) +**Automatische Rollen-Zuweisung (MVP):** +- Neue User erhalten bei erster Anmeldung automatisch die Rolle `private` (Status: `approved`) +- Implementierung in `server/api/auth/login.post.ts` +- Falls ein bestehender User keine Rolle hat (z.B. Legacy-Daten), wird ebenfalls `private` zugewiesen + **Manuelle Zuweisung via Datenbank:** -- Rollen werden manuell via Drizzle Studio zugewiesen +- Weitere Rollen werden manuell via Drizzle Studio zugewiesen - Status immer `approved` (keine Anträge im MVP) -- Standard: Neue User erhalten automatisch Rolle `private` **Automatische Produkt-Rollen-Zuweisung (ERP-Import):** @@ -202,6 +206,7 @@ Beim Import von Produkten aus dem NAV ERP werden Rollen basierend auf der Katego - Bestätigungs-E-Mail wird von Cidaas versendet - E-Mail muss bestätigt werden bevor Login möglich ist - Nach erster Anmeldung wird User-Profil in lokaler DB angelegt (über OAuth2 Callback) +- **Automatische Rollen-Zuweisung**: Bei Erstellung des User-Profils wird automatisch die Rolle "Privatperson" (`private`) zugewiesen - User erhält Fehlermeldung wenn E-Mail bereits registriert - Validierung: Client-seitig (UX) + Server-seitig (Sicherheit) - Übersetzung in Deutsch und Englisch diff --git a/server/api/auth/login.post.ts b/server/api/auth/login.post.ts index 30d8253..bab1fe8 100644 --- a/server/api/auth/login.post.ts +++ b/server/api/auth/login.post.ts @@ -63,6 +63,11 @@ export default defineEventHandler(async (event) => { .returning() user = newUser + + // Auto-assign 'private' role on first login + await assignRoleToUser(newUser.id, 'private', { + adminNotes: 'Auto-assigned on first login', + }) } else { // Update last login timestamp await db @@ -71,6 +76,14 @@ export default defineEventHandler(async (event) => { updatedAt: new Date(), }) .where(eq(users.id, user.id)) + + // Safety check: If existing user has no roles, assign 'private' role + const userRoleCodes = await getUserApprovedRoleCodes(user.id) + if (userRoleCodes.length === 0) { + await assignRoleToUser(user.id, 'private', { + adminNotes: 'Auto-assigned for existing user without roles', + }) + } } // 6. Create encrypted session