feat: supabase schema migrations + kong gateway config
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
_format_version: "2.1"
|
||||||
|
|
||||||
|
services:
|
||||||
|
- name: postgrest
|
||||||
|
url: http://rest:3000
|
||||||
|
routes:
|
||||||
|
- name: rest-v1
|
||||||
|
paths:
|
||||||
|
- /rest/v1/
|
||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<'EOSQL'
|
||||||
|
|
||||||
|
-- Create authenticator role (no-login, used by PostgREST)
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'authenticator') THEN
|
||||||
|
CREATE ROLE authenticator NOLOGIN;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- Grant authenticator usage on public schema and read access to all tables
|
||||||
|
GRANT USAGE ON SCHEMA public TO authenticator;
|
||||||
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO authenticator;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO authenticator;
|
||||||
|
|
||||||
|
EOSQL
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- willhaben-tracker — initial schema migration
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 1. users (whitelisted Telegram users)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
telegram_id bigint UNIQUE NOT NULL,
|
||||||
|
username text,
|
||||||
|
first_name text,
|
||||||
|
is_active boolean NOT NULL DEFAULT true,
|
||||||
|
created_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 2. search_queries (saved searches per user)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS search_queries (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id uuid REFERENCES users(id) ON DELETE CASCADE NOT NULL,
|
||||||
|
keyword text NOT NULL,
|
||||||
|
interval_minutes int NOT NULL DEFAULT 60,
|
||||||
|
is_active boolean NOT NULL DEFAULT true,
|
||||||
|
last_scraped_at timestamptz,
|
||||||
|
created_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 3. ads (raw ad snapshots, globally deduplicated by wh_ad_id)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS ads (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
wh_ad_id text UNIQUE NOT NULL,
|
||||||
|
raw_json jsonb NOT NULL,
|
||||||
|
title text NOT NULL,
|
||||||
|
price numeric,
|
||||||
|
location text,
|
||||||
|
url text,
|
||||||
|
published_at timestamptz,
|
||||||
|
first_seen_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 4. query_ads (junction: which query found which ad)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS query_ads (
|
||||||
|
search_query_id uuid REFERENCES search_queries(id) ON DELETE CASCADE NOT NULL,
|
||||||
|
ad_id uuid REFERENCES ads(id) ON DELETE CASCADE NOT NULL,
|
||||||
|
first_seen_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
is_notified boolean NOT NULL DEFAULT false,
|
||||||
|
PRIMARY KEY (search_query_id, ad_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 5. notifications (audit log of sent Telegram messages)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS notifications (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id uuid REFERENCES users(id) ON DELETE CASCADE NOT NULL,
|
||||||
|
ad_id uuid REFERENCES ads(id) ON DELETE SET NULL,
|
||||||
|
message_id int,
|
||||||
|
sent_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
-- 6. scrape_logs (worker health / debugging)
|
||||||
|
-- -----------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS scrape_logs (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
search_query_id uuid REFERENCES search_queries(id) ON DELETE CASCADE NOT NULL,
|
||||||
|
status text NOT NULL CHECK (status IN ('success', 'error', 'rate_limited')),
|
||||||
|
ads_found int NOT NULL DEFAULT 0,
|
||||||
|
new_ads int NOT NULL DEFAULT 0,
|
||||||
|
error_message text,
|
||||||
|
scraped_at timestamptz NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- Indexes
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- Users: fast lookup by telegram_id (unique constraint already implies an index)
|
||||||
|
|
||||||
|
-- Search queries: user membership lookups
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_search_queries_user_id ON search_queries(user_id);
|
||||||
|
|
||||||
|
-- Scheduler polling: active queries ordered by last scraped time
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_search_queries_active_scraped
|
||||||
|
ON search_queries(is_active, last_scraped_at) WHERE is_active = true;
|
||||||
|
|
||||||
|
-- Notifier lookups: un-notified ads per query
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_query_ads_notified
|
||||||
|
ON query_ads(search_query_id, is_notified) WHERE is_notified = false;
|
||||||
|
|
||||||
|
-- Notifications: recent messages per user
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_notifications_user_sent
|
||||||
|
ON notifications(user_id, sent_at DESC);
|
||||||
|
|
||||||
|
-- Scrape logs: latest runs per query
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_scrape_logs_query_at
|
||||||
|
ON scrape_logs(search_query_id, scraped_at DESC);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- post-boot — runs after all migrations have been applied.
|
||||||
|
-- Grants INSERT/UPDATE to authenticator on user-facing tables.
|
||||||
|
-- (Run after 01-init.sql so tables exist.)
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
GRANT INSERT, UPDATE ON search_queries TO authenticator;
|
||||||
|
GRANT INSERT, UPDATE ON notifications TO authenticator;
|
||||||
Reference in New Issue
Block a user