Commit Graph

11 Commits

Author SHA1 Message Date
schalli a5f99e52e3 feat(quick-260909-dgj): Migrationsverbindung von Laufzeitverbindung trennen (Task 2/4)
- apps/api/scripts/migrate-and-start.sh: TESSERA_MIGRATE_DATABASE_URL fuer
  den Migrationsschritt, DATABASE_URL bleibt unveraendert fuer den
  Laufzeitschritt; leer/nicht gesetzt = bisheriges Verhalten
- Dockerfile kopiert scripts/ und ruft das Skript als CMD auf; exec statt
  &&-Verkettung, damit Signale den Node-Prozess erreichen
- docker-compose.yml/.prod.yml reichen TESSERA_MIGRATE_DATABASE_URL durch
  (leerer Vorgabewert); docker-compose.dev.yml/.ci.yml unveraendert
- .env.example erklaert beide Variablen mit Platzhaltern, Umstellung bleibt
  auskommentiert
- 5 Tests in start-script.spec.ts (rot vor dem Skript, jetzt gruen)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
2026-09-09 10:00:45 +02:00
schalli dab72eb1f9 fix(compose): user-files dauerhaft speichern und Betriebshandbuch nachziehen
- docker-compose.yml und docker-compose.prod.yml mounten /app/user-files
  im Dienst api auf ein neues benanntes Volume user-files (Eigentuemerschaft
  uid 1001 folgt aus dem Image, kein Bind-Mount)
- docker-compose.dev.yml bleibt unveraendert (Compose fuehrt Mount-Listen
  ueber das Ziel zusammen)
- Betriebshandbuch Kapitel 6: Speicher als dauerhaft beschrieben, Mount-Zeile
  woertlich zum Kopieren, Hinweis dass /opt/tessera/docker-compose.yml auf
  dem Server separat gepflegt werden muss (Deploy erreicht sie nicht)
- Betriebshandbuch Kapitel 7: Fehlerzeile zu verschwundenen Avataren/Exporten
  an den reparierten Repository-Stand angepasst

WINDOWS #17 bleibt offen, bis die Serverdatei manuell ergaenzt ist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
2026-09-09 09:34:15 +02:00
schalli f574884b32 refactor: rename the encryption key to what it actually protects
Tessera CI/CD / Lint & Type Check (push) Successful in 54s
Tessera CI/CD / Tests (push) Successful in 51s
Tessera CI/CD / Build & Publish Images (push) Successful in 25s
CALENDAR_ENCRYPTION_KEY was named after the calendar module because that
module needed encryption first, in Phase 5. Every feature since has shared the
same key -- SMTP, the DKV and tender mailboxes, and as of today the LDAP bind
password -- so the name has been describing one of five users rather than the
thing itself, and each new feature inherited the confusion.

TESSERA_ENCRYPTION_KEY is the name now. The old one is still read, because
renaming outright would stop every existing installation at the next start:
their .env carries the old name, and compose was just made to fail hard on a
missing key. When only the old name is present the API logs a deprecation
warning naming both, and when both are set the new one wins -- otherwise a
half-migrated .env would encrypt with one key and decrypt with the other.

CalendarCryptoService becomes CryptoService in its own global CryptoModule.
Four modules used to import CalendarModule purely to reach the provider, which
read as a dependency on calendars where there was none; that import is gone.

Compose keeps the hard failure: without either name the stack refuses to
start. Verified in both files for all three cases -- neither name set (abort),
only the old name (starts), only the new name (starts).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 14:30:46 +02:00
schalli 7bda56d222 build: refuse to start without an encryption key
The base compose file carried a hardcoded fallback key, so a stack whose .env
never set the variable started anyway and encrypted every stored credential
(LDAP bind, calendar, SMTP, DKV and tender mailboxes) with a value that is
public in this repository. That is encryption which looks present and protects
nothing.

Both compose files now use the ${VAR:?message} form, so an unset or empty key
fails at compose level with a message naming the variable and how to generate
one, instead of starting with a known key or dying later inside the API with a
stack trace.

Verified both ways: without the variable `docker compose config` exits 1 and
prints the hint; with a key present it exits 0.

Consequence for a fresh clone: the local stack no longer comes up until
CALENDAR_ENCRYPTION_KEY is set in .env. That is the point.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 14:25:36 +02:00
schalli 37e09dc66f fix(05): add dev default for CALENDAR_ENCRYPTION_KEY in docker-compose
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:37:48 +02:00
schalli bb8990ca66 chore(05-03): Prisma schema push + encryption key configuration
- Add CALENDAR_ENCRYPTION_KEY env var to docker-compose api service
- Push CalendarSource table to live PostgreSQL (16 columns verified)
- Regenerate Prisma client with CalendarSource model
- DB reports in sync on second push (no drift)
2026-06-24 15:15:59 +02:00
schalli 46a6e277b8 fix(03): login redirect + API internal URL for Docker networking
- Use window.location.href for full page reload after login (ensures auth state)
- Add API_INTERNAL_URL for server-side requests within Docker network
- Remove unnecessary credentials:'include' from SSR fetch calls
- Update planning state for Phase 03 progress

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 09:28:05 +02:00
schalli ac617f4fe5 feat(02-03): password reset flow, force-change interceptor, MailModule
- MailModule with SMTP transport configured from ENV variables
- MailService for password reset and welcome emails (plain text, i18n)
- Password reset flow: request-reset (public), reset-password (token-based)
- Change password for logged-in users with current password verification
- Admin reset password endpoint (ADMIN/SUPER_ADMIN only, D-03)
- ForcePasswordChangeInterceptor blocks all routes except change-password,
  logout, me when mustChangePassword=true (D-06, Pitfall 5)
- Frontend: reset-password request page, token reset page, change-password page
- Forgot password link added to login page
- MailHog service added to docker-compose.dev.yml for dev email testing
- SMTP env vars added to docker-compose.yml (defaults to MailHog)
- Complete DE/EN i18n coverage for reset and change password flows
- SUS packages installed: @nestjs-modules/mailer, nodemailer, ldapts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 13:48:23 +02:00
schalli d0b36c8f22 feat(02-01): Prisma schema expansion, RLS migration, and PrismaModule
- Add User, Role enum, PasswordResetToken, LdapConfig, LdapFieldMapping models
- Expand Tenant model with isActive, users relation, ldapConfig relation
- Create RLS migration with tenant isolation policies on all tenant-scoped tables
- Create PrismaModule (global), PrismaService, and forTenant extension
- Add JWT_SECRET, TESSERA_ADMIN_*, TESSERA_FORCE_CHANGE env vars to docker-compose
- Install @nestjs/jwt, @nestjs/passport, passport, argon2, class-validator deps
2026-06-18 13:22:38 +02:00
schalli a9018083b2 fix(01): remove traefik, lighten dark mode, fix sidebar accent color, move locale switcher to sidebar footer 2026-06-18 12:41:02 +02:00
schalli 2c12878cb1 feat(01-01): Next.js app + Docker Compose stack with network segmentation
- Next.js 15 app with Tailwind CSS v4, standalone output for Docker
- Root layout with de locale, page with Tessera placeholder
- Multi-stage Dockerfile for web with monorepo root context
- Docker Compose with 4 services: traefik, web, api, db
- Three segregated networks: frontend-net, backend-net, data-net (internal)
- Traefik v2.11 reverse proxy routing / to web, /api to api
- API strip prefix middleware for clean routing
- PostgreSQL 16-alpine with health checks and named volume
- Fixed API Dockerfile for pnpm monorepo node_modules structure
- Fixed Next.js standalone path for monorepo (apps/web/server.js)
- Fixed Traefik Docker API version compatibility
- Network segmentation: web NOT on data-net, api NOT on frontend-net
2026-06-18 10:17:21 +02:00