0013_ops_console.sql 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. BEGIN;
  2. ALTER TABLE auth_sms_codes
  3. DROP CONSTRAINT IF EXISTS auth_sms_codes_client_type_check;
  4. ALTER TABLE auth_sms_codes
  5. ADD CONSTRAINT auth_sms_codes_client_type_check
  6. CHECK (client_type IN ('app', 'wechat', 'ops'));
  7. CREATE TABLE ops_roles (
  8. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  9. role_code TEXT NOT NULL UNIQUE,
  10. display_name TEXT NOT NULL,
  11. role_rank INT NOT NULL,
  12. permissions_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
  13. status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled', 'archived')),
  14. created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  15. updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
  16. );
  17. CREATE TRIGGER ops_roles_set_updated_at
  18. BEFORE UPDATE ON ops_roles
  19. FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  20. CREATE TABLE ops_users (
  21. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  22. ops_user_public_id TEXT NOT NULL UNIQUE,
  23. country_code TEXT NOT NULL,
  24. mobile TEXT NOT NULL,
  25. display_name TEXT NOT NULL,
  26. status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled', 'deleted')),
  27. last_login_at TIMESTAMPTZ,
  28. created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  29. updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  30. UNIQUE (country_code, mobile)
  31. );
  32. CREATE INDEX ops_users_mobile_idx ON ops_users(country_code, mobile);
  33. CREATE TRIGGER ops_users_set_updated_at
  34. BEFORE UPDATE ON ops_users
  35. FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  36. CREATE TABLE ops_user_roles (
  37. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  38. ops_user_id UUID NOT NULL REFERENCES ops_users(id) ON DELETE CASCADE,
  39. ops_role_id UUID NOT NULL REFERENCES ops_roles(id) ON DELETE CASCADE,
  40. status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
  41. assigned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  42. assigned_by_ops_user_id UUID REFERENCES ops_users(id) ON DELETE SET NULL,
  43. UNIQUE (ops_user_id, ops_role_id)
  44. );
  45. CREATE INDEX ops_user_roles_user_idx ON ops_user_roles(ops_user_id);
  46. CREATE INDEX ops_user_roles_role_idx ON ops_user_roles(ops_role_id);
  47. CREATE TABLE ops_refresh_tokens (
  48. id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  49. ops_user_id UUID NOT NULL REFERENCES ops_users(id) ON DELETE CASCADE,
  50. device_key TEXT,
  51. token_hash TEXT NOT NULL UNIQUE,
  52. issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  53. expires_at TIMESTAMPTZ NOT NULL,
  54. revoked_at TIMESTAMPTZ,
  55. replaced_by_token_id UUID REFERENCES ops_refresh_tokens(id) ON DELETE SET NULL
  56. );
  57. CREATE INDEX ops_refresh_tokens_user_idx ON ops_refresh_tokens(ops_user_id);
  58. CREATE INDEX ops_refresh_tokens_expires_idx ON ops_refresh_tokens(expires_at);
  59. INSERT INTO ops_roles (role_code, display_name, role_rank, permissions_jsonb)
  60. VALUES
  61. ('owner', '所有者', 100, '{"scope":"all"}'::jsonb),
  62. ('admin', '管理员', 80, '{"scope":"ops_admin"}'::jsonb),
  63. ('operator', '运维专员', 50, '{"scope":"ops_operator"}'::jsonb),
  64. ('viewer', '只读观察员', 10, '{"scope":"ops_viewer"}'::jsonb)
  65. ON CONFLICT (role_code) DO NOTHING;
  66. COMMIT;