huntapi/Sql/001_schema.sql
Finn Skov Henriksen d7479db902
Some checks failed
Build / Restore, build and publish (push) Failing after 2m7s
first commit
2026-08-31 12:29:23 +02:00

155 lines
5.6 KiB
SQL

CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE IF NOT EXISTS hunt_area (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL,
description text,
geom geometry(MultiPolygon, 4326),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS app_user (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
display_name text NOT NULL,
email text,
avatar_url text,
color text,
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz
);
CREATE TABLE IF NOT EXISTS user_identity (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
provider text NOT NULL,
provider_subject text NOT NULL,
email text,
email_verified boolean,
display_name text,
avatar_url text,
first_login_at timestamptz NOT NULL DEFAULT now(),
last_login_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (provider, provider_subject),
CHECK (provider IN ('google', 'microsoft', 'apple'))
);
CREATE TABLE IF NOT EXISTS hunt (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_area_id uuid NOT NULL REFERENCES hunt_area(id),
title text NOT NULL,
description text,
starts_at timestamptz,
ends_at timestamptz,
status text NOT NULL DEFAULT 'planned',
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS map_point_type (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL UNIQUE,
icon text,
color text
);
INSERT INTO map_point_type (name, icon, color) VALUES
('HuntingTower', 'tower', '#F59E0B'),
('FeedingPlace', 'corn', '#84CC16'),
('Parking', 'parking', '#3B82F6'),
('MeetingPoint', 'flag', '#22C55E'),
('Observation', 'eye', '#A855F7')
ON CONFLICT (name) DO NOTHING;
CREATE TABLE IF NOT EXISTS map_point (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_area_id uuid NOT NULL REFERENCES hunt_area(id),
type_id uuid NOT NULL REFERENCES map_point_type(id),
name text NOT NULL,
description text,
geom geometry(Point, 4326) NOT NULL,
image_url text,
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS map_zone (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_area_id uuid NOT NULL REFERENCES hunt_area(id),
name text NOT NULL,
zone_type text NOT NULL,
description text,
geom geometry(MultiPolygon, 4326) NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS hunt_area_member (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_area_id uuid NOT NULL REFERENCES hunt_area(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
role text NOT NULL DEFAULT 'member',
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (hunt_area_id, user_id)
);
CREATE TABLE IF NOT EXISTS hunt_participant (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_id uuid NOT NULL REFERENCES hunt(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES app_user(id),
role text NOT NULL DEFAULT 'hunter',
status text NOT NULL DEFAULT 'invited',
share_location boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (hunt_id, user_id)
);
CREATE TABLE IF NOT EXISTS hunt_assignment (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_id uuid NOT NULL REFERENCES hunt(id) ON DELETE CASCADE,
participant_id uuid NOT NULL REFERENCES hunt_participant(id) ON DELETE CASCADE,
map_point_id uuid NOT NULL REFERENCES map_point(id),
note text,
assigned_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (hunt_id, participant_id)
);
CREATE TABLE IF NOT EXISTS user_current_location (
participant_id uuid PRIMARY KEY REFERENCES hunt_participant(id) ON DELETE CASCADE,
geom geometry(Point, 4326) NOT NULL,
accuracy_m numeric(8,2),
speed_mps numeric(8,2),
heading_degrees numeric(6,2),
battery_percent int,
recorded_at timestamptz NOT NULL,
received_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS user_location_history (
id bigserial PRIMARY KEY,
participant_id uuid NOT NULL REFERENCES hunt_participant(id) ON DELETE CASCADE,
geom geometry(Point, 4326) NOT NULL,
accuracy_m numeric(8,2),
speed_mps numeric(8,2),
heading_degrees numeric(6,2),
battery_percent int,
recorded_at timestamptz NOT NULL,
received_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS hunt_message (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
hunt_id uuid NOT NULL REFERENCES hunt(id) ON DELETE CASCADE,
sender_participant_id uuid REFERENCES hunt_participant(id),
message text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_hunt_area_geom ON hunt_area USING gist (geom);
CREATE INDEX IF NOT EXISTS idx_map_point_geom ON map_point USING gist (geom);
CREATE INDEX IF NOT EXISTS idx_map_zone_geom ON map_zone USING gist (geom);
CREATE INDEX IF NOT EXISTS idx_user_current_location_geom ON user_current_location USING gist (geom);
CREATE INDEX IF NOT EXISTS idx_user_location_history_geom ON user_location_history USING gist (geom);
CREATE INDEX IF NOT EXISTS idx_user_location_history_participant_time ON user_location_history (participant_id, recorded_at DESC);
CREATE INDEX IF NOT EXISTS idx_hunt_participant_hunt ON hunt_participant (hunt_id);
CREATE INDEX IF NOT EXISTS idx_hunt_assignment_hunt ON hunt_assignment (hunt_id);