Add host-first environment contracts (Local vs CI vs Prod), deps-only compose, and the Profile → Portrait → deep-access mock payment slice with device identity and auto-migrate on API startup. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
3.8 KiB
SQL
106 lines
3.8 KiB
SQL
-- P1 core schema (see .ai/domain/erd.md)
|
|
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version text PRIMARY KEY,
|
|
applied_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
status varchar(32) NOT NULL DEFAULT 'active',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS device_identities (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
device_key varchar(128) NOT NULL UNIQUE,
|
|
user_id uuid NULL REFERENCES users(id),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_device_identities_user_id ON device_identities(user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS profiles (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES users(id),
|
|
relation varchar(16) NOT NULL CHECK (relation IN ('self', 'other')),
|
|
display_name varchar(64) NOT NULL DEFAULT '',
|
|
birth_date date NOT NULL,
|
|
birth_time time NULL,
|
|
birth_place varchar(128) NULL,
|
|
gender varchar(32) NULL,
|
|
relation_type varchar(32) NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles(user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS growth_reports (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES users(id),
|
|
profile_id uuid NOT NULL REFERENCES profiles(id),
|
|
type varchar(32) NOT NULL,
|
|
summary jsonb NOT NULL DEFAULT '{}',
|
|
detail jsonb NOT NULL DEFAULT '{}',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_growth_reports_user_id ON growth_reports(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_growth_reports_profile_id ON growth_reports(profile_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS memberships (
|
|
user_id uuid PRIMARY KEY REFERENCES users(id),
|
|
plan varchar(32) NOT NULL DEFAULT 'month',
|
|
status varchar(32) NOT NULL DEFAULT 'expired',
|
|
expires_at timestamptz NULL,
|
|
ask_quota_left int NOT NULL DEFAULT 0,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES users(id),
|
|
kind varchar(32) NOT NULL,
|
|
plan varchar(32) NULL,
|
|
report_id uuid NULL REFERENCES growth_reports(id),
|
|
amount_cents int NOT NULL DEFAULT 0,
|
|
status varchar(32) NOT NULL DEFAULT 'created',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders(user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS payments (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
order_id uuid NOT NULL REFERENCES orders(id),
|
|
channel varchar(32) NOT NULL DEFAULT 'mock',
|
|
status varchar(32) NOT NULL DEFAULT 'created',
|
|
raw jsonb NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_payments_order_id ON payments(order_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS deep_accesses (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES users(id),
|
|
report_id uuid NOT NULL REFERENCES growth_reports(id),
|
|
order_id uuid NOT NULL REFERENCES orders(id),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
deleted_at timestamptz NULL,
|
|
UNIQUE (user_id, report_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_deep_accesses_report_id ON deep_accesses(report_id);
|