Schema-only landing for Slice 1 of the CalDAV multi-calendar design
(docs/design-caldav-multi-calendar-2026-05-19.md). Sync engine NOT
touched — Slice 2 wires the per-binding fan-out. After this migration:
- paliad.user_calendar_bindings — N bindings per user with scope_kind
∈ {all_visible, personal_only, project, client, litigation, patent,
case}. Hierarchy scopes anchor scope_id at paliad.projects(id).
Partial unique indexes enforce one binding per (user, scope_kind,
scope_id) for hierarchical scopes and one per (user, scope_kind)
for the scope-less roots. RLS mirrors user_caldav_config.
- paliad.appointment_caldav_targets — per-(appointment, binding) join
carrying caldav_uid + caldav_etag. UID stays canonical per
appointment so the same event in N cals shares one UID.
- Backfill — one all_visible binding per existing user_caldav_config
row, one target row per appointment already pushed. Maps target to
the creator's binding, matching today's Phase F semantics where the
creator's goroutine owns the etag.
Legacy paliad.appointments.caldav_uid / caldav_etag columns are
untouched (kept as denormalised pointers through Slice 1+2; dropped
in Slice 4 after telemetry).
Dry-run verified against live Supabase (PG 15.8): synthetic config +
appointment backfill creates exactly 1 binding + 1 target; re-run is a
no-op; all CHECK + unique-index constraints enforce as designed; final
assertions pass with 0 missing rows.
Prod impact at landing: 0 rows in user_caldav_config and 0 appointments
with caldav_uid — backfill is a true no-op. Slice 1 ships invisible.
14 lines
621 B
SQL
14 lines
621 B
SQL
-- Reverse of 101_caldav_multi_calendar.up.sql.
|
|
--
|
|
-- Drop the new join + binding tables. CASCADE on the FK references
|
|
-- isn't needed because we drop targets before bindings, and Postgres
|
|
-- handles RLS policies / indexes automatically on DROP TABLE.
|
|
--
|
|
-- The legacy paliad.appointments.caldav_uid / caldav_etag columns are
|
|
-- untouched by the up migration, so they're untouched here too —
|
|
-- rollback returns the system to the pre-Slice-1 state where those
|
|
-- scalars are the single source of CalDAV truth.
|
|
|
|
DROP TABLE IF EXISTS paliad.appointment_caldav_targets;
|
|
DROP TABLE IF EXISTS paliad.user_calendar_bindings;
|