feat: handlers — Projekt/Team/Dezernat wiring (Phase 2)

- handlers/projekte.go (was akten.go): Projekt CRUD + tree ops (children,
  tree, ancestors), events cursor-paginated, parteien endpoints.
- handlers/teams.go: GET/POST/DELETE on /api/projekte/{id}/team. ListEffectiveMembers
  returns direct + inherited (annotated with inherited_from_id/title).
- handlers/dezernate.go: admin-gated CRUD for paliad.dezernate + member
  add/remove. Readable by any authenticated user.
- handlers/fristen.go, termine.go, notizen.go, checklist_instances.go updated
  to use projekt_id. Kept /api/akten/{id}/fristen|termine|notizen|checklisten
  as legacy aliases pointing at the same projekt-aware handlers.
- handlers/users.go: dropped handleListAkteEvents (superseded by
  handleListProjektEvents under /api/projekte/{id}/events).
- cmd/server/main.go: ProjektService + TeamService + DezernatService wired
  into handlers.Services. Downstream services (Parteien, Frist, Termin,
  Notiz, Checklist) take projektSvc.
- Removed obsolete internal/services/akte_service_test.go. go build/vet/test
  all clean.

Legacy /api/akten routes still resolve (handlers/JSON shape unchanged on
the GET/POST path) so frontend stays functional during the client cutover.
New /api/projekte routes live alongside.

Phase 3 (frontend tree UI, /projekte page, team tab) + Phase 4 (Dezernat
settings tab) still pending.
This commit is contained in:
m
2026-04-20 14:52:44 +02:00
parent 9aa8037193
commit cb2841fba9
11 changed files with 580 additions and 391 deletions

View File

@@ -70,7 +70,9 @@ func main() {
}
holidays := services.NewHolidayService(pool)
users := services.NewUserService(pool)
akteSvc := services.NewAkteService(pool, users)
projektSvc := services.NewProjektService(pool, users)
teamSvc := services.NewTeamService(pool, projektSvc)
dezernatSvc := services.NewDezernatService(pool, users)
rules := services.NewDeadlineRuleService(pool)
// Phase F: optional CalDAV cipher. If CALDAV_ENCRYPTION_KEY is unset
@@ -87,7 +89,7 @@ func main() {
log.Println("CalDAV encryption configured (AES-256-GCM)")
}
terminSvc := services.NewTerminService(pool, akteSvc)
terminSvc := services.NewTerminService(pool, projektSvc)
caldavSvc = services.NewCalDAVService(pool, cipher, terminSvc)
// Wire the push hook so user-driven mutations sync to the external
// calendar without waiting for the next 60-second tick.
@@ -98,9 +100,11 @@ func main() {
reminderSvc := services.NewReminderService(pool, mailSvc, users, baseURL)
svcBundle = &handlers.Services{
Akte: akteSvc,
Parteien: services.NewParteienService(pool, akteSvc),
Frist: services.NewFristService(pool, akteSvc),
Projekt: projektSvc,
Team: teamSvc,
Dezernat: dezernatSvc,
Parteien: services.NewParteienService(pool, projektSvc),
Frist: services.NewFristService(pool, projektSvc),
Termin: terminSvc,
CalDAV: caldavSvc,
Rules: rules,
@@ -108,8 +112,8 @@ func main() {
Users: users,
Fristenrechner: services.NewFristenrechnerService(rules, holidays),
Dashboard: services.NewDashboardService(pool, users),
Notiz: services.NewNotizService(pool, akteSvc, terminSvc),
ChecklistInst: services.NewChecklistInstanceService(pool, akteSvc),
Notiz: services.NewNotizService(pool, projektSvc, terminSvc),
ChecklistInst: services.NewChecklistInstanceService(pool, projektSvc),
Mail: mailSvc,
Invite: inviteSvc,
}