NobGit
public imalexnord read

Slot

Calendar-first scheduling powered by Cloudflare Workers and Google Calendar.

Languages

Repository composition by tracked source files.

TypeScript
TypeScript 79% CSS 19% SQL 2% HTML 0%
Create file Wiki Documentation
Clone
https://nobgit.com/user/imalexnord/slot.git
ssh://[email protected]:2222/user/imalexnord/slot.git
0005_activity.sql
CREATE TABLE IF NOT EXISTS activity_events (
  id TEXT PRIMARY KEY,
  booking_id TEXT,
  type TEXT NOT NULL,
  occurred_at TEXT NOT NULL DEFAULT (datetime('now')),
  metadata TEXT,
  idempotency_key TEXT
);

CREATE INDEX IF NOT EXISTS idx_activity_events_occurred_at
  ON activity_events(occurred_at DESC);
CREATE INDEX IF NOT EXISTS idx_activity_events_booking_id
  ON activity_events(booking_id);
CREATE UNIQUE INDEX IF NOT EXISTS idx_activity_events_idempotency_key
  ON activity_events(idempotency_key)
  WHERE idempotency_key IS NOT NULL;

-- Backfill the lifecycle points that can be reconstructed safely from existing
-- booking rows. Future changes are recorded as first-class activity events.
INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-confirmed-' || id,
  id,
  'booking_confirmed',
  created_at,
  '{"backfilled":true}',
  'booking:' || id || ':confirmed'
FROM bookings
WHERE status = 'confirmed'
   OR (status = 'cancelled' AND (payment_status <> 'cancelled' OR paid_at IS NOT NULL));

INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-paid-' || id,
  id,
  'payment_received',
  paid_at,
  '{"backfilled":true}',
  'booking:' || id || ':paid'
FROM bookings
WHERE paid_at IS NOT NULL;

INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-rescheduled-' || id,
  id,
  'booking_rescheduled',
  rescheduled_at,
  json_object('backfilled', 1, 'count', reschedule_count),
  'booking:' || id || ':reschedule-backfill'
FROM bookings
WHERE rescheduled_at IS NOT NULL AND reschedule_count > 0;

INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-suggested-' || id,
  id,
  'time_suggested',
  proposed_at,
  json_object('backfilled', 1, 'proposedStart', proposed_start_time, 'proposedEnd', proposed_end_time),
  'booking:' || id || ':suggestion-backfill'
FROM bookings
WHERE proposed_at IS NOT NULL;

INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-refunded-' || id,
  id,
  'refund_succeeded',
  refunded_at,
  json_object('backfilled', 1, 'amount', refunded_amount, 'currency', payment_currency),
  CASE WHEN stripe_refund_id IS NOT NULL THEN 'refund:' || stripe_refund_id || ':succeeded' ELSE 'booking:' || id || ':refund-backfill' END
FROM bookings
WHERE refunded_at IS NOT NULL;

INSERT OR IGNORE INTO activity_events (id, booking_id, type, occurred_at, metadata, idempotency_key)
SELECT
  'backfill-cancelled-' || id,
  id,
  CASE WHEN payment_status = 'cancelled' AND paid_at IS NULL THEN 'payment_hold_released' ELSE 'booking_cancelled' END,
  cancelled_at,
  '{"backfilled":true}',
  'booking:' || id || ':cancelled'
FROM bookings
WHERE cancelled_at IS NOT NULL;