4D Teamassessment — System-Übersicht

Lebende Architektur-Dokumentation: Feature-Matrix, Datenmodell (aus Prisma), Entscheidungs-Log (aus ADRs), API-Routen und Deployment — automatisch aktuell.

Features
21
13 live · 1 teilw. · 7 geplant
Datenbank-Modelle
11
10 Felder in SessionArtifact
ADRs
2
Architektur-Entscheidungen dokumentiert
Sessions
1
in 1 Instanzen · 2 User

Anforderungen & Umsetzungmanuell gepflegt

Landing PageLive

Hero + 5 Sektionen + Footer, responsives Design, agile4d-Palette

Auth (Magic Link + OTP)Live

NextAuth.js v4, Email Magic Link via Brevo, 6-stelliger OTP-Code, Demo-Zugang (tl@demo.4d / su@demo.4d)

Rollen (Admin, TL, SU, User)Live

Vier Rollen — ADMIN, SUPER_USER, TRANSFORMATION_LEAD, USER (Teilnehmer ohne Login)

TL Dashboard + Artefakt-ManagementLive

Sessions-Liste, Detail mit QR-Code, Artefakt-CRUD, Vorbereitungsgrad

SU Dashboard + Session-PlanungLive

Sessions-Liste, Detail, Planungsformular, Observations-Page (Platzhalter)

Session-Teilnahme (4 Runden)Live

Session-Code-Eingabe, Artefakt-Sammlung, Scale → Agreement → Matrix → Freitext

Voice InputLive

Web Speech API für Spracheingabe in Artefakt- und Freitext-Felder

AI-Assist (Artifact Check + Freitext)Live

Provider-agnostisch (DeepSeek/Ollama etc.), Privacy-Layer vorgeschaltet

Privacy-Layer (PII-Masking)Live

Pattern-basierte PII-Erkennung + Maskierung vor AI-Calls, Presidio-vorbereitet

QR-Code + Kurzlink /s/[code]Live

Server-generierter QR-Code (SVG), Kurzlink-Redirect zu Session

Demo-Seed DataLive

EnableChange Demo GmbH, TL/SU Demo-Accounts, 5 Artefakte, DEMO-4D

System-Übersicht (diese Seite)Live

Auto-generierte Architektur-Dokumentation aus Prisma-Schema + ADRs

ADR-ProzessLive

Architecture Decision Records in .pi/adr/ — jede Entscheidung dokumentiert + abgewogen

Mobile OptimierungTeilweise

Responsive + größere Touch-Targets — weitere Tests nötig

Multiple Choice RundeGeplant

Fünfte Bewertungsrunde — Inhalte von Ralf

Facilitator-OverviewGeplant

Live-Aggregation der Teilnehmer-Daten auf /session/[code]/overview

ArtifactResponse-PersistenzGeplant

Bewertungen in DB speichern (aktuell nur React-State)

Excel-Export / ImportGeplant

Datenexport und -import für TL/SU

Admin: Kunden anlegen + EinladenGeplant

Kunden-Verwaltung mit TL/SU-Einladung

DB-Backups (pg_dump)Geplant

Automatisierte PostgreSQL-Backups via Cron

CI/CD-Automatisierung (Webhook/Cron)Geplant

Automatischer Deploy bei Push

Datenmodell

Auto-generiert aus prisma/schema.prisma · PostgreSQL auf Hetzner

User
15 Felder
idString@id @default(cuid()
emailString@unique
nameString?
emailVerifiedDateTime?
imageString?
roleString@default("USER")
createdAtDateTime@default(now()
updatedAtDateTime@updatedAt
accountsAccount
sessionsSession
sessionUsersSessionUser
instancesAssessmentInstance
observationsObservation
artifactResponsesArtifactResponse
superUserInstancesInstanceSuperUser
VerificationToken
6 Felder
identifierString
tokenString@unique
expiresDateTime
otpCodeString?
otpAttemptsInt@default(0)
createdAtDateTime@default(now()
Account
13 Felder
idString@id @default(cuid()
userIdString
typeString
providerString
providerAccountIdString
refresh_tokenString?@db
access_tokenString?@db
expires_atInt?
token_typeString?
scopeString?
id_tokenString?@db
session_stateString?
userUser@relation(fields: [userId], references: [id], onDelete: Cascade)

Relationen: user

Session
6 Felder
idString@id @default(cuid()
sessionTokenString@unique
userIdString
expiresDateTime
createdAtDateTime@default(now()
userUser@relation(fields: [userId], references: [id], onDelete: Cascade)

Relationen: user

AssessmentInstance
9 Felder
idString@id @default(cuid()
nameString
slugString@unique
createdAtDateTime@default(now()
updatedAtDateTime@updatedAt
createdByIdString
createdByUser@relation(fields: [createdById], references: [id])
sessionsAssessmentSession
superUsersInstanceSuperUser

Relationen: createdBy

InstanceSuperUser
6 Felder
idString@id @default(cuid()
instanceIdString
userIdString
addedAtDateTime@default(now()
instanceAssessmentInstance@relation(fields: [instanceId], references: [id])
userUser@relation(fields: [userId], references: [id])

Relationen: instance, user

AssessmentSession
13 Felder
idString@id @default(cuid()
instanceIdString
sessionCodeString@unique
statusString@default("pending")
startedAtDateTime?
completedAtDateTime?
maxDurationInt@default(120)
createdAtDateTime@default(now()
instanceAssessmentInstance@relation(fields: [instanceId], references: [id])
observationsObservation
usersSessionUser
artifactsSessionArtifact
responsesArtifactResponse

Relationen: instance

SessionUser
6 Felder
idString@id @default(cuid()
sessionIdString
userIdString
joinedAtDateTime@default(now()
sessionAssessmentSession@relation(fields: [sessionId], references: [id])
userUser@relation(fields: [userId], references: [id])

Relationen: session, user

Observation
11 Felder
idString@id @default(cuid()
sessionIdString
artifactIdString?
authorIdString?
authorRoleString
contentString@db
dimensionString
createdAtDateTime@default(now()
sessionAssessmentSession@relation(fields: [sessionId], references: [id])
artifactSessionArtifact?@relation(fields: [artifactId], references: [id])
authorUser?@relation(fields: [authorId], references: [id])

Relationen: session, artifact, author

SessionArtifact
10 Felder
idString@id @default(cuid()
sessionIdString
titleString
definitionString@db
addedByString@default("TL")
sortOrderInt@default(0)
createdAtDateTime@default(now()
sessionAssessmentSession@relation(fields: [sessionId], references: [id])
responsesArtifactResponse
observationsObservation

Relationen: session

ArtifactResponse
10 Felder
idString@id @default(cuid()
sessionIdString
artifactIdString
userIdString?
roundTypeString@default("scale")
valueJson
createdAtDateTime@default(now()
sessionAssessmentSession@relation(fields: [sessionId], references: [id])
artifactSessionArtifact@relation(fields: [artifactId], references: [id])
userUser?@relation(fields: [userId], references: [id])

Relationen: session, artifact, user

Architektur-Entscheidungen (ADRs)

Auto-generiert aus .pi/adr/ · Jede Entscheidung dokumentiert + abgewogen

ADR 2: Test-StrategieUnknown

Keine Zusammenfassung.

ADR 1: Architektur-EntscheidungsprozessUnknown

Keine Zusammenfassung.

Architektur

Tech Stack

Frontend
Next.js 16, React 19, Tailwind 4
Backend
Next.js App Router / API Routes
ORM
Prisma 6.19, PostgreSQL 16
Auth
NextAuth.js v4, Brevo Email
AI
OpenAI-kompatibel (DeepSeek/Ollama)
UI
Radix Slot, CVA, lucide-react
Testing
vitest, vitest-mock-extended
Deploy
Docker, Hetzner VPS, nginx
Fonts
Mulish, Baloo Tamma 2

API-Routen

POST/api/auth/[...nextauth]
GET/api/sessions/[sessionId]/artifacts
POST/api/sessions/[sessionId]/artifacts
DELETE/api/sessions/[sessionId]/artifacts/[artifactId]
POST/api/sessions/plan
POST/api/ai/chat
POST/api/ai/check-artifact
POST/api/ai/assist-text

App-Struktur

src/
  app/
    (site)/         Public pages (Landing, Session, Impressum, System)
    (internal)/     Auth-geschützte Seiten (Admin, TL, SU)
    api/            REST-API-Routen
  components/
    ui/             Button, Card, Input (Radix+CTA)
    VoiceInput.tsx  Spracheingabe
    QRCodeSVG.tsx   QR-Code-Generator
    Header/Footer   Public-Layout
  hooks/            useAiAssist (useArtifactCheck, useFreeTextAssist)
  lib/              prisma.ts, auth.ts, cn.ts, ai.ts, privacy.ts, system-data.ts
  __tests__/        Unit-Tests + Prisma-Mocks
  types/            speech-recognition.d.ts
prisma/             schema.prisma + Migrationen
.pi/
  adr/              Architektur-Entscheidungen (ADRs)
  ARCHITECTURE.md   Dauerhafte Constraints
  PLAN.md           Aktuelle Roadmap
  LEARNINGS.md      Fehler + Erkenntnisse

Deployment

Domain
4d.enablechange.de
Server
Hetzner VPS (46.224.16.128)
Container
127.0.0.1:3005 → 3000 (intern)
Netzwerk
calcom_hetzner_network
SSL
Let's Encrypt (certbot, nginx)
Reverse Proxy
nginx (SSL+WAF) → Caddy (8080) → App (3005)
Datenbank
PostgreSQL 16 (Container postgres-calcom)
CI/CD
scripts/deploy.sh (manuell via SSH)