managarten/services/mana-analytics/src/config.ts
Till JS 8b0a943e71 feat(mana-analytics): pseudonym + reactions + public feed + admin
Macht mana-analytics zur Backend-Heimat des Public-Community-Hubs.

- Pseudonym: createDisplayHash(userId, secret) + generateDisplayName()
  produzieren deterministisch "Wachsame Eule #4528" pro User. 100
  Adjektive × 80 Tieren × 10000 Suffixe → ~80M Kombinationen. 7 unit
  tests, 0 PII im Output.
- Schema-Erweiterung user_feedback: display_hash, display_name,
  module_context, parent_id (1-level Threading), reactions jsonb
  (cached emoji→count), score (cached weighted sort).
- feedback_votes ersetzt durch feedback_reactions (Slack-Pattern:
  unique(feedback_id, user_id, emoji), pro User mehrere Emojis möglich).
- Service: createFeedback stempelt display_hash + display_name. Neue
  Methoden getPublicFeed (redacted), getReplies, toggleReaction
  (rebuilt reactions+score). Admin-Methoden adminListAll/adminUpdate
  founder-tier-gated im Route-Layer.
- Routes:
  /api/v1/public/feedback/*  — anonymous reads (kein Auth, kein
                              userId/displayHash/deviceInfo im Output)
  /api/v1/feedback/*         — auth-required Submit/React/Manage,
                              plus :id/replies, :id/react, /admin
- Config: neuer FEEDBACK_PSEUDONYM_SECRET-Env-Var seedet die Hashes;
  Rotation re-keyt nur künftige Pseudonyme, alte Records bleiben stabil.

Migration 0002_public-community-foundation.sql idempotent, lokal +
prod (mana-server) eingespielt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 00:00:35 +02:00

27 lines
1,015 B
TypeScript

export interface Config {
port: number;
databaseUrl: string;
manaAuthUrl: string;
manaLlmUrl: string;
serviceKey: string;
/**
* Secret seeded into the per-user display-hash for the public-community
* pseudonym ("Wachsame Eule #4528"). Rotating this re-keys all future
* pseudonyms — existing rows keep the old hash/name.
*/
pseudonymSecret: string;
cors: { origins: string[] };
}
export function loadConfig(): Config {
const env = (key: string, fallback?: string) => process.env[key] || fallback || '';
return {
port: parseInt(env('PORT', '3064'), 10),
databaseUrl: env('DATABASE_URL', 'postgresql://mana:devpassword@localhost:5432/mana_platform'),
manaAuthUrl: env('MANA_AUTH_URL', 'http://localhost:3001'),
manaLlmUrl: env('MANA_LLM_URL', 'http://localhost:3025'),
serviceKey: env('MANA_SERVICE_KEY', 'dev-service-key'),
pseudonymSecret: env('FEEDBACK_PSEUDONYM_SECRET', 'dev-pseudonym-secret'),
cors: { origins: env('CORS_ORIGINS', 'http://localhost:5173').split(',') },
};
}