275 lines
7.6 KiB
Markdown
275 lines
7.6 KiB
Markdown
# 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 <base href> für korrekte Asset-Pfade ein
|
|
```
|
|
|
|
#### AdminService (`admin.service.ts`)
|
|
|
|
**Kernfunktionen:**
|
|
|
|
1. **RAR-Entpacken:**
|
|
```typescript
|
|
extractRar(projectId: string, rarPath: string): Promise<void>
|
|
// 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<void>
|
|
// 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) |