Replace hardcoded .env configuration with database-backed settings
manageable through the Admin web interface. This reduces .env to
bootstrap-only variables (DB, Keycloak, encryption keys).
Backend:
- Add SystemSetting Prisma model with category, valueType, isSecret
- Add system-settings NestJS module (CRUD, 60s cache, encryption)
- Refactor all 7 connectors to lazy-load credentials from DB via
CredentialsService.findActiveByType() instead of ConfigService
- Add event-driven credential reload (@nestjs/event-emitter)
- Dynamic CORS origins and conditional Swagger from DB settings
- Fix JWT strategy: use Keycloak JWKS (RS256) instead of symmetric secret
- Add SYSTEM_SETTINGS_VIEW/MANAGE permissions
- Seed 13 default settings (sync intervals, features, branding, CORS)
- Add env-to-db migration script (prisma/migrate-env-to-db.ts)
Frontend:
- Add use-credentials hook (full CRUD for integration credentials)
- Add use-system-settings hook (read/update system settings)
- Wire admin-integrations page to real API (create/update/test/toggle)
- Add admin system-settings page with 4 tabs (Branding, CORS, Sync, Features)
- Fix sidebar double-highlighting with exactMatch flag
- Fix integration detail fallback when API unavailable
- Fix API client to unwrap backend's {success, data} envelope
- Update NEXT_PUBLIC_API_URL to include /v1 version prefix
- Fix activity-widget hydration error
- Add i18n keys for systemSettings (de + en)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Since tOS uses Keycloak as sole auth provider, the intermediate
login page with the manual "Mit Keycloak anmelden" button was
unnecessary. Now unauthenticated users are redirected directly
to Keycloak. The error UI with retry button is preserved for
failed auth attempts (expired session, unauthorized).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Skill Matrix: use correct nested key `skillMatrix.title` instead of
`skillMatrix` which resolved to the full object
- Skill Matrix: use `skillMatrix.trend.label` instead of
`skillMatrix.trend` which resolved to the trend object
- Integrations: rename duplicate `title` key to `documentTitle` in
de.json/en.json to prevent the ecoDMS column header from overriding
the page title ("Titel" instead of "Integrationen")
- Shared package: move `types` condition before `import`/`require` in
exports field to fix TypeScript type resolution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>