-- Phase 4c — tracked redirect links for email click-through tracking. -- A short URL at /q/ redirects to the target and records the -- click against the originating send. Cross-posted to Umami as a -- `link-clicked` event. CREATE TABLE IF NOT EXISTS "tracked_links" ( "id" text PRIMARY KEY, "port_id" text NOT NULL REFERENCES "ports"("id"), "slug" text NOT NULL, "target_url" text NOT NULL, "send_id" text REFERENCES "document_sends"("id") ON DELETE SET NULL, "click_count" integer NOT NULL DEFAULT 0, "first_clicked_at" timestamptz, "last_clicked_at" timestamptz, "created_at" timestamptz NOT NULL DEFAULT now(), "created_by_user_id" text REFERENCES "user"("id") ON DELETE SET NULL ); -- Slugs are scoped to a port; an admin can rotate them per-port. Global -- uniqueness isn't required because /q/ is gated by tenancy in -- the route handler. CREATE UNIQUE INDEX IF NOT EXISTS "uniq_tracked_links_slug" ON "tracked_links" ("slug"); CREATE INDEX IF NOT EXISTS "idx_tracked_links_send" ON "tracked_links" ("send_id"); CREATE INDEX IF NOT EXISTS "idx_tracked_links_port" ON "tracked_links" ("port_id", "created_at" DESC); CREATE TABLE IF NOT EXISTS "tracked_link_clicks" ( "id" text PRIMARY KEY, "tracked_link_id" text NOT NULL REFERENCES "tracked_links"("id") ON DELETE CASCADE, "port_id" text NOT NULL REFERENCES "ports"("id"), "clicked_at" timestamptz NOT NULL DEFAULT now(), "user_agent" text, "referer" text ); CREATE INDEX IF NOT EXISTS "idx_tlc_link" ON "tracked_link_clicks" ("tracked_link_id", "clicked_at" DESC); CREATE INDEX IF NOT EXISTS "idx_tlc_port" ON "tracked_link_clicks" ("port_id", "clicked_at" DESC);