schema / migration / 001-pos-outlets-devices-cashier

001 - POS outlets/devices + Cashier role

  • Tanggal: 2026-08-07
  • DB: mpcdb (shared Postgres — mpc-be / mpc-be-pos / mpc-admin)
  • Ringkas: Rename enum StaffRole.ReceptionistCashier; buat tabel pos_outlets + pos_devices dan seed outlet MPC-MAIN.

ALTER (jalankan di DB server)

-- Idempotent; safe to re-run.

DO $$ BEGIN
  IF EXISTS (
    SELECT 1 FROM pg_enum e
    JOIN pg_type t ON e.enumtypid = t.oid
    WHERE t.typname = 'StaffRole' AND e.enumlabel = 'Receptionist'
  ) AND NOT EXISTS (
    SELECT 1 FROM pg_enum e
    JOIN pg_type t ON e.enumtypid = t.oid
    WHERE t.typname = 'StaffRole' AND e.enumlabel = 'Cashier'
  ) THEN
    ALTER TYPE "StaffRole" RENAME VALUE 'Receptionist' TO 'Cashier';
  END IF;
END $$;

DO $$ BEGIN
  CREATE TYPE "PosOutletStatus" AS ENUM ('Active', 'Inactive');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  CREATE TYPE "PosDeviceStatus" AS ENUM ('Active', 'Revoked');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

CREATE TABLE IF NOT EXISTS pos_outlets (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  code text NOT NULL UNIQUE,
  name text NOT NULL,
  court_enabled boolean NOT NULL DEFAULT true,
  fnb_enabled boolean NOT NULL DEFAULT true,
  status "PosOutletStatus" NOT NULL DEFAULT 'Active',
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  deleted_at timestamptz
);

CREATE TABLE IF NOT EXISTS pos_devices (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  outlet_id uuid NOT NULL REFERENCES pos_outlets(id),
  name text NOT NULL,
  api_key_hash text NOT NULL,
  court_enabled boolean NOT NULL DEFAULT true,
  fnb_enabled boolean NOT NULL DEFAULT false,
  last_seen_at timestamptz,
  status "PosDeviceStatus" NOT NULL DEFAULT 'Active',
  registered_at timestamptz NOT NULL DEFAULT now(),
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  deleted_at timestamptz
);

CREATE INDEX IF NOT EXISTS pos_devices_api_key_hash_idx ON pos_devices (api_key_hash);
CREATE INDEX IF NOT EXISTS pos_devices_outlet_id_idx ON pos_devices (outlet_id);

INSERT INTO pos_outlets (code, name, court_enabled, fnb_enabled, status)
VALUES ('MPC-MAIN', 'Metropole Padel Main', true, true, 'Active')
ON CONFLICT (code) DO UPDATE SET
  name = EXCLUDED.name,
  court_enabled = EXCLUDED.court_enabled,
  fnb_enabled = EXCLUDED.fnb_enabled,
  status = EXCLUDED.status,
  updated_at = now();

Rollback (opsional tapi disarankan)

-- Hati-hati: drop devices dulu (FK). Hanya jika belum ada data produksi penting.
DROP TABLE IF EXISTS pos_devices;
DROP TABLE IF EXISTS pos_outlets;
DROP TYPE IF EXISTS "PosDeviceStatus";
DROP TYPE IF EXISTS "PosOutletStatus";

-- Rename balik hanya jika label Cashier ada dan Receptionist belum ada,
-- dan tidak ada baris staff yang masih memakai Cashier (atau update dulu).
DO $$ BEGIN
  IF EXISTS (
    SELECT 1 FROM pg_enum e
    JOIN pg_type t ON e.enumtypid = t.oid
    WHERE t.typname = 'StaffRole' AND e.enumlabel = 'Cashier'
  ) AND NOT EXISTS (
    SELECT 1 FROM pg_enum e
    JOIN pg_type t ON e.enumtypid = t.oid
    WHERE t.typname = 'StaffRole' AND e.enumlabel = 'Receptionist'
  ) THEN
    ALTER TYPE "StaffRole" RENAME VALUE 'Cashier' TO 'Receptionist';
  END IF;
END $$;

Catatan

  • Prod: sudah dijalankan lewat mpc-be-pos EnsureSchema (AUTO_MIGRATE) pada deploy 2026-08-07.
  • Duplikat SQL di mpc-be-pos/scripts/migrate_pos_devices.sql / internal/device/migrate.go — sumber kebenaran untuk ops tetap file ini.
  • Dampak: mpc-admin (Prisma PosOutlet/PosDevice, role Cashier), mpc-be-pos (device auth + JWT), mpc-pos (wizard/login).