feat: production hardening — slog, rate limiting, integration tests, seed data (Phase 4)

- Structured logging: replace log.* with log/slog JSON output across backend
- Request logger middleware: logs method, path, status, duration for all non-health requests
- Rate limiting: token bucket (5 req/min, burst 10) on AI endpoints (/api/ai/*)
- Integration tests: full critical path test (auth -> create case -> add deadline -> dashboard)
- Seed demo data: 1 tenant, 5 cases with deadlines/appointments/parties/events
- docker-compose.yml: add all required env vars (DATABASE_URL, SUPABASE_*, ANTHROPIC_API_KEY)
- .env.example: document all env vars including DATABASE_URL and CalDAV note
This commit is contained in:
m
2026-03-25 14:32:27 +01:00
parent b49992b9c0
commit c5c3f41e08
10 changed files with 694 additions and 17 deletions

View File

@@ -4,7 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"log/slog"
"strings"
"sync"
"time"
@@ -83,14 +83,14 @@ func (s *CalDAVService) Start() {
s.wg.Go(func() {
s.backgroundLoop()
})
log.Println("CalDAV sync service started")
slog.Info("CalDAV sync service started")
}
// Stop gracefully stops the background sync.
func (s *CalDAVService) Stop() {
close(s.stopCh)
s.wg.Wait()
log.Println("CalDAV sync service stopped")
slog.Info("CalDAV sync service stopped")
}
// backgroundLoop polls tenants at their configured interval.
@@ -113,7 +113,7 @@ func (s *CalDAVService) backgroundLoop() {
func (s *CalDAVService) syncAllTenants() {
configs, err := s.loadAllTenantConfigs()
if err != nil {
log.Printf("CalDAV: failed to load tenant configs: %v", err)
slog.Error("CalDAV: failed to load tenant configs", "error", err)
return
}
@@ -137,7 +137,7 @@ func (s *CalDAVService) syncAllTenants() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
if _, err := s.SyncTenant(ctx, tid, c); err != nil {
log.Printf("CalDAV: sync failed for tenant %s: %v", tid, err)
slog.Error("CalDAV: sync failed", "tenant_id", tid, "error", err)
}
}(tenantID, cfg)
}
@@ -649,7 +649,7 @@ func (s *CalDAVService) logConflictEvent(ctx context.Context, tenantID, caseID u
VALUES ($1, $2, $3, 'caldav_conflict', $4, $5, $6, NOW(), NOW())`,
uuid.New(), tenantID, caseID, "CalDAV sync conflict", msg, metadata)
if err != nil {
log.Printf("CalDAV: failed to log conflict event: %v", err)
slog.Error("CalDAV: failed to log conflict event", "error", err)
}
}