Refactor code structure for improved readability and maintainability
This commit is contained in:
1 parent
207401b5fb
commit
c10d98f3b4
9 files changed
+2358
No files matched your search
@@ -0,0 +1,282 @@
|
|||||||
|
# API Reference
|
||||||
|
|
||||||
|
This document describes the currently implemented API surfaces in Linear Void.
|
||||||
|
|
||||||
|
## Base URLs
|
||||||
|
|
||||||
|
- Public app and admin: <https://linearvoid.tv>
|
||||||
|
- WebSocket endpoint: <wss://linearvoid.tv/ws>
|
||||||
|
- Local fallback: <http://localhost> and <ws://localhost/ws>
|
||||||
|
|
||||||
|
## Authentication Model
|
||||||
|
|
||||||
|
Admin REST endpoints use a cookie session.
|
||||||
|
|
||||||
|
- Cookie name: linearvoid_admin_session
|
||||||
|
- Cookie attributes: HttpOnly, SameSite=Strict, Secure when request is HTTPS (or X-Forwarded-Proto=https)
|
||||||
|
- Session TTL: controlled by ADMIN_SESSION_TTL_HOURS (default 12h)
|
||||||
|
|
||||||
|
## Chat WebSocket API
|
||||||
|
|
||||||
|
### Connect
|
||||||
|
|
||||||
|
Endpoint:
|
||||||
|
|
||||||
|
- GET /ws?username={name}&room={room}
|
||||||
|
|
||||||
|
Client sends JSON messages over the socket.
|
||||||
|
|
||||||
|
### Message Envelope (client -> server)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"room": "main",
|
||||||
|
"username": "viewer123",
|
||||||
|
"text": "hello world",
|
||||||
|
"type": "public"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- type is usually public for room chat and private for DM room routing.
|
||||||
|
- Private room names are formatted like dm:userA-userB (sorted usernames).
|
||||||
|
- Moderation/system events are sent as type=system messages.
|
||||||
|
|
||||||
|
### Message Envelope (server -> client)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"room": "main",
|
||||||
|
"username": "viewer123",
|
||||||
|
"text": "hello world",
|
||||||
|
"type": "public",
|
||||||
|
"timestamp": "2026-08-04T12:34:56Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Admin Session API
|
||||||
|
|
||||||
|
### Login
|
||||||
|
|
||||||
|
- POST /api/admin/login
|
||||||
|
- Auth: none
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"password": "your-password"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Success response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"authenticated": true,
|
||||||
|
"username": "admin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logout
|
||||||
|
|
||||||
|
- POST /api/admin/logout
|
||||||
|
- Auth: optional (clears cookie either way)
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"authenticated": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session Check
|
||||||
|
|
||||||
|
- GET /api/admin/session
|
||||||
|
- Auth: cookie required
|
||||||
|
|
||||||
|
Success response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"authenticated": true,
|
||||||
|
"username": "admin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Failure:
|
||||||
|
|
||||||
|
- 401 unauthorized
|
||||||
|
|
||||||
|
## Admin Data API
|
||||||
|
|
||||||
|
All endpoints below require admin authentication.
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
- GET /api/admin/overview
|
||||||
|
|
||||||
|
Returns aggregate counters and runtime/system snapshot fields.
|
||||||
|
|
||||||
|
### Playlist
|
||||||
|
|
||||||
|
- GET /api/admin/playlist
|
||||||
|
- PUT /api/admin/playlist
|
||||||
|
|
||||||
|
PUT request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"content": "file '/app/media/video1.mp4'\nfile '/app/media/video2.mp4'\n"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schedule
|
||||||
|
|
||||||
|
- GET /api/admin/schedule
|
||||||
|
|
||||||
|
Returns parsed playlist entries plus matched media metadata/runtime.
|
||||||
|
|
||||||
|
### Moderation
|
||||||
|
|
||||||
|
- GET /api/admin/moderation/logs?limit=50
|
||||||
|
- POST /api/admin/moderation/actions
|
||||||
|
|
||||||
|
Action request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"action": "mute",
|
||||||
|
"target": "username-or-id",
|
||||||
|
"moderator": "admin",
|
||||||
|
"reason": "spam",
|
||||||
|
"room": "main"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Analytics
|
||||||
|
|
||||||
|
- GET /api/admin/analytics
|
||||||
|
|
||||||
|
Returns totals (messages, moderation actions, rooms) and top room summary.
|
||||||
|
|
||||||
|
### System
|
||||||
|
|
||||||
|
- GET /api/admin/system
|
||||||
|
|
||||||
|
Returns service health snapshot for chat/playout/redis/database and config metadata.
|
||||||
|
|
||||||
|
### Active Users
|
||||||
|
|
||||||
|
- GET /api/admin/users
|
||||||
|
|
||||||
|
Returns currently discovered presence users (room + username) when Redis is available.
|
||||||
|
|
||||||
|
## Media Library API
|
||||||
|
|
||||||
|
### Media Collection
|
||||||
|
|
||||||
|
- GET /api/admin/media
|
||||||
|
- POST /api/admin/media (multipart upload, legacy path)
|
||||||
|
|
||||||
|
Multipart form field name: file
|
||||||
|
|
||||||
|
### Media Item
|
||||||
|
|
||||||
|
- GET /api/admin/media/{id}
|
||||||
|
- PUT /api/admin/media/{id}
|
||||||
|
- DELETE /api/admin/media/{id}
|
||||||
|
|
||||||
|
PUT request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ready",
|
||||||
|
"title": "My Clip",
|
||||||
|
"tags": "music,live"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resumable Upload API
|
||||||
|
|
||||||
|
Maximum file size: 2GB
|
||||||
|
|
||||||
|
Default chunk size: 8MB
|
||||||
|
|
||||||
|
### Initialize or Resume Session
|
||||||
|
|
||||||
|
- POST /api/admin/media/uploads
|
||||||
|
|
||||||
|
Request:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"uploadId": "optional-existing-id",
|
||||||
|
"fileName": "clip.mp4",
|
||||||
|
"fileSize": 123456789,
|
||||||
|
"mimeType": "video/mp4",
|
||||||
|
"chunkSize": 8388608,
|
||||||
|
"totalChunks": 15
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"uploadId": "hex-token",
|
||||||
|
"fileName": "clip.mp4",
|
||||||
|
"fileSize": 123456789,
|
||||||
|
"chunkSize": 8388608,
|
||||||
|
"totalChunks": 15,
|
||||||
|
"uploadedChunks": 3,
|
||||||
|
"progress": 20
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Upload Status
|
||||||
|
|
||||||
|
- GET /api/admin/media/uploads/{uploadId}
|
||||||
|
|
||||||
|
Returns same status envelope as initialize.
|
||||||
|
|
||||||
|
### Upload Chunk
|
||||||
|
|
||||||
|
- PUT /api/admin/media/uploads/{uploadId}/chunk?index={chunkIndex}
|
||||||
|
- Content-Type: application/octet-stream
|
||||||
|
|
||||||
|
Response returns updated upload status envelope.
|
||||||
|
|
||||||
|
### Complete Upload
|
||||||
|
|
||||||
|
- POST /api/admin/media/uploads/{uploadId}/complete
|
||||||
|
|
||||||
|
On success returns admin media listing payload (files + generatedAt).
|
||||||
|
|
||||||
|
## Metrics and Health
|
||||||
|
|
||||||
|
### Chat metrics
|
||||||
|
|
||||||
|
- GET /metrics
|
||||||
|
|
||||||
|
Prometheus exposition includes connected clients, stored messages, moderation actions, Redis indicators, active admin sessions, and build info.
|
||||||
|
|
||||||
|
### Health
|
||||||
|
|
||||||
|
- GET /health on chat service
|
||||||
|
- GET /health on playout service
|
||||||
|
- GET /health on nginx reverse proxy
|
||||||
|
|
||||||
|
## HTTP Status Conventions
|
||||||
|
|
||||||
|
- 200/201: successful request
|
||||||
|
- 400: malformed payload, invalid input, missing required fields
|
||||||
|
- 401: unauthorized admin request
|
||||||
|
- 404: not found
|
||||||
|
- 405: method not allowed
|
||||||
|
- 409: logical conflict (for example, mismatched resumed upload)
|
||||||
|
- 413: payload too large
|
||||||
|
- 500: internal server error
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
- Added a dedicated plain TypeScript admin module for tab navigation, media CRUD actions, schedule/system analytics refresh, and moderation workflows without Alpine dependencies.
|
- Added a dedicated plain TypeScript admin module for tab navigation, media CRUD actions, schedule/system analytics refresh, and moderation workflows without Alpine dependencies.
|
||||||
- Added resumable chunked admin media upload flow with upload-session endpoints and client progress indicators.
|
- Added resumable chunked admin media upload flow with upload-session endpoints and client progress indicators.
|
||||||
- Expanded architecture documentation with scaling strategy, API surface reference, detailed video normalization spec, and Cloudflare configuration reference.
|
- Expanded architecture documentation with scaling strategy, API surface reference, detailed video normalization spec, and Cloudflare configuration reference.
|
||||||
|
- Added `API.md`, `DEPLOYMENT.md`, `MONITORING.md`, and `SECURITY.md` as dedicated operational documentation guides.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
- Switched the frontend theme to dark-mode-first token defaults with a light-scheme override path for users who prefer light appearance.
|
- Switched the frontend theme to dark-mode-first token defaults with a light-scheme override path for users who prefer light appearance.
|
||||||
- Refactored the viewer page to a single header plus unified content layout with responsive video/chat split, mobile stacking, and chat panel toggle behavior.
|
- Refactored the viewer page to a single header plus unified content layout with responsive video/chat split, mobile stacking, and chat panel toggle behavior.
|
||||||
- Code-split `hls.js` via lazy loading in the viewer bootstrap to shrink the main frontend bundle and isolate stream playback logic into a dedicated chunk.
|
- Code-split `hls.js` via lazy loading in the viewer bootstrap to shrink the main frontend bundle and isolate stream playback logic into a dedicated chunk.
|
||||||
|
- Added navigation links in root README and architecture docs to the new API, deployment, monitoring, and security guide files.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
+169
@@ -0,0 +1,169 @@
|
|||||||
|
# Production Deployment Guide
|
||||||
|
|
||||||
|
This guide describes a production-style deployment for Linear Void using Docker Compose, Gitea registry images, and Cloudflare fronting.
|
||||||
|
|
||||||
|
## Target Topology
|
||||||
|
|
||||||
|
- Host: Linux server with Docker Engine
|
||||||
|
- Reverse proxy: nginx container (linearvoid-nginx)
|
||||||
|
- Core services: playout, chat, redis, postgres
|
||||||
|
- Observability: prometheus, grafana
|
||||||
|
- CDN/edge: Cloudflare
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker Engine + Docker Compose plugin
|
||||||
|
- Network access to git.allucanget.biz
|
||||||
|
- A valid .env file with production values
|
||||||
|
- DNS configured for linearvoid.tv (and media.linearvoid.tv if split media domain is used)
|
||||||
|
|
||||||
|
## Environment File
|
||||||
|
|
||||||
|
Use .env with at least:
|
||||||
|
|
||||||
|
- CI_REGISTRY_URL
|
||||||
|
- CI_REGISTRY_NAMESPACE
|
||||||
|
- CHAT_PORT
|
||||||
|
- NGINX_PORT
|
||||||
|
- DATABASE_URL (if overridden)
|
||||||
|
- REDIS_URL (if overridden)
|
||||||
|
- ADMIN_USERNAME
|
||||||
|
- ADMIN_PASSWORD
|
||||||
|
- VITE_PUBLIC_APP_URL
|
||||||
|
- VITE_PUBLIC_WS_URL
|
||||||
|
- VITE_PUBLIC_HLS_URL
|
||||||
|
- Cloudflare/R2 variables when media sync is enabled
|
||||||
|
|
||||||
|
See .env.example and SETUP.md for full variable reference.
|
||||||
|
|
||||||
|
## Pull-and-Run Deployment
|
||||||
|
|
||||||
|
From repository root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker login git.allucanget.biz
|
||||||
|
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
||||||
|
```
|
||||||
|
|
||||||
|
## First-Time or Recovery Provisioning
|
||||||
|
|
||||||
|
1. Ensure host paths exist:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p data/chat data/playlist data/media data/hls
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Confirm volumes and networks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume ls
|
||||||
|
docker network ls
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Start stack:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Health Verification
|
||||||
|
|
||||||
|
After startup, check service status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
Endpoint checks:
|
||||||
|
|
||||||
|
- App: <http://{host}:8080/>
|
||||||
|
- Nginx health: <http://{host}:8080/health>
|
||||||
|
- Chat health: <http://{host}:3000/health>
|
||||||
|
- Playout health: <http://{host}:8081/health>
|
||||||
|
- Prometheus: <http://{host}:9090>
|
||||||
|
- Grafana: <http://{host}:3001>
|
||||||
|
|
||||||
|
Domain checks:
|
||||||
|
|
||||||
|
- <https://linearvoid.tv>
|
||||||
|
- <https://linearvoid.tv/admin>
|
||||||
|
- <https://linearvoid.tv/metrics>
|
||||||
|
|
||||||
|
## Zero/Low-Downtime Update Pattern
|
||||||
|
|
||||||
|
1. Pull newest images.
|
||||||
|
1. Recreate changed services only:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
|
||||||
|
docker compose -f docker-compose.prod.yml up -d nginx chat playout
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Re-run health checks.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
If new images are unhealthy:
|
||||||
|
|
||||||
|
1. Pin previous tags in docker-compose.prod.yml.
|
||||||
|
2. Pull pinned tags.
|
||||||
|
3. Restart impacted services.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
|
||||||
|
docker compose -f docker-compose.prod.yml up -d nginx chat playout
|
||||||
|
```
|
||||||
|
|
||||||
|
## Operational Tasks
|
||||||
|
|
||||||
|
### View logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml logs -f nginx chat playout
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart one service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml restart chat
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stop stack
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml down
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keep volumes (recommended) vs remove volumes (destructive)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# keep data
|
||||||
|
docker compose -f docker-compose.prod.yml down
|
||||||
|
|
||||||
|
# destructive (remove data)
|
||||||
|
docker compose -f docker-compose.prod.yml down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nginx and Proxy Considerations
|
||||||
|
|
||||||
|
- If an external proxy (for example Nginx Proxy Manager) fronts the stack, align request body limits with internal nginx.
|
||||||
|
- For resumable admin uploads, ensure client_max_body_size supports chunk requests in both proxy layers.
|
||||||
|
|
||||||
|
## Security Baseline
|
||||||
|
|
||||||
|
- Use strong ADMIN_PASSWORD and rotate regularly.
|
||||||
|
- Keep Docker host access restricted.
|
||||||
|
- Prefer HTTPS/WSS through Cloudflare.
|
||||||
|
- Restrict exposed ports if only proxy access is needed.
|
||||||
|
|
||||||
|
## Common Deployment Pitfalls
|
||||||
|
|
||||||
|
- Missing frontend build artifacts in local-only compose workflows.
|
||||||
|
- Wrong registry credentials or missing login.
|
||||||
|
- Misaligned domain env vars (app/ws/hls) causing mixed-origin errors.
|
||||||
|
- Proxy-layer body size limits returning 413 on upload.
|
||||||
|
- Health checks failing before service warmup is complete.
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
# Monitoring Guide
|
||||||
|
|
||||||
|
This guide covers Prometheus and Grafana setup for Linear Void.
|
||||||
|
|
||||||
|
## Current Monitoring Components
|
||||||
|
|
||||||
|
- Prometheus container: linearvoid-prometheus
|
||||||
|
- Grafana container: linearvoid-grafana
|
||||||
|
- Metrics target: chat service /metrics
|
||||||
|
- Base scrape config: monitoring/prometheus/prometheus.yml
|
||||||
|
|
||||||
|
## Prometheus Configuration
|
||||||
|
|
||||||
|
Current scrape config:
|
||||||
|
|
||||||
|
- Job chat -> chat:3000
|
||||||
|
- Job prometheus -> prometheus:9090
|
||||||
|
- Global scrape interval: 15s
|
||||||
|
|
||||||
|
File:
|
||||||
|
|
||||||
|
- monitoring/prometheus/prometheus.yml
|
||||||
|
|
||||||
|
## Start Monitoring Stack
|
||||||
|
|
||||||
|
With compose stack up:
|
||||||
|
|
||||||
|
- Prometheus UI: <http://localhost:9090>
|
||||||
|
- Grafana UI: <http://localhost:3001>
|
||||||
|
|
||||||
|
Compose services include prometheus and grafana in both docker-compose.yml and docker-compose.prod.yml.
|
||||||
|
|
||||||
|
## Grafana Provisioning
|
||||||
|
|
||||||
|
Current mount paths:
|
||||||
|
|
||||||
|
- Dashboards directory: monitoring/grafana/dashboards
|
||||||
|
- Datasources directory: monitoring/grafana/datasources
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- The dashboards directory includes a Prometheus overview dashboard file.
|
||||||
|
- Datasource provisioning can be done with a YAML file in monitoring/grafana/datasources, or by configuring a datasource in Grafana UI.
|
||||||
|
|
||||||
|
Example datasource provisioning file (create if needed):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
|
isDefault: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dashboard References
|
||||||
|
|
||||||
|
- Provisioned dashboard: [monitoring/grafana/dashboards/dashboard.json](monitoring/grafana/dashboards/dashboard.json)
|
||||||
|
- Root dashboard snapshot: [monitoring/grafana/dashboard.json](monitoring/grafana/dashboard.json)
|
||||||
|
|
||||||
|
Grafana screenshot:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Key Metrics to Track
|
||||||
|
|
||||||
|
### Chat/Application
|
||||||
|
|
||||||
|
- linearvoid_chat_connected_clients
|
||||||
|
- linearvoid_chat_stored_messages_total
|
||||||
|
- linearvoid_chat_moderation_actions_total
|
||||||
|
- linearvoid_chat_redis_enabled
|
||||||
|
- linearvoid_chat_redis_up
|
||||||
|
- linearvoid_chat_active_admin_sessions
|
||||||
|
|
||||||
|
### Prometheus Runtime
|
||||||
|
|
||||||
|
- up
|
||||||
|
- process_cpu_seconds_total
|
||||||
|
- process_resident_memory_bytes
|
||||||
|
- prometheus_tsdb_head_series
|
||||||
|
- prometheus_tsdb_wal_writes_failed_total
|
||||||
|
- prometheus_tsdb_compactions_failed_total
|
||||||
|
|
||||||
|
## Suggested Alerts
|
||||||
|
|
||||||
|
Create a Prometheus rules file (for example monitoring/prometheus/alerts.yml) and wire it into Prometheus.
|
||||||
|
|
||||||
|
Recommended baseline alerts:
|
||||||
|
|
||||||
|
- Chat target down for 2m
|
||||||
|
- Prometheus target down for 2m
|
||||||
|
- Redis indicator down for 2m
|
||||||
|
- TSDB WAL/compaction failure rate above zero
|
||||||
|
- Elevated handler/query latency p99
|
||||||
|
|
||||||
|
## Validate Monitoring End-to-End
|
||||||
|
|
||||||
|
1. Verify /metrics through nginx:
|
||||||
|
|
||||||
|
- <https://linearvoid.tv/metrics>
|
||||||
|
|
||||||
|
1. Confirm targets in Prometheus:
|
||||||
|
|
||||||
|
- Status -> Targets page in Prometheus UI
|
||||||
|
|
||||||
|
1. Confirm dashboard data in Grafana:
|
||||||
|
|
||||||
|
- Import or open provisioned dashboards
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### No chat metrics in Prometheus
|
||||||
|
|
||||||
|
- Check chat container health and logs.
|
||||||
|
- Confirm /metrics is reachable from Prometheus container.
|
||||||
|
- Verify scrape target is chat:3000 in prometheus.yml.
|
||||||
|
|
||||||
|
### Grafana shows no data
|
||||||
|
|
||||||
|
- Ensure datasource points to <http://prometheus:9090>.
|
||||||
|
- Confirm Prometheus is healthy.
|
||||||
|
- Check dashboard query labels match active jobs.
|
||||||
|
|
||||||
|
### High cardinality or query slowness
|
||||||
|
|
||||||
|
- Reduce unneeded labels.
|
||||||
|
- Limit expensive dashboard panels.
|
||||||
|
- Tune retention and query windows.
|
||||||
|
|
||||||
|
## Operational Recommendations
|
||||||
|
|
||||||
|
- Keep alert thresholds tied to actual user impact.
|
||||||
|
- Review dashboards after each release that changes endpoints or metrics names.
|
||||||
|
- Periodically test alert routing and incident response flow.
|
||||||
@@ -204,6 +204,10 @@ Contributions, issues, and further evolution (LL-HLS, ABR, multi-channel, E2EE)
|
|||||||
- [CHANGELOG.md](CHANGELOG.md) - Version history and completed features.
|
- [CHANGELOG.md](CHANGELOG.md) - Version history and completed features.
|
||||||
- [CONTRIBUTING.md](CONTRIBUTING.md) - Guidelines for contributing to the project.
|
- [CONTRIBUTING.md](CONTRIBUTING.md) - Guidelines for contributing to the project.
|
||||||
- [SETUP.md](SETUP.md) - Complete setup guide with prerequisites, environment configuration, running the application, and troubleshooting.
|
- [SETUP.md](SETUP.md) - Complete setup guide with prerequisites, environment configuration, running the application, and troubleshooting.
|
||||||
|
- [API.md](API.md) - Implemented WebSocket and REST API reference.
|
||||||
|
- [DEPLOYMENT.md](DEPLOYMENT.md) - Production deployment and operations guide.
|
||||||
|
- [MONITORING.md](MONITORING.md) - Prometheus and Grafana setup and troubleshooting.
|
||||||
|
- [SECURITY.md](SECURITY.md) - Security controls, hardening checklist, and incident baseline.
|
||||||
- [Architecture Documentation](docs/architecture/README.md) - Full arc42 template with diagrams and decisions.
|
- [Architecture Documentation](docs/architecture/README.md) - Full arc42 template with diagrams and decisions.
|
||||||
- [ADRs](docs/architecture/adr/) - Detailed decision records (ADR-001 to ADR-007).
|
- [ADRs](docs/architecture/adr/) - Detailed decision records (ADR-001 to ADR-007).
|
||||||
|
|
||||||
|
|||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
# Security Guide
|
||||||
|
|
||||||
|
This document summarizes security controls and best practices for Linear Void.
|
||||||
|
|
||||||
|
## Security Model Overview
|
||||||
|
|
||||||
|
Security is layered across:
|
||||||
|
|
||||||
|
- Cloudflare edge
|
||||||
|
- nginx reverse proxy
|
||||||
|
- chat/admin backend
|
||||||
|
- container and host operations
|
||||||
|
|
||||||
|
## Authentication and Sessions
|
||||||
|
|
||||||
|
Admin access is session-cookie based.
|
||||||
|
|
||||||
|
- Login endpoint: /api/admin/login
|
||||||
|
- Session endpoint: /api/admin/session
|
||||||
|
- Logout endpoint: /api/admin/logout
|
||||||
|
- Cookie: linearvoid_admin_session
|
||||||
|
- Cookie flags: HttpOnly, SameSite=Strict, Secure over HTTPS
|
||||||
|
- Session expiry enforced server-side
|
||||||
|
|
||||||
|
Best practices:
|
||||||
|
|
||||||
|
- Set strong ADMIN_USERNAME and ADMIN_PASSWORD values.
|
||||||
|
- Rotate admin credentials periodically.
|
||||||
|
- Keep ADMIN_SESSION_TTL_HOURS aligned with operational policy.
|
||||||
|
|
||||||
|
## Transport Security
|
||||||
|
|
||||||
|
- Enforce HTTPS for app/admin endpoints.
|
||||||
|
- Use WSS for chat WebSocket.
|
||||||
|
- Keep Cloudflare TLS mode strict and valid at origin.
|
||||||
|
|
||||||
|
## Reverse Proxy Controls
|
||||||
|
|
||||||
|
nginx controls include:
|
||||||
|
|
||||||
|
- auth_request guard for /admin and /api/admin paths
|
||||||
|
- dedicated unauthorized behavior for admin API responses
|
||||||
|
- explicit websocket upgrade headers for /ws
|
||||||
|
- upload body-size limits for resumable media chunk uploads
|
||||||
|
|
||||||
|
Best practices:
|
||||||
|
|
||||||
|
- Keep proxy body-size and timeout settings aligned across all proxy layers.
|
||||||
|
- Avoid exposing backend service ports publicly unless required.
|
||||||
|
|
||||||
|
## Input Validation and Upload Safety
|
||||||
|
|
||||||
|
Server-side protections include:
|
||||||
|
|
||||||
|
- extension allow-list for media uploads
|
||||||
|
- MIME checks
|
||||||
|
- file-size ceiling (2GB)
|
||||||
|
- resumable chunk bounds and chunk-index validation
|
||||||
|
- media path safety checks on delete
|
||||||
|
|
||||||
|
Best practices:
|
||||||
|
|
||||||
|
- Keep upload chunk size bounded.
|
||||||
|
- Reject unsupported content types consistently.
|
||||||
|
- Monitor 4xx/5xx rates on upload routes.
|
||||||
|
|
||||||
|
## Rate Limiting and Abuse Controls
|
||||||
|
|
||||||
|
- Chat rate limiting uses Redis INCR + EXPIRE windows.
|
||||||
|
- Current baseline: more than 10 messages in 10 seconds is throttled.
|
||||||
|
- Moderation actions are logged for auditability.
|
||||||
|
|
||||||
|
Best practices:
|
||||||
|
|
||||||
|
- Tune thresholds by observed abuse patterns.
|
||||||
|
- Keep moderation logs reviewed and retained per policy.
|
||||||
|
|
||||||
|
## Infrastructure and Secrets
|
||||||
|
|
||||||
|
- Store secrets in .env (not in committed source).
|
||||||
|
- Use Gitea Actions secrets for CI/CD credentials and admin credentials.
|
||||||
|
- Restrict Docker host control plane exposure.
|
||||||
|
- Limit who can read deployment environment files.
|
||||||
|
|
||||||
|
## Cloudflare and Edge Security
|
||||||
|
|
||||||
|
Recommended baseline:
|
||||||
|
|
||||||
|
- WAF enabled
|
||||||
|
- Rate limits on sensitive paths
|
||||||
|
- Bot protection where appropriate
|
||||||
|
- Cache rules scoped carefully to avoid caching private/control-plane content
|
||||||
|
|
||||||
|
## Data Protection and Retention
|
||||||
|
|
||||||
|
- Persistent data: postgres, redis append-only, chat state, playlist/media metadata
|
||||||
|
- Backup and restore drills should be periodic
|
||||||
|
- Restore procedures should be tested in isolated environments
|
||||||
|
|
||||||
|
## Logging and Monitoring for Security
|
||||||
|
|
||||||
|
Track and alert on:
|
||||||
|
|
||||||
|
- repeated failed admin login attempts
|
||||||
|
- spikes in 401 and 403 responses
|
||||||
|
- sudden upload errors (413/400/500 patterns)
|
||||||
|
- unusual websocket disconnect or message-rate anomalies
|
||||||
|
|
||||||
|
## Hardening Checklist
|
||||||
|
|
||||||
|
- [ ] HTTPS/WSS enforced end-to-end
|
||||||
|
- [ ] Strong admin credentials configured
|
||||||
|
- [ ] Secrets only in env/secrets stores
|
||||||
|
- [ ] Proxy auth and websocket headers validated
|
||||||
|
- [ ] Upload limits and validation active
|
||||||
|
- [ ] Rate limiting active and tested
|
||||||
|
- [ ] Cloudflare WAF/rate-limit rules active
|
||||||
|
- [ ] Backup/restore drills completed
|
||||||
|
- [ ] Security-related monitoring alerts routed
|
||||||
|
|
||||||
|
## Incident Response Baseline
|
||||||
|
|
||||||
|
1. Detect issue (alerts/logs/user reports).
|
||||||
|
2. Triage scope (edge, proxy, app, data plane).
|
||||||
|
3. Contain impact (rate limit, credential rotate, route disable).
|
||||||
|
4. Recover services and verify health.
|
||||||
|
5. Record timeline and corrective actions.
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Introduction and Goals](#introduction-and-goals)
|
- [Introduction and Goals](#introduction-and-goals)
|
||||||
|
- [Companion Documentation](#companion-documentation)
|
||||||
- [Architecture Constraints](#architecture-constraints)
|
- [Architecture Constraints](#architecture-constraints)
|
||||||
- [Context and Scope](#context-and-scope)
|
- [Context and Scope](#context-and-scope)
|
||||||
- [Solution Strategy](#solution-strategy)
|
- [Solution Strategy](#solution-strategy)
|
||||||
@@ -17,6 +18,13 @@
|
|||||||
- [Risks and Technical Debts](#risks-and-technical-debts)
|
- [Risks and Technical Debts](#risks-and-technical-debts)
|
||||||
- [Glossary](#glossary)
|
- [Glossary](#glossary)
|
||||||
|
|
||||||
|
## Companion Documentation
|
||||||
|
|
||||||
|
- [API.md](../../API.md) - Implemented WebSocket and REST API reference.
|
||||||
|
- [DEPLOYMENT.md](../../DEPLOYMENT.md) - Production deployment and operational runbook.
|
||||||
|
- [MONITORING.md](../../MONITORING.md) - Metrics, dashboards, and monitoring troubleshooting.
|
||||||
|
- [SECURITY.md](../../SECURITY.md) - Security model, controls, and hardening baseline.
|
||||||
|
|
||||||
## Introduction and Goals
|
## Introduction and Goals
|
||||||
|
|
||||||
### Requirements Overview
|
### Requirements Overview
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 284 KiB |
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user