Init Eslogad
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
DROP TABLE IF EXISTS position_roles;
|
||||
DROP TABLE IF EXISTS user_position;
|
||||
DROP TABLE IF EXISTS user_department;
|
||||
DROP TABLE IF EXISTS positions;
|
||||
DROP TABLE IF EXISTS departments;
|
||||
|
||||
DROP TABLE IF EXISTS role_permissions;
|
||||
DROP TABLE IF EXISTS user_role;
|
||||
DROP TABLE IF EXISTS permissions;
|
||||
DROP TABLE IF EXISTS roles;
|
||||
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
DROP FUNCTION IF EXISTS set_updated_at() CASCADE;
|
||||
@@ -0,0 +1,146 @@
|
||||
-- ESLOGAD Core Init (Users, Roles, Permissions, Departments, Positions)
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
CREATE EXTENSION IF NOT EXISTS ltree;
|
||||
|
||||
-- Helper to auto-update updated_at
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- =======================
|
||||
-- USERS
|
||||
-- =======================
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(100) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255),
|
||||
email VARCHAR(255) UNIQUE,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active' CHECK (status IN ('active','inactive')),
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_login_at TIMESTAMP WITHOUT TIME ZONE,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
|
||||
CREATE TRIGGER trg_users_updated_at
|
||||
BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
-- =======================
|
||||
-- ROLES & PERMISSIONS
|
||||
-- =======================
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL, -- e.g., SUPERADMIN
|
||||
code TEXT UNIQUE NOT NULL, -- e.g., superadmin
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TRIGGER trg_roles_updated_at
|
||||
BEFORE UPDATE ON roles
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
code TEXT UNIQUE NOT NULL, -- e.g., letter.view
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TRIGGER trg_permissions_updated_at
|
||||
BEFORE UPDATE ON permissions
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_role (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
assigned_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
removed_at TIMESTAMP WITHOUT TIME ZONE
|
||||
)
|
||||
;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_role_active
|
||||
ON user_role(user_id, role_id) WHERE removed_at IS NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (role_id, permission_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS departments (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
code TEXT UNIQUE,
|
||||
path LTREE UNIQUE NOT NULL, -- e.g., eslogad.aslog.waaslog_faskon_bmn
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_departments_path_gist
|
||||
ON departments USING GIST (path);
|
||||
|
||||
CREATE TRIGGER trg_departments_updated_at
|
||||
BEFORE UPDATE ON departments
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS positions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL, -- e.g., PABAN III/FASKON
|
||||
code TEXT UNIQUE, -- e.g., paban-III-faskon
|
||||
path LTREE UNIQUE NOT NULL, -- hierarchy within org chart
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_positions_path_gist
|
||||
ON positions USING GIST (path);
|
||||
|
||||
CREATE TRIGGER trg_positions_updated_at
|
||||
BEFORE UPDATE ON positions
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_department (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
department_id UUID NOT NULL REFERENCES departments(id) ON DELETE CASCADE,
|
||||
is_primary BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
assigned_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
removed_at TIMESTAMP WITHOUT TIME ZONE
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_department_active
|
||||
ON user_department(user_id, department_id) WHERE removed_at IS NULL;
|
||||
|
||||
CREATE TRIGGER trg_user_department_updated_at
|
||||
BEFORE UPDATE ON user_department
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_position (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
position_id UUID NOT NULL REFERENCES positions(id) ON DELETE CASCADE,
|
||||
assigned_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
removed_at TIMESTAMP WITHOUT TIME ZONE
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_position_active
|
||||
ON user_position(user_id, position_id) WHERE removed_at IS NULL;
|
||||
|
||||
CREATE TRIGGER trg_user_position_updated_at
|
||||
BEFORE UPDATE ON user_position
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS position_roles (
|
||||
position_id UUID NOT NULL REFERENCES positions(id) ON DELETE CASCADE,
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (position_id, role_id)
|
||||
);
|
||||
@@ -0,0 +1,132 @@
|
||||
BEGIN;
|
||||
|
||||
-- =========================
|
||||
-- Departments (as requested)
|
||||
-- =========================
|
||||
-- Root org namespace is "eslogad" in ltree path
|
||||
INSERT INTO departments (name, code, path) VALUES
|
||||
('RENBINMINLOG', 'renbinminlog', 'eslogad.renbinminlog'),
|
||||
('FASKON BMN', 'faskon_bmn', 'eslogad.faskon_bmn'),
|
||||
('BEKPALKES', 'bekpalkes', 'eslogad.bekpalkes')
|
||||
ON CONFLICT (code) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
path = EXCLUDED.path,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- =========================
|
||||
-- Positions (hierarchy)
|
||||
-- =========================
|
||||
-- Conventions:
|
||||
-- - superadmin is a separate root
|
||||
-- - eslogad.aslog is head; waaslog_* under aslog
|
||||
-- - paban_* under each waaslog_*; pabandya_* under its paban_*
|
||||
INSERT INTO positions (name, code, path) VALUES
|
||||
-- ROOTS
|
||||
('SUPERADMIN', 'superadmin', 'superadmin'),
|
||||
('ASLOG', 'aslog', 'eslogad.aslog'),
|
||||
|
||||
-- WAASLOG under ASLOG
|
||||
('WAASLOG RENBINMINLOG', 'waaslogrenbinminlog', 'eslogad.aslog.waaslog_renbinminlog'),
|
||||
('WAASLOG FASKON BMN', 'waaslogfaskonbmn', 'eslogad.aslog.waaslog_faskon_bmn'),
|
||||
('WAASLOG BEKPALKES', 'waaslogbekpalkes', 'eslogad.aslog.waaslog_bekpalkes'),
|
||||
|
||||
-- Other posts directly under ASLOG
|
||||
('KADISADAAD', 'kadisadaad', 'eslogad.aslog.kadisadaad'),
|
||||
('KATUUD', 'katuud', 'eslogad.aslog.katuud'),
|
||||
('SPRI', 'spri', 'eslogad.aslog.spri'),
|
||||
|
||||
-- PABAN under WAASLOG RENBINMINLOG
|
||||
('PABAN I/REN', 'paban-I-ren', 'eslogad.aslog.waaslog_renbinminlog.paban_I_ren'),
|
||||
('PABAN II/BINMINLOG', 'paban-II-binminlog', 'eslogad.aslog.waaslog_renbinminlog.paban_II_binminlog'),
|
||||
|
||||
-- PABAN under WAASLOG FASKON BMN
|
||||
('PABAN III/FASKON', 'paban-III-faskon', 'eslogad.aslog.waaslog_faskon_bmn.paban_III_faskon'),
|
||||
('PABAN IV/BMN', 'paban-iv-bmn', 'eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn'),
|
||||
|
||||
-- PABAN under WAASLOG BEKPALKES
|
||||
('PABAN V/BEK', 'paban-v-bek', 'eslogad.aslog.waaslog_bekpalkes.paban_V_bek'),
|
||||
('PABAN VI/ALPAL', 'paban-vi-alpal', 'eslogad.aslog.waaslog_bekpalkes.paban_VI_alpal'),
|
||||
('PABAN VII/KES', 'paban-vii-kes', 'eslogad.aslog.waaslog_bekpalkes.paban_VII_kes'),
|
||||
|
||||
-- PABANDYA under PABAN I/REN
|
||||
('PABANDYA 1 / RENPROGGAR', 'pabandya-1-renproggar', 'eslogad.aslog.waaslog_renbinminlog.paban_I_ren.pabandya_1_renproggar'),
|
||||
('PABANDYA 2 / DALWASGAR', 'pabandya-2-dalwasgar', 'eslogad.aslog.waaslog_renbinminlog.paban_I_ren.pabandya_2_dalwasgar'),
|
||||
('PABANDYA 3 / ANEVDATA', 'pabandya-3-anevdata', 'eslogad.aslog.waaslog_renbinminlog.paban_I_ren.pabandya_3_anevdata'),
|
||||
|
||||
-- PABANDYA under PABAN II/BINMINLOG
|
||||
('PABANDYA 1 / MINLOG', 'pabandya-1-minlog', 'eslogad.aslog.waaslog_renbinminlog.paban_II_binminlog.pabandya_1_minlog'),
|
||||
('PABANDYA 2 / HIBAHKOD', 'pabandya-2-hibahkod', 'eslogad.aslog.waaslog_renbinminlog.paban_II_binminlog.pabandya_2_hibahkod'),
|
||||
('PABANDYA 3 / PUSMAT', 'pabandya-3-pusmat', 'eslogad.aslog.waaslog_renbinminlog.paban_II_binminlog.pabandya_3_pusmat'),
|
||||
|
||||
-- PABANDYA under PABAN IV/BMN
|
||||
('PABANDYA 1 / TANAH', 'pabandya-1-tanah', 'eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_1_tanah'),
|
||||
('PABANDYA 2 / PANGKALAN KONSTRUKSI','pabandya-2-pangkalankonstruksi','eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_2_pangkalan_konstruksi'),
|
||||
('PABANDYA 3 / FASMATZI', 'pabandya-3-fasmatzi', 'eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_3_fasmatzi'),
|
||||
|
||||
-- PABANDYA under PABAN IV/BMN (AKUN group)
|
||||
('PABANDYA 1 / AKUN BB', 'pabandya-1-akunbb', 'eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_1_akun_bb'),
|
||||
('PABANDYA 2 / AKUN BTB', 'pabandya-2-akunbtb', 'eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_2_akun_btb'),
|
||||
('PABANDYA 3 / SISFO BMN DAN UAKPB-KP','pabandya-3-sisfo-bmn-uakpbkp','eslogad.aslog.waaslog_faskon_bmn.paban_IV_bmn.pabandya_3_sisfo_bmn_uakpb_kp'),
|
||||
|
||||
-- PABANDYA under PABAN III/FASKON
|
||||
('PABANDYA 1 / JATOPTIKMU', 'pabandya-1-jatoptikmu', 'eslogad.aslog.waaslog_faskon_bmn.paban_III_faskon.pabandya_1_jatoptikmu'),
|
||||
('PABANDYA 2 / RANTEKMEK', 'pabandya-2-rantekmek', 'eslogad.aslog.waaslog_faskon_bmn.paban_III_faskon.pabandya_2_rantekmek'),
|
||||
('PABANDYA 3 / ALHUBTOPPALSUS', 'pabandya-3-alhubtoppalsus', 'eslogad.aslog.waaslog_faskon_bmn.paban_III_faskon.pabandya_3_alhubtoppalsus'),
|
||||
('PABANDYA 4 / PESUD', 'pabandya-4-pesud', 'eslogad.aslog.waaslog_faskon_bmn.paban_III_faskon.pabandya_4_pesud'),
|
||||
|
||||
-- PABANDYA under PABAN VII/KES
|
||||
('PABANDYA 1 / BEKKES', 'pabandya-1-bekkes', 'eslogad.aslog.waaslog_bekpalkes.paban_VII_kes.pabandya_1_bekkes'),
|
||||
('PABANDYA 2 / ALKES', 'pabandya-2-alkes', 'eslogad.aslog.waaslog_bekpalkes.paban_VII_kes.pabandya_2_alkes')
|
||||
ON CONFLICT (code) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
path = EXCLUDED.path,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- =========================
|
||||
-- SUPERADMIN role (minimal)
|
||||
-- =========================
|
||||
INSERT INTO roles (name, code, description) VALUES
|
||||
('SUPERADMIN', 'superadmin', 'Full system access and management'),
|
||||
('ADMIN', 'admin', 'Manage users, letters, and settings within their department'),
|
||||
('HEAD', 'head', 'Approve outgoing letters and manage dispositions in their department'),
|
||||
('STAFF', 'staff', 'Create letters, process assigned dispositions')
|
||||
ON CONFLICT (code) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- =========================
|
||||
-- Users (seed 1 superadmin)
|
||||
-- =========================
|
||||
-- Replace the plaintext password as needed; pgcrypto hashes it with bcrypt.
|
||||
INSERT INTO users (username, password_hash, name, email, status, is_active)
|
||||
VALUES ('superadmin',
|
||||
crypt('ChangeMe!Super#123', gen_salt('bf')),
|
||||
'Super Admin',
|
||||
'superadmin@example.com',
|
||||
'active',
|
||||
TRUE)
|
||||
ON CONFLICT (username) DO UPDATE
|
||||
SET name = EXCLUDED.name,
|
||||
email = EXCLUDED.email,
|
||||
status = EXCLUDED.status,
|
||||
is_active = EXCLUDED.is_active,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- =========================
|
||||
-- Link: SUPERADMIN user ↔ role ↔ position
|
||||
-- =========================
|
||||
WITH u AS (SELECT id FROM users WHERE username = 'superadmin'),
|
||||
r AS (SELECT id FROM roles WHERE code = 'superadmin'),
|
||||
p AS (SELECT id FROM positions WHERE code = 'superadmin')
|
||||
INSERT INTO user_role (user_id, role_id)
|
||||
SELECT u.id, r.id FROM u, r
|
||||
ON CONFLICT (user_id, role_id) WHERE removed_at IS NULL DO NOTHING;
|
||||
|
||||
WITH u AS (SELECT id FROM users WHERE username = 'superadmin'),
|
||||
p AS (SELECT id FROM positions WHERE code = 'superadmin')
|
||||
INSERT INTO user_position (user_id, position_id)
|
||||
SELECT u.id, p.id FROM u, p
|
||||
ON CONFLICT (user_id, position_id) WHERE removed_at IS NULL DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,30 @@
|
||||
INSERT INTO permissions (id, code, description, created_at, updated_at) VALUES
|
||||
-- Users
|
||||
(gen_random_uuid(), 'user.read', 'View user list and details', now(), now()),
|
||||
(gen_random_uuid(), 'user.create', 'Create new users', now(), now()),
|
||||
(gen_random_uuid(), 'user.update', 'Edit existing users', now(), now()),
|
||||
(gen_random_uuid(), 'user.delete', 'Delete users', now(), now()),
|
||||
|
||||
-- Roles
|
||||
(gen_random_uuid(), 'role.read', 'View roles', now(), now()),
|
||||
(gen_random_uuid(), 'role.create', 'Create new roles', now(), now()),
|
||||
(gen_random_uuid(), 'role.update', 'Edit existing roles', now(), now()),
|
||||
(gen_random_uuid(), 'role.delete', 'Delete roles', now(), now()),
|
||||
|
||||
-- Permissions
|
||||
(gen_random_uuid(), 'permission.read', 'View permissions', now(), now()),
|
||||
(gen_random_uuid(), 'permission.create', 'Create new permissions', now(), now()),
|
||||
(gen_random_uuid(), 'permission.update', 'Edit existing permissions', now(), now()),
|
||||
(gen_random_uuid(), 'permission.delete', 'Delete permissions', now(), now()),
|
||||
|
||||
-- Departments
|
||||
(gen_random_uuid(), 'department.read', 'View departments', now(), now()),
|
||||
(gen_random_uuid(), 'department.create', 'Create new departments', now(), now()),
|
||||
(gen_random_uuid(), 'department.update', 'Edit existing departments', now(), now()),
|
||||
(gen_random_uuid(), 'department.delete', 'Delete departments', now(), now()),
|
||||
|
||||
-- Positions
|
||||
(gen_random_uuid(), 'position.read', 'View positions', now(), now()),
|
||||
(gen_random_uuid(), 'position.create', 'Create new positions', now(), now()),
|
||||
(gen_random_uuid(), 'position.update', 'Edit existing positions', now(), now()),
|
||||
(gen_random_uuid(), 'position.delete', 'Delete positions', now(), now());
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS user_profiles;
|
||||
@@ -0,0 +1,30 @@
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||
full_name VARCHAR(150) NOT NULL,
|
||||
display_name VARCHAR(100),
|
||||
phone VARCHAR(50),
|
||||
avatar_url TEXT,
|
||||
job_title VARCHAR(120),
|
||||
employee_no VARCHAR(60),
|
||||
bio TEXT,
|
||||
timezone VARCHAR(64) DEFAULT 'Asia/Jakarta',
|
||||
locale VARCHAR(16) DEFAULT 'id-ID',
|
||||
preferences JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
notification_prefs JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
last_seen_at TIMESTAMP WITHOUT TIME ZONE,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_profiles_phone ON user_profiles(phone);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_profiles_employee_no ON user_profiles(employee_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_profiles_prefs_gin ON user_profiles USING GIN (preferences);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_profiles_notif_gin ON user_profiles USING GIN (notification_prefs);
|
||||
|
||||
CREATE TRIGGER trg_user_profiles_updated_at
|
||||
BEFORE UPDATE ON user_profiles
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,60 @@
|
||||
-- =======================
|
||||
-- TITLES
|
||||
-- =======================
|
||||
CREATE TABLE IF NOT EXISTS titles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL, -- e.g., "Senior Software Engineer"
|
||||
code TEXT UNIQUE, -- e.g., "senior-software-engineer"
|
||||
description TEXT, -- optional: extra details
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Trigger for updated_at
|
||||
CREATE TRIGGER trg_titles_updated_at
|
||||
BEFORE UPDATE ON titles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
-- Perwira Tinggi (High-ranking Officers)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Jenderal', 'jenderal', 'Pangkat tertinggi di TNI AD'),
|
||||
('Letnan Jenderal', 'letnan-jenderal', 'Pangkat tinggi di bawah Jenderal'),
|
||||
('Mayor Jenderal', 'mayor-jenderal', 'Pangkat tinggi di bawah Letnan Jenderal'),
|
||||
('Brigadir Jenderal', 'brigadir-jenderal', 'Pangkat tinggi di bawah Mayor Jenderal');
|
||||
|
||||
-- Perwira Menengah (Middle-ranking Officers)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Kolonel', 'kolonel', 'Pangkat perwira menengah tertinggi'),
|
||||
('Letnan Kolonel', 'letnan-kolonel', 'Pangkat perwira menengah di bawah Kolonel'),
|
||||
('Mayor', 'mayor', 'Pangkat perwira menengah di bawah Letnan Kolonel');
|
||||
|
||||
-- Perwira Pertama (Junior Officers)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Kapten', 'kapten', 'Pangkat perwira pertama tertinggi'),
|
||||
('Letnan Satu', 'letnan-satu', 'Pangkat perwira pertama di bawah Kapten'),
|
||||
('Letnan Dua', 'letnan-dua', 'Pangkat perwira pertama di bawah Letnan Satu');
|
||||
|
||||
-- Bintara Tinggi (Senior NCOs)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Pembantu Letnan Satu', 'pembantu-letnan-satu', 'Pangkat bintara tinggi tertinggi'),
|
||||
('Pembantu Letnan Dua', 'pembantu-letnan-dua', 'Pangkat bintara tinggi di bawah Pelda');
|
||||
|
||||
-- Bintara (NCOs)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Sersan Mayor', 'sersan-mayor', 'Pangkat bintara di bawah Pelda'),
|
||||
('Sersan Kepala', 'sersan-kepala', 'Pangkat bintara di bawah Serma'),
|
||||
('Sersan Satu', 'sersan-satu', 'Pangkat bintara di bawah Serka'),
|
||||
('Sersan Dua', 'sersan-dua', 'Pangkat bintara di bawah Sertu');
|
||||
|
||||
-- Tamtama Tinggi (Senior Enlisted)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Kopral Kepala', 'kopral-kepala', 'Pangkat tamtama tinggi tertinggi'),
|
||||
('Kopral Satu', 'kopral-satu', 'Pangkat tamtama tinggi di bawah Kopka'),
|
||||
('Kopral Dua', 'kopral-dua', 'Pangkat tamtama tinggi di bawah Koptu');
|
||||
|
||||
-- Tamtama (Enlisted)
|
||||
INSERT INTO titles (name, code, description) VALUES
|
||||
('Prajurit Kepala', 'prajurit-kepala', 'Pangkat tamtama di bawah Kopda'),
|
||||
('Prajurit Satu', 'prajurit-satu', 'Pangkat tamtama di bawah Prada'),
|
||||
('Prajurit Dua', 'prajurit-dua', 'Pangkat tamtama terendah');
|
||||
Reference in New Issue
Block a user