First-attempt commit3a5c6e184only captured the .gitignore change; the pre-commit hook silently dropped the 343 staged moves/deletes during lint-staged's "no matching task" path. This commit re-applies the intended J1 content on top ofbec75f143(which was pushed in parallel). Uses --no-verify because: - J1 only touches .md/.json/.log/.png/binaries — zero code that would benefit from lint-staged, typecheck, or vitest - The hook demonstrated it corrupts pure-rename commits in this repo - Explicitly authorized by user for this one commit Changes (343 total: 169 deletions + 174 renames): Binaries purged (~167 MB): - veza-backend-api/{server,modern-server,encrypt_oauth_tokens,seed,seed-v2} Generated reports purged: - 9 apps/web/lint_report*.json (~32 MB) - 8 apps/web/tsc_*.{log,txt} + ts_*.log (TS error snapshots) - 3 apps/web/storybook_*.json (1375+ stored errors) - apps/web/{build_errors*,build_output,final_errors}.txt - 70 veza-backend-api/coverage*.out + coverage_groups/ (~4 MB) - 3 veza-backend-api/internal/handlers/*.bak Root cleanup: - 54 audit-*.png (visual regression baselines, ~11 MB) - 9 stale MVP-era scripts (Jan 27, hardcoded v0.101): start_{iteration,mvp,recovery}.sh, test_{mvp_endpoints,protected_endpoints,user_journey}.sh, validate_v0101.sh, verify_logs_setup.sh, gen_hash.py Session docs archived (not deleted — preserved under docs/archive/): - 78 apps/web/*.md → docs/archive/frontend-sessions-2026/ - 43 veza-backend-api/*.md → docs/archive/backend-sessions-2026/ - 53 docs/{RETROSPECTIVE_V,SMOKE_TEST_V,PLAN_V0_,V0_*_RELEASE_SCOPE, AUDIT_,PLAN_ACTION_AUDIT,REMEDIATION_PROGRESS}*.md → docs/archive/v0-history/ README.md and CONTRIBUTING.md preserved in apps/web/ and veza-backend-api/. Note: The .gitignore rules preventing recurrence were already pushed in3a5c6e184and remain in place — this commit does not modify .gitignore. Refs: AUDIT_REPORT.md §11
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
- Middleware :
internal/middleware/(auth.go, cors.go, csrf.go, rate_limiter.go) - Admin handler :
admin_handler.go - Developer page :
apps/web/src/features/developer/ - Admin pages :
apps/web/src/features/admin/ - User handler :
user_handler.go(for account deletion)
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/resolvePOST /admin/announcements,GET /announcements/activeGET /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 filtresAnnouncementsView— CRUD annonces, previewFeatureFlagsView— 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