CREATE EXTENSION IF NOT EXISTS postgis; CREATE TABLE IF NOT EXISTS marine_features ( id bigserial PRIMARY KEY, layer text NOT NULL CHECK (layer IN ('seamarks', 'bridges', 'locks', 'harbours', 'waterways', 'fairways')), source text NOT NULL DEFAULT 'manual', source_id text, name text, properties jsonb NOT NULL DEFAULT '{}'::jsonb, geom geometry(Geometry, 4326) NOT NULL, updated_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS marine_features_geom_idx ON marine_features USING gist (geom); CREATE INDEX IF NOT EXISTS marine_features_layer_idx ON marine_features (layer); CREATE INDEX IF NOT EXISTS marine_features_properties_idx ON marine_features USING gin (properties); CREATE UNIQUE INDEX IF NOT EXISTS marine_features_source_layer_uidx ON marine_features (source, source_id, layer) WHERE source_id IS NOT NULL; CREATE TABLE IF NOT EXISTS marine_enrichment_attempts ( id bigserial PRIMARY KEY, layer text NOT NULL CHECK (layer IN ('locks', 'harbours')), original_source text NOT NULL, original_source_id text NOT NULL, provider text NOT NULL, query_fingerprint text NOT NULL, query text, status text NOT NULL CHECK ( status IN ( 'success', 'no_match', 'ambiguous', 'no_contacts', 'fetch_failed', 'provider_blocked', 'invalid_candidate' ) ), result_url text, details jsonb NOT NULL DEFAULT '{}'::jsonb, attempted_at timestamptz NOT NULL DEFAULT now(), retry_after timestamptz, UNIQUE (layer, original_source, original_source_id, provider, query_fingerprint) ); CREATE INDEX IF NOT EXISTS marine_enrichment_attempts_retry_idx ON marine_enrichment_attempts (provider, retry_after); CREATE TABLE IF NOT EXISTS marine_fairway_edges ( id bigserial PRIMARY KEY, source text NOT NULL DEFAULT 'osm', source_id text, name text, min_depth_m numeric, properties jsonb NOT NULL DEFAULT '{}'::jsonb, geom geometry(LineString, 4326) NOT NULL, updated_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS marine_fairway_edges_geom_idx ON marine_fairway_edges USING gist (geom); CREATE INDEX IF NOT EXISTS marine_fairway_edges_source_idx ON marine_fairway_edges (source, source_id); CREATE UNIQUE INDEX IF NOT EXISTS marine_fairway_edges_source_uidx ON marine_fairway_edges (source, source_id) WHERE source_id IS NOT NULL; CREATE OR REPLACE VIEW marine_features_mvt AS SELECT id, layer, source, name, properties, geom FROM marine_features;