Add Anthropic API, test environment, remove locale settings

Feature 1: Anthropic API Integration
- Add @anthropic-ai/sdk with adapter wrapping OpenAI-shaped interface
- Support Claude models (opus, sonnet, haiku) with extended thinking
- Auto-reset model on provider switch, JSON retry logic
- Add Claude model pricing to ai-usage tracker
- Update AI settings form with Anthropic provider option

Feature 2: Remove Locale Settings UI
- Strip Localization tab from admin settings
- Remove i18n settings from router inferCategory and getFeatureFlags
- Keep franc document language detection intact

Feature 3: Test Environment with Role Impersonation
- Add isTest field to User, Program, Project, Competition models
- Test environment service: create/teardown with realistic dummy data
- JWT-based impersonation for test users (@test.local emails)
- Impersonation banner with quick-switch between test roles
- Test environment panel in admin settings (SUPER_ADMIN only)
- Email redirect: @test.local emails routed to admin with [TEST] prefix
- Complete data isolation: 45+ isTest:false filters across platform
  - All global queries on User/Project/Program/Competition
  - AI services blocked from processing test data
  - Cron jobs skip test rounds/users
  - Analytics/exports exclude test data
  - Admin layout/pickers hide test programs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 17:20:48 +01:00
parent 161cd1684a
commit 87d5aea315
61 changed files with 2089 additions and 983 deletions

View File

@@ -101,7 +101,6 @@ enum SettingCategory {
DEFAULTS
WHATSAPP
AUDIT_CONFIG
LOCALIZATION
DIGEST
ANALYTICS
INTEGRATIONS
@@ -351,6 +350,9 @@ model User {
preferredWorkload Int?
availabilityJson Json? @db.JsonB // { startDate?: string, endDate?: string }
// Test environment isolation
isTest Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
@@ -495,6 +497,9 @@ model Program {
description String?
settingsJson Json? @db.JsonB
// Test environment isolation
isTest Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -619,6 +624,9 @@ model Project {
metadataJson Json? @db.JsonB // Custom fields from Typeform, etc.
externalIdsJson Json? @db.JsonB // Typeform ID, Notion ID, etc.
// Test environment isolation
isTest Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -907,7 +915,8 @@ model AIUsageLog {
entityId String?
// What was used
model String // gpt-4o, gpt-4o-mini, o1, etc.
provider String? // 'openai', 'anthropic', 'litellm'
model String // gpt-4o, gpt-4o-mini, o1, claude-sonnet-4-5, etc.
promptTokens Int
completionTokens Int
totalTokens Int
@@ -2090,6 +2099,9 @@ model Competition {
notifyOnDeadlineApproach Boolean @default(true)
deadlineReminderDays Int[] @default([7, 3, 1])
// Test environment isolation
isTest Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -2104,6 +2116,7 @@ model Competition {
@@index([programId])
@@index([status])
@@index([isTest])
}
model Round {