diff --git a/apps/api/src/middleware/auth.ts b/apps/api/src/middleware/auth.ts index a044b5a..35fd5d1 100644 --- a/apps/api/src/middleware/auth.ts +++ b/apps/api/src/middleware/auth.ts @@ -1,5 +1,6 @@ import type { Context, MiddlewareHandler } from 'hono'; import { createRemoteJWKSet, jwtVerify } from 'jose'; +import { fireFirstUseOnce } from '../services/aura-client.ts'; /** * Auth-Middleware der Cards-API (Phase 2 Auth-Föderation). @@ -81,6 +82,9 @@ export const authMiddleware: MiddlewareHandler<{ Variables: AuthVars }> = async c.set('userId', claims.sub); c.set('tier', claims.tier); c.set('authMode', 'jwt'); + // Cross-App-Aura-Hook: erste Wordeck-Aktion → 25 Aura einmalig. + // Reason-Katalog: mana/docs/playbooks/AURA_PER_APP_HOOKS.md. + fireFirstUseOnce(claims.sub); await next(); return; } diff --git a/apps/api/src/services/aura-client.ts b/apps/api/src/services/aura-client.ts new file mode 100644 index 0000000..fc63e2a --- /dev/null +++ b/apps/api/src/services/aura-client.ts @@ -0,0 +1,38 @@ +/** + * Aura-Client für Service-to-Service-Calls an mana-admin. + * + * Heute: nur `fireFirstUseOnce` für den Cross-App-Hook + * `onboarding.first_use` (25 Aura, einmalig). + * + * Server-seitig (mana-admin Migration 0003) gibt es UNIQUE-Indizes + * auf `aura_ledger(user_id, reason)` für einmalig-Reasons, also + * sind Doppel-Awards auf DB-Ebene unmöglich. Der Process-Cache + * hier ist reine HTTP-Overhead-Reduktion. + * + * Reason-Katalog: mana/docs/playbooks/AURA_PER_APP_HOOKS.md. + */ + +const firedFirstUse = new Set(); + +export function fireFirstUseOnce(userId: string): void { + if (firedFirstUse.has(userId)) return; + firedFirstUse.add(userId); + + const adminUrl = process.env.MANA_ADMIN_URL ?? 'http://localhost:3071'; + const serviceKey = process.env.MANA_SERVICE_KEY ?? 'dev-service-key'; + + fetch(`${adminUrl}/api/v1/internal/aura/award`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Service-Key': serviceKey, + }, + body: JSON.stringify({ + userId, + delta: 25, + reason: 'onboarding.first_use', + refId: userId, + context: { app: 'wordeck' }, + }), + }).catch(() => {}); +}