mirror of
https://github.com/arthur-pbty/flint.git
synced 2026-08-01 20:29:03 +02:00
feat: introduce web dashboard with multi-bot management
- add Discord OAuth2 authentication - allow users to register their bots via token - implement dynamic bot start/stop system - store bots in database (multi-tenant) - replace single-bot env setup with scalable architecture
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenants (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
owner_user_id UUID,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||||
discord_user_id TEXT NOT NULL UNIQUE,
|
||||
username TEXT NOT NULL,
|
||||
avatar_url TEXT,
|
||||
role TEXT NOT NULL CHECK (role IN ('owner', 'member')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_tenants_owner_user'
|
||||
) THEN
|
||||
ALTER TABLE tenants
|
||||
ADD CONSTRAINT fk_tenants_owner_user
|
||||
FOREIGN KEY (owner_user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bots (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||||
owner_user_id UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
discord_bot_id TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
token_ciphertext TEXT NOT NULL,
|
||||
token_iv TEXT NOT NULL,
|
||||
token_tag TEXT NOT NULL,
|
||||
status TEXT NOT NULL CHECK (status IN ('stopped', 'starting', 'running', 'stopping', 'error')),
|
||||
last_error TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (tenant_id, discord_bot_id),
|
||||
UNIQUE (discord_bot_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bot_runtime_events (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||||
bot_id UUID NOT NULL REFERENCES bots(id) ON DELETE CASCADE,
|
||||
level TEXT NOT NULL CHECK (level IN ('info', 'warn', 'error')),
|
||||
message TEXT NOT NULL,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_users_tenant_id ON users (tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bots_tenant_id ON bots (tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bot_runtime_events_tenant_created ON bot_runtime_events (tenant_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_bot_runtime_events_bot_created ON bot_runtime_events (bot_id, created_at DESC);
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_updated_at_timestamp()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_users_updated_at ON users;
|
||||
CREATE TRIGGER trg_users_updated_at
|
||||
BEFORE UPDATE ON users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at_timestamp();
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_bots_updated_at ON bots;
|
||||
CREATE TRIGGER trg_bots_updated_at
|
||||
BEFORE UPDATE ON bots
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at_timestamp();
|
||||
|
||||
ALTER TABLE bot_presence_states
|
||||
ADD COLUMN IF NOT EXISTS tenant_id UUID,
|
||||
ADD COLUMN IF NOT EXISTS owner_user_id UUID;
|
||||
|
||||
ALTER TABLE bot_member_message_configs
|
||||
ADD COLUMN IF NOT EXISTS tenant_id UUID,
|
||||
ADD COLUMN IF NOT EXISTS owner_user_id UUID;
|
||||
|
||||
ALTER TABLE bot_log_event_configs
|
||||
ADD COLUMN IF NOT EXISTS tenant_id UUID,
|
||||
ADD COLUMN IF NOT EXISTS owner_user_id UUID;
|
||||
|
||||
UPDATE bot_presence_states p
|
||||
SET tenant_id = b.tenant_id,
|
||||
owner_user_id = b.owner_user_id
|
||||
FROM bots b
|
||||
WHERE p.bot_id = b.discord_bot_id
|
||||
AND (p.tenant_id IS NULL OR p.owner_user_id IS NULL);
|
||||
|
||||
UPDATE bot_member_message_configs m
|
||||
SET tenant_id = b.tenant_id,
|
||||
owner_user_id = b.owner_user_id
|
||||
FROM bots b
|
||||
WHERE m.bot_id = b.discord_bot_id
|
||||
AND (m.tenant_id IS NULL OR m.owner_user_id IS NULL);
|
||||
|
||||
UPDATE bot_log_event_configs l
|
||||
SET tenant_id = b.tenant_id,
|
||||
owner_user_id = b.owner_user_id
|
||||
FROM bots b
|
||||
WHERE l.bot_id = b.discord_bot_id
|
||||
AND (l.tenant_id IS NULL OR l.owner_user_id IS NULL);
|
||||
|
||||
DELETE FROM bot_presence_states p
|
||||
WHERE p.tenant_id IS NULL OR p.owner_user_id IS NULL;
|
||||
|
||||
DELETE FROM bot_member_message_configs m
|
||||
WHERE m.tenant_id IS NULL OR m.owner_user_id IS NULL;
|
||||
|
||||
DELETE FROM bot_log_event_configs l
|
||||
WHERE l.tenant_id IS NULL OR l.owner_user_id IS NULL;
|
||||
|
||||
ALTER TABLE bot_presence_states
|
||||
ALTER COLUMN tenant_id SET NOT NULL,
|
||||
ALTER COLUMN owner_user_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE bot_member_message_configs
|
||||
ALTER COLUMN tenant_id SET NOT NULL,
|
||||
ALTER COLUMN owner_user_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE bot_log_event_configs
|
||||
ALTER COLUMN tenant_id SET NOT NULL,
|
||||
ALTER COLUMN owner_user_id SET NOT NULL;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_presence_states_tenant'
|
||||
) THEN
|
||||
ALTER TABLE bot_presence_states
|
||||
ADD CONSTRAINT fk_bot_presence_states_tenant
|
||||
FOREIGN KEY (tenant_id)
|
||||
REFERENCES tenants(id)
|
||||
ON DELETE CASCADE;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_presence_states_owner_user'
|
||||
) THEN
|
||||
ALTER TABLE bot_presence_states
|
||||
ADD CONSTRAINT fk_bot_presence_states_owner_user
|
||||
FOREIGN KEY (owner_user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_member_message_configs_tenant'
|
||||
) THEN
|
||||
ALTER TABLE bot_member_message_configs
|
||||
ADD CONSTRAINT fk_bot_member_message_configs_tenant
|
||||
FOREIGN KEY (tenant_id)
|
||||
REFERENCES tenants(id)
|
||||
ON DELETE CASCADE;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_member_message_configs_owner_user'
|
||||
) THEN
|
||||
ALTER TABLE bot_member_message_configs
|
||||
ADD CONSTRAINT fk_bot_member_message_configs_owner_user
|
||||
FOREIGN KEY (owner_user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_log_event_configs_tenant'
|
||||
) THEN
|
||||
ALTER TABLE bot_log_event_configs
|
||||
ADD CONSTRAINT fk_bot_log_event_configs_tenant
|
||||
FOREIGN KEY (tenant_id)
|
||||
REFERENCES tenants(id)
|
||||
ON DELETE CASCADE;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conname = 'fk_bot_log_event_configs_owner_user'
|
||||
) THEN
|
||||
ALTER TABLE bot_log_event_configs
|
||||
ADD CONSTRAINT fk_bot_log_event_configs_owner_user
|
||||
FOREIGN KEY (owner_user_id)
|
||||
REFERENCES users(id)
|
||||
ON DELETE RESTRICT;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_bot_presence_states_tenant_id ON bot_presence_states (tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bot_member_message_configs_tenant_id ON bot_member_message_configs (tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bot_log_event_configs_tenant_id ON bot_log_event_configs (tenant_id);
|
||||
Reference in New Issue
Block a user