-- PostgreSQL schema for KIllaDesign data model -- Safe re-runnable DDL -- Recommended: run inside a dedicated schema CREATE SCHEMA IF NOT EXISTS kd; SET search_path TO kd, public; -- Domain definitions (optionally used for clarity) CREATE DOMAIN IF NOT EXISTS money_aed AS NUMERIC(16,2) CHECK (VALUE >= 0); -- Lookup tables (optional, minimal to keep example concise) CREATE TABLE IF NOT EXISTS project_types ( type TEXT PRIMARY KEY ); INSERT INTO project_types(type) VALUES ('Mixed-Use'), ('Hospitality'), ('Office'), ('Residential'), ('Cultural') ON CONFLICT DO NOTHING; CREATE TABLE IF NOT EXISTS work_categories ( category TEXT PRIMARY KEY ); INSERT INTO work_categories(category) VALUES ('Architecture'), ('Project Management'), ('Subcontractor') ON CONFLICT DO NOTHING; -- Core tables CREATE TABLE IF NOT EXISTS projects ( project_id TEXT PRIMARY KEY, project_name TEXT NOT NULL, client_name TEXT NOT NULL, contract_value_aed money_aed NOT NULL, planned_cost_aed money_aed NOT NULL, project_start_date DATE NOT NULL, project_end_date DATE, project_type TEXT REFERENCES project_types(type), project_status TEXT NOT NULL, current_phase TEXT ); CREATE TABLE IF NOT EXISTS employees ( employee_id TEXT PRIMARY KEY, employee_name TEXT NOT NULL, department TEXT, role TEXT, hourly_rate_aed money_aed NOT NULL, employment_type TEXT, start_date DATE, cost_category TEXT REFERENCES work_categories(category) ); CREATE TABLE IF NOT EXISTS milestones ( project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, milestone_name TEXT NOT NULL, milestone_order INT NOT NULL, planned_date DATE, actual_date DATE, status TEXT, completion_percentage INT CHECK (completion_percentage BETWEEN 0 AND 100), PRIMARY KEY (project_id, milestone_order) ); CREATE TABLE IF NOT EXISTS invoices ( invoice_id TEXT PRIMARY KEY, project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, invoice_date DATE NOT NULL, invoice_amount_aed money_aed NOT NULL, due_date DATE, payment_date DATE, payment_status TEXT, days_outstanding INT, milestone_reference TEXT ); CREATE TABLE IF NOT EXISTS subcontractors ( project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, subcontractor_name TEXT NOT NULL, service_type TEXT NOT NULL, contract_amount_aed money_aed NOT NULL, amount_invoiced_aed money_aed NOT NULL, payment_status TEXT, work_category TEXT REFERENCES work_categories(category), PRIMARY KEY (project_id, subcontractor_name, service_type) ); CREATE TABLE IF NOT EXISTS timesheets ( record_id TEXT PRIMARY KEY, date DATE NOT NULL, employee_id TEXT NOT NULL REFERENCES employees(employee_id) ON DELETE RESTRICT, project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, hours_worked NUMERIC(6,2) NOT NULL CHECK (hours_worked >= 0), work_category TEXT REFERENCES work_categories(category), task_description TEXT, billable_hours NUMERIC(6,2) CHECK (billable_hours >= 0) ); CREATE TABLE IF NOT EXISTS milestone_budgets ( project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, milestone_name TEXT NOT NULL, milestone_order INT NOT NULL, planned_date DATE, actual_date DATE, status TEXT, budgeted_hours NUMERIC(10,2), budgeted_cost_aed money_aed, actual_hours NUMERIC(10,2), actual_cost_aed money_aed, cumulative_budgeted_hours NUMERIC(10,2), cumulative_budgeted_cost_aed money_aed, cumulative_actual_hours NUMERIC(10,2), cumulative_actual_cost_aed money_aed, hours_variance NUMERIC(10,2), cost_variance_aed money_aed, schedule_variance_days INT, budget_utilization_percent NUMERIC(5,2), architecture_hours NUMERIC(10,2), architecture_cost_aed money_aed, pm_hours NUMERIC(10,2), pm_cost_aed money_aed, subcontractor_hours NUMERIC(10,2), subcontractor_cost_aed money_aed, notes TEXT, PRIMARY KEY (project_id, milestone_order) ); CREATE TABLE IF NOT EXISTS staff_allocation ( project_id TEXT NOT NULL REFERENCES projects(project_id) ON DELETE CASCADE, milestone_id TEXT, milestone_name TEXT, employee_id TEXT NOT NULL REFERENCES employees(employee_id) ON DELETE RESTRICT, employee_name TEXT, role TEXT, category TEXT, hours_allocated NUMERIC(10,2), hours_worked NUMERIC(10,2), hourly_rate_aed money_aed, cost_aed money_aed, utilization_percent NUMERIC(6,2), skill_match_score NUMERIC(6,2), availability_status TEXT, start_date DATE, end_date DATE, performance_rating TEXT, notes TEXT, PRIMARY KEY (project_id, milestone_name, employee_id) );