-- 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);