veza/docs/PLAN_V0_803_IMPLEMENTATION.md

11 KiB

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


Step 1 : Security headers middleware (SEC1-01 to SEC1-03)

Fichier : veza-backend-api/internal/middleware/security_headers.go (nouveau)

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)

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)

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 :

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)

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:

swag init -g cmd/api/main.go -o docs/swagger

Fichier : internal/api/routes_core.go — ajouter route Swagger UI :

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)

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)

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

git tag v0.803

Validation finale

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