48 lines
1.7 KiB
SQL
48 lines
1.7 KiB
SQL
|
|
CREATE TABLE users (
|
||
|
|
id text PRIMARY KEY,
|
||
|
|
wechat_identity text NOT NULL UNIQUE,
|
||
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE sessions (
|
||
|
|
token_hash text PRIMARY KEY,
|
||
|
|
user_id text NOT NULL REFERENCES users(id),
|
||
|
|
expires_at timestamptz NOT NULL
|
||
|
|
);
|
||
|
|
CREATE INDEX sessions_expiry ON sessions(expires_at);
|
||
|
|
|
||
|
|
CREATE TABLE projects (
|
||
|
|
id text PRIMARY KEY,
|
||
|
|
user_id text NOT NULL REFERENCES users(id),
|
||
|
|
name text NOT NULL CHECK (char_length(btrim(name)) BETWEEN 1 AND 40),
|
||
|
|
archived boolean NOT NULL DEFAULT false,
|
||
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
position bigint GENERATED ALWAYS AS IDENTITY,
|
||
|
|
UNIQUE (user_id, id)
|
||
|
|
);
|
||
|
|
CREATE INDEX projects_owner ON projects(user_id, position);
|
||
|
|
|
||
|
|
CREATE TABLE records (
|
||
|
|
id text PRIMARY KEY,
|
||
|
|
user_id text NOT NULL REFERENCES users(id),
|
||
|
|
project_id text NOT NULL,
|
||
|
|
practice_date date NOT NULL CHECK (practice_date >= DATE '0001-01-01'),
|
||
|
|
minutes integer NOT NULL CHECK (minutes > 0),
|
||
|
|
note text NOT NULL DEFAULT '' CHECK (char_length(note) <= 2000),
|
||
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
FOREIGN KEY (user_id, project_id) REFERENCES projects(user_id, id) ON DELETE RESTRICT
|
||
|
|
);
|
||
|
|
CREATE INDEX records_owner_date ON records(user_id, practice_date DESC, id DESC);
|
||
|
|
CREATE INDEX records_owner_updated ON records(user_id, updated_at DESC, id DESC);
|
||
|
|
CREATE INDEX records_project ON records(user_id, project_id);
|
||
|
|
|
||
|
|
-- Keep submission receipts after a record is deleted so a delayed retry cannot resurrect it.
|
||
|
|
CREATE TABLE submissions (
|
||
|
|
user_id text NOT NULL REFERENCES users(id),
|
||
|
|
request_id text NOT NULL,
|
||
|
|
payload_hash text NOT NULL,
|
||
|
|
record_id text NOT NULL,
|
||
|
|
PRIMARY KEY (user_id, request_id)
|
||
|
|
);
|