Staff can lock a section (or the whole event) to their device, download its tickets and keep scanning with no connection. Scans are queued in IndexedDB and synced idempotently when back online; conflicts go into a sync report for supervisors, who can also force-release a lost device. The server now validates scan sections and refuses scans in a scope locked to another device. Adds a web app manifest and a service worker for the scanner page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
94 lines
3.5 KiB
SQL
94 lines
3.5 KiB
SQL
-- AlterEnum
|
|
-- This migration adds more than one value to an enum.
|
|
-- With PostgreSQL versions 11 and earlier, this is not possible
|
|
-- in a single migration. This can be worked around by creating
|
|
-- multiple migrations, each migration adding only one value to
|
|
-- the enum.
|
|
|
|
|
|
ALTER TYPE "AdminAuditAction" ADD VALUE 'scan_lock_acquired';
|
|
ALTER TYPE "AdminAuditAction" ADD VALUE 'scan_lock_released';
|
|
ALTER TYPE "AdminAuditAction" ADD VALUE 'scan_lock_force_released';
|
|
ALTER TYPE "AdminAuditAction" ADD VALUE 'offline_sync';
|
|
|
|
-- AlterTable
|
|
ALTER TABLE "TicketUsage" ADD COLUMN "clientScanId" TEXT,
|
|
ADD COLUMN "offline" BOOLEAN NOT NULL DEFAULT false,
|
|
ADD COLUMN "scanLockId" TEXT,
|
|
ADD COLUMN "syncedAt" TIMESTAMP(3);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ScanLock" (
|
|
"id" TEXT NOT NULL,
|
|
"eventId" TEXT NOT NULL,
|
|
"sectionId" TEXT,
|
|
"deviceId" TEXT NOT NULL,
|
|
"deviceName" TEXT,
|
|
"userId" TEXT NOT NULL,
|
|
"lockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"snapshotAt" TIMESTAMP(3),
|
|
"lastSyncAt" TIMESTAMP(3),
|
|
"releasedAt" TIMESTAMP(3),
|
|
"forceReleasedById" TEXT,
|
|
|
|
CONSTRAINT "ScanLock_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "OfflineSyncReport" (
|
|
"id" TEXT NOT NULL,
|
|
"scanLockId" TEXT NOT NULL,
|
|
"accepted" INTEGER NOT NULL DEFAULT 0,
|
|
"duplicates" INTEGER NOT NULL DEFAULT 0,
|
|
"conflicts" JSONB NOT NULL DEFAULT '[]',
|
|
"afterForceRelease" BOOLEAN NOT NULL DEFAULT false,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"reviewedAt" TIMESTAMP(3),
|
|
"reviewedById" TEXT,
|
|
|
|
CONSTRAINT "OfflineSyncReport_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ScanLock_eventId_releasedAt_idx" ON "ScanLock"("eventId", "releasedAt");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ScanLock_userId_idx" ON "ScanLock"("userId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ScanLock_sectionId_idx" ON "ScanLock"("sectionId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "ScanLock_forceReleasedById_idx" ON "ScanLock"("forceReleasedById");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "OfflineSyncReport_scanLockId_idx" ON "OfflineSyncReport"("scanLockId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "OfflineSyncReport_reviewedById_idx" ON "OfflineSyncReport"("reviewedById");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "TicketUsage_clientScanId_key" ON "TicketUsage"("clientScanId");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "TicketUsage" ADD CONSTRAINT "TicketUsage_scanLockId_fkey" FOREIGN KEY ("scanLockId") REFERENCES "ScanLock"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ScanLock" ADD CONSTRAINT "ScanLock_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ScanLock" ADD CONSTRAINT "ScanLock_sectionId_fkey" FOREIGN KEY ("sectionId") REFERENCES "Section"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ScanLock" ADD CONSTRAINT "ScanLock_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ScanLock" ADD CONSTRAINT "ScanLock_forceReleasedById_fkey" FOREIGN KEY ("forceReleasedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "OfflineSyncReport" ADD CONSTRAINT "OfflineSyncReport_scanLockId_fkey" FOREIGN KEY ("scanLockId") REFERENCES "ScanLock"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "OfflineSyncReport" ADD CONSTRAINT "OfflineSyncReport_reviewedById_fkey" FOREIGN KEY ("reviewedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|