# System-Architektur - PointCab Webexport Server Diese Dokumentation beschreibt die technische Architektur des Systems. ## πŸ—οΈ Übersicht ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Browser │◄───►│ Nginx Proxy │◄───►│ NestJS β”‚ β”‚ (Client) β”‚ β”‚ Manager (443) β”‚ β”‚ (Port 3000) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”‚ PostgreSQL β”‚ β”‚ Filesystem β”‚ β”‚ (pointcab_db)β”‚ β”‚ (uploads/) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## πŸ“‚ Verzeichnisstruktur ``` /var/www/pointcab_webexport_server/ β”œβ”€β”€ nodejs_space/ # Haupt-Anwendung β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ controllers/ # HTTP-Endpunkte β”‚ β”‚ β”‚ β”œβ”€β”€ admin.controller.ts β”‚ β”‚ β”‚ β”œβ”€β”€ projects.controller.ts β”‚ β”‚ β”‚ └── root.controller.ts β”‚ β”‚ └── services/ # Business-Logik β”‚ β”‚ β”œβ”€β”€ admin.service.ts β”‚ β”‚ β”œβ”€β”€ projects.service.ts β”‚ β”‚ β”œβ”€β”€ upload.service.ts β”‚ β”‚ └── prisma.service.ts β”‚ β”œβ”€β”€ prisma/ β”‚ β”‚ └── schema.prisma # Datenbank-Schema β”‚ β”œβ”€β”€ dist/ # Kompilierter Code β”‚ β”œβ”€β”€ uploads/ # Hochgeladene Projekte β”‚ β”œβ”€β”€ package.json β”‚ β”œβ”€β”€ tsconfig.json β”‚ └── .env # Konfiguration └── backups/ # Deployment-Backups ``` ## πŸ› οΈ Komponenten ### 1. Controllers #### ProjectsController (`projects.controller.ts`) Verantwortlich fΓΌr: - Projekt-Anzeige (`GET /:shareId/view`) - Passwort-Authentifizierung (`POST /:shareId/auth`) - Asset-Serving (`GET /:shareId/*`) **Wichtige Funktionen:** ```typescript // Projekt anzeigen @Get(':shareId/view') async viewProject() // Assets laden (JS, CSS, Bilder) @Get(':shareId/*') async getProjectResource() // Passwort-Seite @Get(':shareId') async showPasswordPage() ``` #### AdminController (`admin.controller.ts`) Verantwortlich fΓΌr: - Dashboard (`GET /admin/dashboard`) - Projekt-Verwaltung (CRUD) - RAR-Entpacken - Datei-Upload ### 2. Services #### ProjectsService (`projects.service.ts`) **Kernfunktionen:** 1. **Web-Subfolder-Erkennung:** ```typescript detectWebSubfolder(projectPath: string): string | null // Erkennt z.B. "Web_0_web/" Ordner ``` 2. **Asset-Pfad-AuflΓΆsung:** ```typescript resolveAssetPath(projectPath: string, assetPath: string): string // LΓΆst relative Pfade auf ``` 3. **Base-Tag-Injection:** ```typescript injectBaseTag(html: string, shareId: string, htmlPath?: string): string // FΓΌgt fΓΌr korrekte Asset-Pfade ein ``` #### AdminService (`admin.service.ts`) **Kernfunktionen:** 1. **RAR-Entpacken:** ```typescript extractRar(projectId: string, rarPath: string): Promise // Verwendet spawn() fΓΌr große Dateien ``` 2. **HTML-Erkennung:** ```typescript findHtmlFiles(projectPath: string): string[] // Findet alle HTML-Dateien im Projekt ``` 3. **Multi-HTML-Logik:** ```typescript processExtractedProject(projectId: string): Promise // Setzt htmlfilename = null bei mehreren HTMLs ``` #### UploadService (`upload.service.ts`) **Kernfunktionen:** - ZIP/RAR-Upload verarbeiten - Projekt in Datenbank erstellen - Multi-HTML-Erkennung ### 3. Datenbank-Schema ```prisma model project { id String @id @default(uuid()) name String @unique shareid String @unique password String // Klartext (kein Hash!) htmlfilename String? // NULL bei Multi-HTML uploaddate DateTime @default(now()) expirydate DateTime? createdat DateTime @default(now()) } ``` **Wichtig:** `htmlfilename` ist **nullable** fΓΌr Multi-HTML-UnterstΓΌtzung! ## πŸ”„ Request-Flow ### Projekt anzeigen ``` 1. Browser: GET /abc123/view ↓ 2. Nginx Proxy: Weiterleitung an :3000 ↓ 3. ProjectsController.viewProject() β”‚ β”œβ”€ Projekt aus DB laden β”œβ”€ Passwort-Check (Cookie) β”œβ”€ htmlfilename prΓΌfen β”‚ β”œβ”€ null β†’ HTML-Auswahl-Seite β”‚ └─ vorhanden β†’ HTML laden β”œβ”€ Web-Subfolder erkennen β”œβ”€ Base-Tag injecten └─ HTML zurΓΌckgeben ↓ 4. Browser: Rendert HTML ↓ 5. Browser: LΓ€dt Assets (GET /abc123/js/main.js) ↓ 6. ProjectsController.getProjectResource() β”œβ”€ Pfad auflΓΆsen (mit Subfolder) └─ Datei zurΓΌckgeben ``` ### RAR entpacken ``` 1. Admin: POST /admin/projects/:id/extract-rar ↓ 2. AdminController.extractRar() ↓ 3. AdminService.extractRar() β”œβ”€ Platzhalter-HTML lΓΆschen β”œβ”€ RAR entpacken (spawn) β”œβ”€ HTML-Dateien finden β”œβ”€ Web-Subfolder erkennen β”œβ”€ htmlfilename setzen β”‚ β”œβ”€ 1 HTML β†’ Dateiname β”‚ └─ >1 HTML β†’ null └─ DB aktualisieren ``` ## πŸ” Sicherheit ### Passwort-Handling - PasswΓΆrter werden als **Klartext** gespeichert - Kein bcrypt-Hashing (bewusste Entscheidung fΓΌr einfache Verwaltung) - Cookie-basierte Session nach erfolgreicher Authentifizierung ### Pfad-Sicherheit ```typescript // Pfad-Normalisierung verhindert Directory Traversal const safePath = path.normalize(requestedPath).replace(/^(\.\.\/)+/, ''); ``` ### Datei-Zugriff - Nur Dateien innerhalb des Projekt-Verzeichnisses - Keine direkten Pfade vom Client - MIME-Type-Validierung ## πŸ“Š Technologie-Stack | Schicht | Technologie | Version | |---------|-------------|--------| | Runtime | Node.js | 18.x LTS | | Framework | NestJS | 10.x | | Sprache | TypeScript | 5.x | | Datenbank | PostgreSQL | 16.x | | ORM | Prisma | 5.x | | Process Manager | PM2 | 5.x | | Reverse Proxy | Nginx Proxy Manager | Latest | | OS | Ubuntu | 24.04 LTS | ## πŸ”§ Konfiguration ### Umgebungsvariablen (.env) ```env PORT=3000 # Server-Port NODE_ENV=production # Umgebung DATABASE_URL="postgresql://..." # DB-Verbindung UPLOAD_DIR=/path/to/uploads # Upload-Verzeichnis SESSION_SECRET=... # Session-VerschlΓΌsselung ADMIN_PASSWORD=... # Admin-Zugang ``` ### PM2 Konfiguration ```javascript // ecosystem.config.js module.exports = { apps: [{ name: 'pointcab-server', script: './dist/main.js', instances: 1, autorestart: true, max_memory_restart: '1G' }] }; ``` ## πŸ“ˆ Performance ### Optimierungen 1. **Spawn statt Exec:** FΓΌr RAR-Entpacken (kein Buffer-Limit) 2. **Lazy Loading:** Assets werden on-demand geladen 3. **PM2 Clustering:** MΓΆglich fΓΌr Skalierung ### Limits - Max Upload: 500 MB (konfigurierbar) - Max Projekte: Unbegrenzt (Speicherplatz-abhΓ€ngig) - Gleichzeitige Verbindungen: Node.js Standard --- **Siehe auch:** [CHANGELOG.md](CHANGELOG.md)