Files
paliad/internal/services
m fca7143244 feat(t-paliad-089): admin Event-Type moderation panel
Q6 of t-paliad-088 left firm-wide event_type creation open to any user; this
ships the moderation surface admins use to dedupe and clean up the resulting
drift.

Service layer (internal/services/event_type_service.go):
- ListAllForAdmin(filter) — firm-wide rows with usage_count and
  author_display_name, optionally including archived (single query, scalar
  subquery + LEFT JOIN paliad.users). Sorted live-first, then category +
  label_de.
- ListPrivatePendingPromotion — every private non-archived row across all
  users, sorted by usage_count DESC.
- ArchiveBulk(ids) — UPDATE archived_at=now() WHERE is_firm_wide AND NULL.
- Promote(id) — flip is_firm_wide=true; surfaces ErrEventTypeSlugTaken on
  collision so the admin can merge instead.
- Restore(id) — flip archived_at back to NULL; same slug-collision surface.
- MergeIDs(winner, losers) — tx-scoped INSERT … SELECT … ON CONFLICT
  redirect of deadline_event_types from losers → winner, then DELETE on the
  loser junction rows, then archive the losers. Refuses if the winner is
  archived or private. Junction PK does the dedup.
- requireAdmin gate runs at every method (defence-in-depth on top of the
  handler-level RequireAdminFunc).

Handlers (internal/handlers/admin_event_types.go):
- GET /api/admin/event-types[?include_archived=1]
- GET /api/admin/event-types/private
- POST /api/admin/event-types/archive { ids:[…] }
- POST /api/admin/event-types/merge { winner_id, loser_ids:[…] }
- POST /api/admin/event-types/{id}/promote
- POST /api/admin/event-types/{id}/restore
- GET /admin/event-types page shell.
All wrapped behind auth.RequireAdminFunc at registration time.

Frontend:
- New /admin/event-types SPA (admin-event-types.tsx + client/admin-event-types.ts):
  search, "Archivierte anzeigen" toggle, per-row archive/restore, bulk
  archive, merge modal (winner picker defaults to highest-usage row),
  separate table for private types pending promotion.
- Sidebar entry under Verwaltung; admin landing card.
- ~50 i18n keys DE+EN under admin.event_types.* + nav.admin.event_types.
- CSS for archived badge, merge option list, bulk-actions bar.

Out of scope (deferred): public "merge request" workflow for non-admins.
2026-04-30 16:37:48 +02:00
..