- Database: kanzlai.audit_log table with RLS, append-only policies
(no UPDATE/DELETE), indexes for entity, user, and time queries
- Backend: AuditService.Log() with context-based tenant/user/IP/UA
extraction, wired into all 7 services (case, deadline, appointment,
document, note, party, tenant)
- API: GET /api/audit-log with entity_type, entity_id, user_id,
from/to date, and pagination filters
- Frontend: Protokoll tab on case detail page with chronological
audit entries, diff preview, and pagination
Required by § 50 BRAO and DSGVO Art. 5(2).
- Create kanzlai.notes table (polymorphic FK with CHECK constraint,
partial indexes, RLS)
- Add Note model, NoteService (ListByParent, Create, Update, Delete),
and NoteHandler with endpoints: GET/POST /api/notes, PUT/DELETE /api/notes/{id}
- Add GET /api/deadlines/{deadlineID} detail endpoint
- Add GET /api/appointments/{id} detail endpoint
- Add GET /api/case-events/{id} detail endpoint (new CaseEventHandler)
- Fix dashboard query: add case_id to upcoming_deadlines SELECT,
add id and case_id to recent_activity SELECT
- Register all new routes in router.go
Tenant management:
- POST /api/tenants — create tenant (creator becomes owner)
- GET /api/tenants — list tenants for authenticated user
- GET /api/tenants/:id — tenant details with access check
- POST /api/tenants/:id/invite — invite user by email (owner/admin)
- DELETE /api/tenants/:id/members/:uid — remove member
- GET /api/tenants/:id/members — list members
New packages:
- internal/services/tenant_service.go — CRUD on tenants + user_tenants
- internal/handlers/tenant_handler.go — HTTP handlers with auth checks
- internal/auth/tenant_resolver.go — X-Tenant-ID header middleware,
defaults to user's first tenant for scoped routes
Authorization: owners/admins can invite and remove members. Cannot
remove the last owner. Users can remove themselves. TenantResolver
applies to resource routes (cases, deadlines, etc.) but not tenant
management routes.