Issue-Tracker
Monorepo-basiertes Issue-Management-System mit JWT-Authentication, RBAC und Policy-basierter Authorization
Lernfokus & Kompetenzen
SPA-Architektur
Angular Routing, Standalone Components, OnPush Change Detection, RxJS State Management
Authentifizierung & JWT-Security
Passport JWT Strategy, authGuard (CanActivateFn), HTTP-Interceptoren, 4 Rollen (Admin, Manager, Developer, User)
RESTful API-Design mit Validation
NestJS Controller mit verschachtelten Routen, class-validator DTOs, ValidationPipe, Global Exception Filter
Datenmodellierung (Relationen, ORM, SQL)
Prisma ORM mit 8 Modellen, Composite Keys, 16 Indizes, Migrations, Relations (@relation), JSONB für Activity Logs
Suche, Filter & Pagination
Rollenbasierte Projekt-Filterung, Policy-basierte Zugriffssteuerung, Query Optimierung mit WHERE-Indizes
Dokumentation & Team-Relevanz
Nx Monorepo Architektur, Shared-Types Library, Architekturdiagramm, DB-Modell, saubere Code-Struktur für Teams
UI/UX & Design
Angular Material Components, Reactive Forms, responsive Layouts, Dashboard mit Statistiken
Features
JWT Authentication mit 4 Rollen (Admin, Manager, Developer, Reporter)
CRUD für Tickets, Projects, Comments mit Policy-basierter Authorization
Status-Workflows (Open → In Progress → Resolved → Closed)
Project-spezifische Labels mit Farben für Kategorisierung
Rollenbasierte Filterung und Suche mit Prisma Query Builder
Project Members mit Add/Remove Funktionalität
Comments mit CRUD und Owner/Admin-basiertem Delete
class-validator DTOs in shared-types Library
Ticket Activity Tracking (Status-, Assignee-, Label-Changes)
Architektur
- Standalone Components mit OnPush Change Detection
- Reactive Forms mit Custom Validators
- RxJS für async State (takeUntil Pattern)
- Angular Material 20 für UI-Komponenten
- authGuard (CanActivateFn) für Route Protection
- Global Guards: JwtAuthGuard, ThrottlerGuard
- Passport JWT Strategy mit @Public() Decorator
- Prisma ORM mit PostgreSQL
- Policy Handlers für granulare Authorization
- Health Check Endpoints für Monitoring
- 8 Tabellen: User, Project, Ticket, Label, Comment, ProjectMember, TicketLabel, TicketActivity
- Foreign Keys mit Cascade Delete
- 16 Indizes für Query-Optimierung
- JSONB für Activity Details
- RESTful API mit nested Routes (z.B. /projects/:id/tickets)
- JWT Interceptor für Authorization Header
- Error Interceptor für zentrale Fehlerbehandlung
- CORS mit Environment-spezifischen Origins
Screenshots & UI-Flows
Technische Details
Nx Monorepo mit apps/frontend, apps/backend und libs/shared-types. Feature-basierte Module mit Lazy Loading und strikter Separation of Concerns.
- Frontend-Struktur: core/ (guards, interceptors, services, layout), features/ (auth, projects, tickets, dashboard, users)
- Backend-Struktur: NestJS Module: auth, projects, tickets, comments, users, dashboard, health - jeweils mit Controller, Service, DTOs
Herausforderungen & Learnings
Herausforderungen
Policy-basierte Authorization
Problem: RoleGuard allein reichte nicht: Ticket-Update sollte nur für Owner, Assignee oder Manager/Admin erlaubt sein - nicht pauschal für alle Developers.
Lösung: Implementierung von IPolicyHandler Interface mit konkreten Policy-Klassen (UpdateTicketPolicyHandler). PoliciesGuard nutzt ModuleRef für DI und führt handle(user, resource) aus. @CheckPolicies Decorator für deklarative Policy-Zuweisung.
Monorepo Shared Types
Problem: DTO-Duplikation zwischen Frontend und Backend führte zu Type-Mismatch und manueller Synchronisation.
Lösung: Nx Library @issue-tracker/shared-types mit class-validator DTOs. Backend importiert DTOs direkt, Frontend nutzt Interfaces. Definite Assignment Assertions (email!) für TypeScript Strict Mode.
Nested Route Guards
Problem: Routes wie /projects/:projectId/tickets/:ticketId/comments benötigten Projekt-Zugriff, aber ProjectAccessGuard erwartete :id Parameter.
Lösung: extractProjectId() Methode im Guard prüft beide Patterns (:id und :projectId). ProjectsService.hasProjectAccess() prüft Rolle (Admin/Manager immer erlaubt) oder ProjectMember-Tabelle.
Activity Tracking mit JSONB
Problem: Activity-Logs brauchten flexible Struktur: Status-Change hat oldValue/newValue, Label-Change hat labelName/color - starres Schema zu limitierend.
Lösung: Prisma JSONB field "detail" mit Type Record<string, unknown>. Backend speichert { oldValue, newValue } oder { labelName, color }. GIN-Index auf detail für Query-Performance.
Learnings
- Policy Handler Pattern: Separation of Concerns - Authorization-Logik in testbaren Klassen statt in Guards. ModuleRef.get() ermöglicht DI-basierte Instantiierung.
- Prisma vs TypeORM: Prisma Schema ist deklarativer (Enums mit @map, Relations eindeutiger), aber Query Builder weniger flexibel für komplexe Joins.
- Guard Execution Order: JwtAuthGuard (global APP_GUARD) → RoleGuard (@UseGuards) → ProjectAccessGuard → PoliciesGuard - Reihenfolge ist kritisch!
- Nx Monorepo: shared-types Library vermeidet DTO-Duplikation, aber Circular Dependencies zwischen libs/shared-types und apps/backend erfordern sorgfältige Strukturierung.
- OnPush Change Detection: Reduziert Render-Zyklen massiv, aber erfordert immutable Updates (new Arrays statt push) und explizites ChangeDetectorRef.markForCheck().
Mögliche Verbesserungen
- E2E Tests mit Cypress für kritische User Flows (Login, Create Ticket, Comment).
- Rate Limiting pro User (aktuell nur global via ThrottlerGuard) für feinere Kontrolle.
- Optimistic UI Updates mit Rollback bei Backend-Fehler (aktuell nur Loading-States).
- GraphQL Subscriptions für Real-time Activity Updates (Alternative zu Polling).