1. Tenant isolation bypass (CRITICAL): TenantResolver now verifies user
has access to X-Tenant-ID via user_tenants lookup before setting context.
Added VerifyAccess method to TenantLookup interface and TenantService.
2. Consolidated tenant resolution: Removed duplicate resolveTenant() from
helpers.go and tenant resolution from auth middleware. TenantResolver is
now the single source of truth. Deadlines and AI handlers use
auth.TenantFromContext() instead of direct DB queries.
3. CalDAV credential masking: tenant settings responses now mask CalDAV
passwords with "********" via maskSettingsPassword helper. Applied to
GetTenant, ListTenants, and UpdateSettings responses.
4. CORS + security headers: New middleware/security.go with CORS
(restricted to FRONTEND_ORIGIN) and security headers (X-Frame-Options,
X-Content-Type-Options, HSTS, Referrer-Policy, X-XSS-Protection).
5. Internal error leaking: All writeError(w, 500, err.Error()) replaced
with internalError() that logs via slog and returns generic "internal
error" to client. Same for jsonError in tenant handler.
6. Input validation: Max length on title (500), description (10000),
case_number (100), search (200). Pagination clamped to max 100.
Content-Disposition filename sanitized against header injection.
Regression test added for tenant access denial (403 on unauthorized
X-Tenant-ID). All existing tests pass, go vet clean.
Add two Claude API-powered endpoints:
- POST /api/ai/extract-deadlines: accepts PDF upload or JSON text, extracts
legal deadlines using Claude tool_use for structured output
- POST /api/ai/summarize-case: generates AI summary from case events/deadlines,
caches result in cases.ai_summary
New files:
- internal/services/ai_service.go: AIService with Anthropic SDK integration
- internal/handlers/ai.go: HTTP handlers for both endpoints
- internal/services/ai_service_test.go: tool schema and serialization tests
Uses anthropic-sdk-go v1.27.1 with Claude Sonnet 4.5. AI service is optional —
endpoints only registered when ANTHROPIC_API_KEY is set.