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

Frontend (Angular 20)
  • 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
Backend (NestJS 11)
  • 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
Datenbank (PostgreSQL)
  • 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
Kommunikation
  • 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

Login & Authentifizierung
Login & Authentifizierung
Dashboard
Dashboard
Projects Overview
Projects Overview
Ticket Management
Ticket Management
Ticket Details
Ticket Details
Project Management
Project Management

Technische Details

Modulstruktur
Modulstruktur

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
Authorization Guards
API-Design & DTOs
DB-Modell & Migrations

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).