-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.postgres.sql
More file actions
executable file
·71 lines (63 loc) · 2.55 KB
/
Copy pathschema.postgres.sql
File metadata and controls
executable file
·71 lines (63 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
-- APEX schema (PostgreSQL — production).
-- Functionally identical to the SQLite dev schema; uses native types,
-- JSONB, and constraints suited to Postgres.
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- gen_random_uuid()
CREATE TYPE difficulty_t AS ENUM ('Easy', 'Medium', 'Hard');
CREATE TYPE quest_status_t AS ENUM ('active', 'completed', 'skipped', 'expired');
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email CITEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
display_name TEXT,
xp INTEGER NOT NULL DEFAULT 0,
level INTEGER NOT NULL DEFAULT 1,
interests JSONB NOT NULL DEFAULT '[]',
difficulty difficulty_t NOT NULL DEFAULT 'Easy',
location TEXT,
age_range TEXT,
timezone TEXT NOT NULL DEFAULT 'UTC',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE quest_templates (
id TEXT PRIMARY KEY,
category TEXT NOT NULL,
pattern TEXT NOT NULL,
title_hint TEXT NOT NULL,
variables JSONB NOT NULL,
difficulty difficulty_t NOT NULL,
est_minutes INTEGER NOT NULL CHECK (est_minutes BETWEEN 5 AND 60),
requires_photo BOOLEAN NOT NULL DEFAULT FALSE,
indoor_ok BOOLEAN NOT NULL DEFAULT TRUE,
min_age_range TEXT,
active BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE quests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
template_id TEXT NOT NULL REFERENCES quest_templates(id),
quest_date DATE NOT NULL,
title TEXT NOT NULL,
description TEXT NOT NULL,
category TEXT NOT NULL,
difficulty difficulty_t NOT NULL,
xp_reward INTEGER NOT NULL,
est_minutes INTEGER NOT NULL,
requires_photo BOOLEAN NOT NULL DEFAULT FALSE,
variables JSONB NOT NULL DEFAULT '{}',
status quest_status_t NOT NULL DEFAULT 'active',
completed_at TIMESTAMPTZ,
photo_path TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_quests_user_date ON quests(user_id, quest_date);
CREATE INDEX idx_quests_user_status ON quests(user_id, status);
CREATE TABLE generation_runs (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
quest_date DATE NOT NULL,
quest_count INTEGER NOT NULL,
source TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (user_id, quest_date)
);
-- For the daily batch job: which users still need quests for a given date.
CREATE INDEX idx_users_timezone ON users(timezone);