All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m27s
CI / docker (push) Successful in 1m10s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 1m40s
SonarQube / sonarqube (push) Successful in 4m29s
BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
130 lines
5.0 KiB
SQL
130 lines
5.0 KiB
SQL
-- V1__init.sql — PostgreSQL schema for Cameleer Server
|
|
-- PostgreSQL stores RBAC, configuration, and audit data only.
|
|
-- All observability data (executions, metrics, diagrams, logs, stats) is in ClickHouse.
|
|
|
|
-- =============================================================
|
|
-- RBAC
|
|
-- =============================================================
|
|
|
|
CREATE TABLE users (
|
|
user_id TEXT PRIMARY KEY,
|
|
provider TEXT NOT NULL,
|
|
email TEXT,
|
|
display_name TEXT,
|
|
password_hash TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE roles (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL UNIQUE,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
scope TEXT NOT NULL DEFAULT 'custom',
|
|
system BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
INSERT INTO roles (id, name, description, scope, system) VALUES
|
|
('00000000-0000-0000-0000-000000000001', 'AGENT', 'Agent registration and data ingestion', 'system-wide', true),
|
|
('00000000-0000-0000-0000-000000000002', 'VIEWER', 'Read-only access to dashboards and data', 'system-wide', true),
|
|
('00000000-0000-0000-0000-000000000003', 'OPERATOR', 'Operational commands (start/stop/configure agents)', 'system-wide', true),
|
|
('00000000-0000-0000-0000-000000000004', 'ADMIN', 'Full administrative access', 'system-wide', true);
|
|
|
|
CREATE TABLE groups (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL UNIQUE,
|
|
parent_group_id UUID REFERENCES groups(id) ON DELETE SET NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
INSERT INTO groups (id, name) VALUES
|
|
('00000000-0000-0000-0000-000000000010', 'Admins');
|
|
|
|
CREATE TABLE group_roles (
|
|
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
|
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (group_id, role_id)
|
|
);
|
|
|
|
INSERT INTO group_roles (group_id, role_id) VALUES
|
|
('00000000-0000-0000-0000-000000000010', '00000000-0000-0000-0000-000000000004');
|
|
|
|
CREATE TABLE user_groups (
|
|
user_id TEXT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
|
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (user_id, group_id)
|
|
);
|
|
|
|
CREATE TABLE user_roles (
|
|
user_id TEXT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
|
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (user_id, role_id)
|
|
);
|
|
|
|
CREATE INDEX idx_user_roles_user_id ON user_roles(user_id);
|
|
CREATE INDEX idx_user_groups_user_id ON user_groups(user_id);
|
|
CREATE INDEX idx_group_roles_group_id ON group_roles(group_id);
|
|
CREATE INDEX idx_groups_parent ON groups(parent_group_id);
|
|
|
|
-- =============================================================
|
|
-- Server configuration
|
|
-- =============================================================
|
|
|
|
CREATE TABLE server_config (
|
|
config_key TEXT PRIMARY KEY,
|
|
config_val JSONB NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_by TEXT
|
|
);
|
|
|
|
-- =============================================================
|
|
-- Application configuration
|
|
-- =============================================================
|
|
|
|
CREATE TABLE application_config (
|
|
application TEXT NOT NULL,
|
|
environment TEXT NOT NULL,
|
|
config_val JSONB NOT NULL,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_by TEXT,
|
|
PRIMARY KEY (application, environment)
|
|
);
|
|
|
|
CREATE TABLE app_settings (
|
|
application_id TEXT NOT NULL,
|
|
environment TEXT NOT NULL,
|
|
sla_threshold_ms INTEGER NOT NULL DEFAULT 300,
|
|
health_error_warn DOUBLE PRECISION NOT NULL DEFAULT 1.0,
|
|
health_error_crit DOUBLE PRECISION NOT NULL DEFAULT 5.0,
|
|
health_sla_warn DOUBLE PRECISION NOT NULL DEFAULT 99.0,
|
|
health_sla_crit DOUBLE PRECISION NOT NULL DEFAULT 95.0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (application_id, environment)
|
|
);
|
|
|
|
-- =============================================================
|
|
-- Audit log
|
|
-- =============================================================
|
|
|
|
CREATE TABLE audit_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
username TEXT NOT NULL,
|
|
action TEXT NOT NULL,
|
|
category TEXT NOT NULL,
|
|
target TEXT,
|
|
detail JSONB,
|
|
result TEXT NOT NULL,
|
|
ip_address TEXT,
|
|
user_agent TEXT
|
|
);
|
|
|
|
CREATE INDEX idx_audit_log_timestamp ON audit_log (timestamp DESC);
|
|
CREATE INDEX idx_audit_log_username ON audit_log (username);
|
|
CREATE INDEX idx_audit_log_category ON audit_log (category);
|
|
CREATE INDEX idx_audit_log_action ON audit_log (action);
|
|
CREATE INDEX idx_audit_log_target ON audit_log (target);
|