Changeset 0.8.0.1 (#43)
This commit is contained in:
76
server/database/migrations/016_teams.sql
Normal file
76
server/database/migrations/016_teams.sql
Normal file
@@ -0,0 +1,76 @@
|
||||
-- ==========================================
|
||||
-- Migration 016: Teams
|
||||
-- ==========================================
|
||||
-- Teams are the middle tier between system admin and individual users.
|
||||
-- A team admin can manage members, create team-scoped presets,
|
||||
-- and enforce provider policies — without system-wide access.
|
||||
-- ==========================================
|
||||
|
||||
-- ── 1. Teams table ──────────────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS teams (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(200) NOT NULL UNIQUE,
|
||||
description TEXT DEFAULT '',
|
||||
created_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
settings JSONB DEFAULT '{}'::jsonb, -- team-level policies
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_teams_active ON teams(is_active) WHERE is_active = true;
|
||||
|
||||
CREATE TRIGGER teams_updated_at BEFORE UPDATE ON teams
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
COMMENT ON TABLE teams IS 'Organizational teams with scoped administration';
|
||||
COMMENT ON COLUMN teams.settings IS 'Team policies: {"require_private_providers": false}';
|
||||
|
||||
-- ── 2. Team Members table ───────────────────
|
||||
|
||||
CREATE TABLE IF NOT EXISTS team_members (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
team_id UUID NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'member'
|
||||
CHECK (role IN ('admin', 'member')),
|
||||
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(team_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_team_members_team ON team_members(team_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_team_members_user ON team_members(user_id);
|
||||
|
||||
COMMENT ON TABLE team_members IS 'Team membership with per-team roles (admin or member)';
|
||||
COMMENT ON COLUMN team_members.role IS 'admin = manages team; member = uses team resources';
|
||||
|
||||
-- ── 3. Wire model_presets.team_id FK ────────
|
||||
-- Column already exists (migration 012), just add the FK constraint.
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE model_presets
|
||||
ADD CONSTRAINT fk_presets_team
|
||||
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
-- ── 4. Add team_id to channels ──────────────
|
||||
-- Team channels are visible to all team members.
|
||||
|
||||
ALTER TABLE channels ADD COLUMN IF NOT EXISTS team_id UUID REFERENCES teams(id) ON DELETE SET NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_channels_team ON channels(team_id) WHERE team_id IS NOT NULL;
|
||||
|
||||
-- ── 5. Private provider flag ────────────────
|
||||
-- Marks a provider as local/self-hosted (data stays on-prem).
|
||||
|
||||
ALTER TABLE api_configs ADD COLUMN IF NOT EXISTS is_private BOOLEAN DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN api_configs.is_private IS 'Private/self-hosted provider — data does not leave network';
|
||||
|
||||
-- ── 6. Add team_id to notes ─────────────────
|
||||
-- Team notes are shared within the team.
|
||||
|
||||
ALTER TABLE notes ADD COLUMN IF NOT EXISTS team_id UUID REFERENCES teams(id) ON DELETE SET NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_team ON notes(team_id) WHERE team_id IS NOT NULL;
|
||||
Reference in New Issue
Block a user