Changeset 0.8.0.1 (#43)

This commit is contained in:
2026-02-22 00:39:45 +00:00
parent 8925e8dcbf
commit 1adef94617
14 changed files with 902 additions and 16 deletions

View 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;