tasq/supabase/migrations/20260306090400_live_positions.sql

86 lines
2.9 KiB
PL/PgSQL

-- Live position tracking for whereabouts map
CREATE TABLE IF NOT EXISTS live_positions (
user_id uuid PRIMARY KEY REFERENCES auth.users(id),
lat double precision NOT NULL,
lng double precision NOT NULL,
updated_at timestamptz NOT NULL DEFAULT now(),
in_premise boolean NOT NULL DEFAULT false
);
-- Enable realtime
ALTER PUBLICATION supabase_realtime ADD TABLE live_positions;
-- RLS
ALTER TABLE live_positions ENABLE ROW LEVEL SECURITY;
-- All authenticated users can read live positions
CREATE POLICY "live_positions_select" ON live_positions FOR SELECT TO authenticated
USING (true);
-- Users can only upsert their own position
CREATE POLICY "live_positions_insert" ON live_positions FOR INSERT TO authenticated
WITH CHECK (user_id = auth.uid());
CREATE POLICY "live_positions_update" ON live_positions FOR UPDATE TO authenticated
USING (user_id = auth.uid());
-- RPC: update_live_position — upserts position, computes in_premise via geofence
CREATE OR REPLACE FUNCTION public.update_live_position(
p_lat double precision,
p_lng double precision
) RETURNS boolean
LANGUAGE plpgsql SECURITY DEFINER
AS $$
DECLARE
v_geofence jsonb;
v_in_premise boolean := false;
v_polygon jsonb;
v_point_count int;
v_i int;
v_j int;
v_xi double precision;
v_yi double precision;
v_xj double precision;
v_yj double precision;
v_inside boolean := false;
BEGIN
-- Fetch geofence config
SELECT value INTO v_geofence FROM app_settings WHERE key = 'geofence';
IF v_geofence IS NOT NULL THEN
v_polygon := COALESCE(v_geofence->'polygon', v_geofence->'points');
IF v_polygon IS NOT NULL AND jsonb_array_length(v_polygon) > 2 THEN
-- Ray-casting point-in-polygon
v_point_count := jsonb_array_length(v_polygon);
v_j := v_point_count - 1;
FOR v_i IN 0..(v_point_count - 1) LOOP
v_xi := (v_polygon->v_i->>'lng')::double precision;
v_yi := (v_polygon->v_i->>'lat')::double precision;
v_xj := (v_polygon->v_j->>'lng')::double precision;
v_yj := (v_polygon->v_j->>'lat')::double precision;
IF ((v_yi > p_lat) != (v_yj > p_lat)) AND
(p_lng < (v_xj - v_xi) * (p_lat - v_yi) / (v_yj - v_yi) + v_xi) THEN
v_inside := NOT v_inside;
END IF;
v_j := v_i;
END LOOP;
v_in_premise := v_inside;
END IF;
END IF;
INSERT INTO live_positions (user_id, lat, lng, updated_at, in_premise)
VALUES (auth.uid(), p_lat, p_lng, now(), v_in_premise)
ON CONFLICT (user_id)
DO UPDATE SET lat = p_lat, lng = p_lng, updated_at = now(), in_premise = v_in_premise;
RETURN v_in_premise;
END;
$$;
-- Update the duty_schedules RLS to allow all authenticated users to SELECT
-- (previously only admin/dispatcher could see all; now all roles can see all schedules)
DROP POLICY IF EXISTS "duty_schedules_select" ON duty_schedules;
CREATE POLICY "duty_schedules_select" ON duty_schedules FOR SELECT TO authenticated
USING (true);