001_init.up.sql 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. -- 001_init.up.sql
  2. -- M1 minimum-viable schema. Three tables, all tenant-scoped.
  3. -- Future migrations add: groups, group_members, sources,
  4. -- subscriptions, routing_rules, telegram_bots.
  5. --
  6. -- All tables include company_id and the per-tenant queries MUST
  7. -- filter on it. We do NOT enable RLS in v1; isolation is enforced
  8. -- in the app layer. See SPEC §4 + §22.
  9. CREATE EXTENSION IF NOT EXISTS pgcrypto;
  10. CREATE TABLE IF NOT EXISTS companies (
  11. id TEXT PRIMARY KEY,
  12. name TEXT NOT NULL,
  13. status TEXT NOT NULL DEFAULT 'active', -- active | suspended
  14. rate_limit_per_sec INTEGER NOT NULL DEFAULT 10000,
  15. created_at TIMESTAMPTZ NOT NULL DEFAULT now()
  16. );
  17. CREATE TABLE IF NOT EXISTS individuals (
  18. id TEXT PRIMARY KEY, -- individuals are global IDs, not scoped
  19. company_id TEXT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
  20. full_name TEXT NOT NULL,
  21. email TEXT,
  22. phone_e164 TEXT,
  23. locale TEXT DEFAULT 'en',
  24. tz TEXT DEFAULT 'UTC',
  25. status TEXT NOT NULL DEFAULT 'active', -- active | suspended
  26. created_at TIMESTAMPTZ NOT NULL DEFAULT now()
  27. );
  28. CREATE INDEX IF NOT EXISTS idx_individuals_company ON individuals(company_id) WHERE status = 'active';
  29. CREATE TABLE IF NOT EXISTS fcm_tokens (
  30. id BIGSERIAL PRIMARY KEY,
  31. individual_id TEXT NOT NULL REFERENCES individuals(id) ON DELETE CASCADE,
  32. token TEXT NOT NULL UNIQUE,
  33. device_id TEXT,
  34. platform TEXT NOT NULL DEFAULT 'android',
  35. locale TEXT,
  36. app_version TEXT,
  37. last_seen TIMESTAMPTZ,
  38. status TEXT NOT NULL DEFAULT 'active', -- active | unregistered
  39. created_at TIMESTAMPTZ NOT NULL DEFAULT now()
  40. );
  41. CREATE INDEX IF NOT EXISTS idx_fcm_tokens_individual ON fcm_tokens(individual_id) WHERE status = 'active';