# Plan d'implémentation v0.803 — Sécurité, Compliance & Outillage Dev **Statut** : Terminé **Date de création** : 2026-02-25 **Estimation révisée** : ~2 sprints (10 jours ouvrés) — réduit car beaucoup de features déjà partiellement implémentées --- ## Audit du code existant (gap analysis réel) | Feature | Backend | Frontend | Tests | Gap réel | |---------|---------|----------|-------|----------| | Security headers (CSP, HSTS, etc.) | ✅ `security_headers.go` (118L) | — | ✅ `security_headers_test.go` | **DONE** — rien à faire | | Rate limiting per-IP/user | ✅ `rate_limiter.go` (475L) + `endpoint_limiter.go` (352L) | — | ✅ | Ajouter global limit (1000/s) | | Audit logs (table, service, handler) | ✅ migration 910, `handlers/audit.go` (588L), routes `/audit/*` + `/admin/audit/*` | ✅ `AdminAuditLogsView.tsx` | ✅ MSW | **DONE** — rien à faire | | Audit middleware (auto-log POST/PUT/DELETE) | ❌ Absent | — | ❌ | **À CRÉER** | | Account deletion | ✅ `DELETE /users/me` dans `internal/api/user/routes.go` | ✅ `AccountSettingsDeleteCard.tsx` | ❌ | Vérifier handler, ajouter tests | | CCPA / "Do Not Sell" | ❌ Absent | ❌ | ❌ | **À CRÉER** | | OpenAPI/Swagger | ✅ Routes `/swagger/*any` dans `router.go`, swaggo importé | ✅ `SwaggerUI.tsx` dans developer | ❌ | Compléter annotations handlers | | API keys CRUD | ✅ `api_key_handler.go` (74L), model, migration 082, routes | ✅ `DeveloperDashboardView.tsx` + `CreateAPIKeyModal.tsx` | ❌ | Ajouter tests backend | | API key auth (X-API-Key) | ✅ Supporté dans `auth.go` | — | ❌ | Ajouter tests | | Moderation queue | ❌ Backend absent (frontend utilise mocks) | ✅ `AdminModerationView.tsx` (196L, connecté à `adminService`) | ❌ | **Backend + migration + connecter frontend** | | Maintenance mode | ❌ Backend absent | ⚠️ Toggle local dans `AdminSettingsView.tsx` | ❌ | **Middleware + endpoint + connecter** | | Announcements | ❌ Backend absent | ⚠️ Textarea locale dans `AdminSettingsView.tsx` | ❌ | **Backend CRUD + migration + banner + connecter** | | Feature flags UI | ❌ `features/features.go` = stub vide | ⚠️ Liste statique hardcodée dans `AdminSettingsView.tsx` | ❌ | **Backend CRUD + migration + connecter** | --- ## Fichiers existants clés - Middleware : [`internal/middleware/`](veza-backend-api/internal/middleware/) (auth.go, cors.go, csrf.go, rate_limiter.go) - Admin handler : [`admin_handler.go`](veza-backend-api/internal/handlers/admin_handler.go) - Developer page : [`apps/web/src/features/developer/`](apps/web/src/features/developer/) - Admin pages : [`apps/web/src/features/admin/`](apps/web/src/features/admin/) - User handler : [`user_handler.go`](veza-backend-api/internal/handlers/) (for account deletion) --- ## Step 1 : Security headers middleware (SEC1-01 to SEC1-03) **Fichier** : `veza-backend-api/internal/middleware/security_headers.go` (nouveau) ```go package middleware import "github.com/gin-gonic/gin" func SecurityHeaders(isProd bool) gin.HandlerFunc { return func(c *gin.Context) { c.Header("X-Content-Type-Options", "nosniff") c.Header("X-Frame-Options", "DENY") c.Header("Referrer-Policy", "strict-origin-when-cross-origin") c.Header("Permissions-Policy", "camera=(), microphone=(self), geolocation=()") c.Header("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; "+ "img-src 'self' data: https:; connect-src 'self' wss: https:; font-src 'self'") if isProd { c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") } c.Next() } } ``` Register in `internal/api/router.go` : `router.Use(middleware.SecurityHeaders(config.IsProd))` **Commit** : `feat(security): add CSP, HSTS, X-Frame-Options, security headers middleware` --- ## Step 2 : DDoS rate limiting amélioré (SEC1-04) **Fichier** : `veza-backend-api/internal/middleware/rate_limiter.go` — ajouter : - Global rate limit (1000 req/s total) - Per-IP rate limit (100 req/s) - Per-endpoint custom limits via config map **Commit** : `feat(security): enhanced DDoS rate limiting with global and per-IP limits` --- ## Step 3 : Audit logs (SEC2-01 to SEC2-04) **Fichier** : `migrations/123_audit_logs.sql` (nouveau) ```sql CREATE TABLE IF NOT EXISTS audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, action VARCHAR(100) NOT NULL, resource_type VARCHAR(100) NOT NULL, resource_id VARCHAR(255), ip_address VARCHAR(45), user_agent TEXT, metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id); CREATE INDEX idx_audit_logs_action ON audit_logs(action); CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at); ``` **Fichier** : `veza-backend-api/internal/audit/service.go` (nouveau) ```go type AuditService struct { db *gorm.DB logger *zap.Logger } func (s *AuditService) Log(ctx context.Context, entry AuditEntry) error { return s.db.Create(&entry).Error } func (s *AuditService) List(ctx context.Context, filters AuditFilters) ([]AuditEntry, int64, error) { // pagination, filters by user_id, action, date range } ``` **Fichier** : `veza-backend-api/internal/middleware/audit.go` (nouveau) — middleware qui log automatiquement POST/PUT/DELETE **Fichier** : `veza-backend-api/internal/handlers/admin_handler.go` — ajouter `GET /admin/audit-logs` **Commit** : `feat(audit): audit logs table, service, middleware, admin endpoint` --- ## Step 4 : Account deletion (SEC2-05) **Fichier** : `veza-backend-api/internal/handlers/user_handler.go` — ajouter `DELETE /users/me` : ```go func (h *UserHandler) DeleteAccount(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } // 1. Soft delete user // 2. Anonymize: username → "deleted-{uuid}", email → "deleted-{uuid}@veza.app" // 3. Delete S3 files (cloud, tracks, avatars) // 4. Revoke all sessions (delete from sessions table) // 5. Audit log: "account_deleted" RespondSuccess(c, http.StatusOK, gin.H{"message": "Account deleted"}) } ``` **Commit** : `feat(users): account deletion with data anonymization and S3 cleanup` --- ## Step 5 : OpenAPI/Swagger (DEV1-01, DEV1-02) ```bash cd veza-backend-api && go install github.com/swaggo/swag/cmd/swag@latest ``` Add swaggo annotations to key handlers (auth, marketplace, live, admin, health). Generate docs: ```bash swag init -g cmd/api/main.go -o docs/swagger ``` **Fichier** : `internal/api/routes_core.go` — ajouter route Swagger UI : ```go import ginSwagger "github.com/swaggo/gin-swagger" import swaggerFiles "github.com/swaggo/files" router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) ``` **Commit** : `feat(api): OpenAPI/Swagger annotations and Swagger UI endpoint` --- ## Step 6 : API keys (DEV1-03 to DEV1-05) **Fichier** : `migrations/124_api_keys.sql` (nouveau) ```sql CREATE TABLE IF NOT EXISTS api_keys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, key_hash VARCHAR(64) NOT NULL, name VARCHAR(100) NOT NULL, permissions JSONB DEFAULT '["read"]', last_used_at TIMESTAMPTZ, expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX idx_api_keys_hash ON api_keys(key_hash); ``` **Fichier** : `internal/handlers/developer_handler.go` — CRUD API keys (hash with SHA-256, return raw key only on create) **Fichier** : `internal/middleware/auth.go` — ajouter support `X-API-Key` header comme alternative au Bearer token **Commit** : `feat(developer): API key management with CRUD and X-API-Key auth` --- ## Step 7 : Admin — moderation, maintenance, announcements, feature flags (ADM1) **Fichier** : `migrations/125_reports_announcements.sql` (nouveau) ```sql CREATE TABLE IF NOT EXISTS reports ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), reporter_id UUID NOT NULL REFERENCES users(id), reported_user_id UUID REFERENCES users(id), content_type VARCHAR(50) NOT NULL, content_id UUID, reason TEXT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'pending', resolved_by UUID REFERENCES users(id), resolved_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS announcements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title VARCHAR(200) NOT NULL, content TEXT NOT NULL, type VARCHAR(20) NOT NULL DEFAULT 'info', is_active BOOLEAN NOT NULL DEFAULT true, starts_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), ends_at TIMESTAMPTZ, created_by UUID REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS feature_flags ( name VARCHAR(100) PRIMARY KEY, enabled BOOLEAN NOT NULL DEFAULT false, description TEXT, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); ``` **Fichier** : `internal/middleware/maintenance.go` (nouveau) — si `MAINTENANCE_MODE=true`, retourne 503 sauf /health et /admin **Fichier** : `internal/handlers/admin_handler.go` — ajouter : - `GET /admin/reports`, `POST /admin/reports/:id/resolve` - `POST /admin/announcements`, `GET /announcements/active` - `GET /admin/feature-flags`, `PUT /admin/feature-flags/:name` **Commit** : `feat(admin): moderation queue, maintenance mode, announcements, feature flags` --- ## Step 8 : Frontend admin + developer (ADM1-06, DEV1-06, DEV1-07, SEC2-07) **Frontend pages** : - `ModerationQueueView` — table signalements avec actions (dismiss, warn, ban) - `AuditLogsView` — table audit logs avec filtres - `AnnouncementsView` — CRUD annonces, preview - `FeatureFlagsView` — table avec toggles - Developer dashboard enrichi — gestion API keys, lien Swagger - Settings — page "Delete Account" avec confirmation double **Commit** : `feat(ui): admin moderation, audit logs, announcements, feature flags, delete account` --- ## Step 9 : MSW handlers + Tests **MSW** : handlers pour admin reports, audit logs, announcements, feature flags, API keys, Swagger mock **Tests** : security headers verification, audit log creation, account deletion cascade, API key auth, moderation CRUD **Commit** : `test(security,admin): unit tests for headers, audit, moderation, API keys` --- ## Step 10 : Documentation + release **Commit** : `docs: update documentation for v0.803` --- ## Step 11 : Rétrospective + archivage + tag ```bash git tag v0.803 ``` --- ## Validation finale ```bash cd veza-backend-api && go build ./... && go test ./... -v cd apps/web && npm run build # Verify: curl -I http://localhost:8080/api/v1/health | grep -i "content-security-policy" # Verify: http://localhost:8080/swagger/index.html loads git tag v0.803 ```