-- OMS·WMS·ERP Unified Platform Database Schema v1.0
-- PostgreSQL 15+
-- Principles Applied:
--   3: Data Consistency (SSOT)
--   5: Normalization (3NF minimum)
--   6: Denormalization (performance-justified only)
--  14: Traceability (audit_log on all mutations)
--  23: Security (NUMERIC for financial precision)

CREATE SCHEMA IF NOT EXISTS quantengine;
SET search_path = quantengine, public;

-- ===== ENUMS (Type Safety - Principle 19) =====

CREATE TYPE order_status AS ENUM ('DRAFT', 'CONFIRMED', 'SHIPPED', 'DELIVERED', 'CANCELLED');
CREATE TYPE order_line_status AS ENUM ('PENDING', 'ALLOCATED', 'SHIPPED', 'CANCELLED');
CREATE TYPE transfer_status AS ENUM ('REQUESTED', 'APPROVED', 'SHIPPED', 'RECEIVED', 'CANCELLED');
CREATE TYPE product_status AS ENUM ('ACTIVE', 'INACTIVE', 'OBSOLETE');
CREATE TYPE supplier_status AS ENUM ('ACTIVE', 'INACTIVE', 'SUSPENDED');
CREATE TYPE customer_status AS ENUM ('ACTIVE', 'INACTIVE', 'SUSPENDED');
CREATE TYPE gl_account_type AS ENUM ('ASSET', 'LIABILITY', 'EQUITY', 'REVENUE', 'EXPENSE');
CREATE TYPE voucher_status AS ENUM ('DRAFT', 'POSTED', 'APPROVED', 'VOIDED');
CREATE TYPE voucher_document_type AS ENUM ('PURCHASE', 'SALES', 'JOURNAL', 'ADJUSTMENT');
CREATE TYPE inventory_status AS ENUM ('ACTIVE', 'INACTIVE', 'DAMAGED');
CREATE TYPE unit_of_measure AS ENUM ('EA', 'KG', 'M', 'L', 'BOX');
CREATE TYPE audit_operation AS ENUM ('CREATE', 'UPDATE', 'DELETE');
CREATE TYPE user_role AS ENUM ('ADMIN', 'MANAGER', 'OPERATOR', 'VIEWER', 'ANALYST');

-- ===== COMMON/MASTER TABLES =====

CREATE TABLE users (
  user_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email VARCHAR(255) NOT NULL UNIQUE,
  password_hash VARCHAR(255) NOT NULL,
  name VARCHAR(255) NOT NULL,
  role user_role NOT NULL DEFAULT 'VIEWER',
  status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
  created_by UUID,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_users_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT fk_users_modified_by FOREIGN KEY (modified_by) REFERENCES users(user_id),
  CONSTRAINT fk_users_deleted_by FOREIGN KEY (deleted_by) REFERENCES users(user_id)
);
CREATE INDEX idx_users_email ON users(email);

CREATE TABLE warehouses (
  warehouse_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  warehouse_code VARCHAR(50) NOT NULL UNIQUE,
  warehouse_name VARCHAR(255) NOT NULL,
  location VARCHAR(255),
  status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_warehouses_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);
CREATE INDEX idx_warehouses_code ON warehouses(warehouse_code);

CREATE TABLE product_categories (
  category_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  category_name VARCHAR(255) NOT NULL UNIQUE,
  description TEXT,
  status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT fk_categories_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);

-- ===== OMS: ORDER MANAGEMENT =====

CREATE TABLE customers (
  customer_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  customer_code VARCHAR(50) NOT NULL UNIQUE,
  customer_name VARCHAR(255) NOT NULL,
  email VARCHAR(255),
  phone VARCHAR(20),
  business_registration VARCHAR(50),
  status customer_status NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_customers_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);
CREATE INDEX idx_customers_code ON customers(customer_code);
CREATE INDEX idx_customers_email ON customers(email);

CREATE TABLE orders (
  order_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  order_no VARCHAR(50) NOT NULL UNIQUE,
  customer_id UUID NOT NULL,
  order_date DATE NOT NULL DEFAULT CURRENT_DATE,
  total_amount NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  status order_status NOT NULL DEFAULT 'DRAFT',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
  CONSTRAINT fk_orders_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT chk_total_amount CHECK (total_amount >= 0)
);
CREATE INDEX idx_orders_no ON orders(order_no);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_orders_order_date ON orders(order_date);

CREATE TABLE order_lines (
  line_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  order_id UUID NOT NULL,
  line_no SMALLINT NOT NULL,
  product_id UUID NOT NULL,
  quantity NUMERIC(19,4) NOT NULL,
  quantity_unit unit_of_measure NOT NULL,
  unit_price NUMERIC(19,4) NOT NULL,
  line_total NUMERIC(19,4) NOT NULL,
  status order_line_status NOT NULL DEFAULT 'PENDING',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_order_lines_order FOREIGN KEY (order_id) REFERENCES orders(order_id),
  CONSTRAINT fk_order_lines_product FOREIGN KEY (product_id) REFERENCES products(product_id),
  CONSTRAINT fk_order_lines_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT uk_order_lines_order_lineno UNIQUE (order_id, line_no),
  CONSTRAINT chk_quantity CHECK (quantity > 0),
  CONSTRAINT chk_unit_price CHECK (unit_price >= 0),
  CONSTRAINT chk_line_total CHECK (line_total >= 0)
);
CREATE INDEX idx_order_lines_order_id ON order_lines(order_id);
CREATE INDEX idx_order_lines_product_id ON order_lines(product_id);

-- ===== WMS: WAREHOUSE MANAGEMENT =====

CREATE TABLE inventory (
  inventory_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  warehouse_id UUID NOT NULL,
  product_id UUID NOT NULL,
  qty_on_hand NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  qty_reserved NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  qty_available NUMERIC(19,4) NOT NULL GENERATED ALWAYS AS (qty_on_hand - qty_reserved) STORED,
  last_adjustment_date TIMESTAMP,
  status inventory_status NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_inventory_warehouse FOREIGN KEY (warehouse_id) REFERENCES warehouses(warehouse_id),
  CONSTRAINT fk_inventory_product FOREIGN KEY (product_id) REFERENCES products(product_id),
  CONSTRAINT fk_inventory_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT uk_inventory_warehouse_product UNIQUE (warehouse_id, product_id),
  CONSTRAINT chk_qty_on_hand CHECK (qty_on_hand >= 0),
  CONSTRAINT chk_qty_reserved CHECK (qty_reserved >= 0)
);
CREATE INDEX idx_inventory_warehouse_id ON inventory(warehouse_id);
CREATE INDEX idx_inventory_product_id ON inventory(product_id);

CREATE TABLE stock_transfers (
  transfer_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  transfer_no VARCHAR(50) NOT NULL UNIQUE,
  from_warehouse_id UUID NOT NULL,
  to_warehouse_id UUID NOT NULL,
  product_id UUID NOT NULL,
  quantity NUMERIC(19,4) NOT NULL,
  reason TEXT,
  status transfer_status NOT NULL DEFAULT 'REQUESTED',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_transfers_from_warehouse FOREIGN KEY (from_warehouse_id) REFERENCES warehouses(warehouse_id),
  CONSTRAINT fk_transfers_to_warehouse FOREIGN KEY (to_warehouse_id) REFERENCES warehouses(warehouse_id),
  CONSTRAINT fk_transfers_product FOREIGN KEY (product_id) REFERENCES products(product_id),
  CONSTRAINT fk_transfers_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT chk_quantity CHECK (quantity > 0),
  CONSTRAINT chk_different_warehouses CHECK (from_warehouse_id != to_warehouse_id)
);
CREATE INDEX idx_stock_transfers_no ON stock_transfers(transfer_no);
CREATE INDEX idx_stock_transfers_from_warehouse ON stock_transfers(from_warehouse_id);
CREATE INDEX idx_stock_transfers_to_warehouse ON stock_transfers(to_warehouse_id);
CREATE INDEX idx_stock_transfers_status ON stock_transfers(status);

-- ===== ERP: ENTERPRISE RESOURCE PLANNING =====

CREATE TABLE products (
  product_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  sku VARCHAR(50) NOT NULL UNIQUE,
  product_name VARCHAR(255) NOT NULL,
  category_id UUID,
  unit_of_measure unit_of_measure NOT NULL DEFAULT 'EA',
  status product_status NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_products_category FOREIGN KEY (category_id) REFERENCES product_categories(category_id),
  CONSTRAINT fk_products_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);
CREATE INDEX idx_products_sku ON products(sku);
CREATE INDEX idx_products_status ON products(status);

CREATE TABLE suppliers (
  supplier_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  supplier_code VARCHAR(50) NOT NULL UNIQUE,
  supplier_name VARCHAR(255) NOT NULL,
  email VARCHAR(255),
  phone VARCHAR(20),
  business_registration VARCHAR(50),
  status supplier_status NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_suppliers_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);
CREATE INDEX idx_suppliers_code ON suppliers(supplier_code);

CREATE TABLE gl_accounts (
  account_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  account_code VARCHAR(50) NOT NULL UNIQUE,
  account_name VARCHAR(255) NOT NULL,
  account_type gl_account_type NOT NULL,
  status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_gl_accounts_created_by FOREIGN KEY (created_by) REFERENCES users(user_id)
);
CREATE INDEX idx_gl_accounts_code ON gl_accounts(account_code);
CREATE INDEX idx_gl_accounts_type ON gl_accounts(account_type);

CREATE TABLE vouchers (
  voucher_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  voucher_no VARCHAR(50) NOT NULL UNIQUE,
  document_date DATE NOT NULL,
  document_type voucher_document_type NOT NULL,
  description TEXT,
  total_debit NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  total_credit NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  status voucher_status NOT NULL DEFAULT 'DRAFT',
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified_by UUID,
  modified_at TIMESTAMP,
  deleted_by UUID,
  deleted_at TIMESTAMP,

  CONSTRAINT fk_vouchers_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT chk_totals_balance CHECK (total_debit = total_credit)
);
CREATE INDEX idx_vouchers_no ON vouchers(voucher_no);
CREATE INDEX idx_vouchers_document_date ON vouchers(document_date);
CREATE INDEX idx_vouchers_status ON vouchers(status);

CREATE TABLE voucher_lines (
  voucher_line_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  voucher_id UUID NOT NULL,
  line_no SMALLINT NOT NULL,
  account_id UUID NOT NULL,
  debit_amount NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  credit_amount NUMERIC(19,4) NOT NULL DEFAULT 0.0,
  description TEXT,
  created_by UUID NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT fk_voucher_lines_voucher FOREIGN KEY (voucher_id) REFERENCES vouchers(voucher_id),
  CONSTRAINT fk_voucher_lines_account FOREIGN KEY (account_id) REFERENCES gl_accounts(account_id),
  CONSTRAINT fk_voucher_lines_created_by FOREIGN KEY (created_by) REFERENCES users(user_id),
  CONSTRAINT uk_voucher_lines_voucher_lineno UNIQUE (voucher_id, line_no),
  CONSTRAINT chk_debit_amount CHECK (debit_amount >= 0),
  CONSTRAINT chk_credit_amount CHECK (credit_amount >= 0),
  CONSTRAINT chk_either_debit_or_credit CHECK ((debit_amount > 0 OR credit_amount > 0) AND NOT (debit_amount > 0 AND credit_amount > 0))
);
CREATE INDEX idx_voucher_lines_voucher_id ON voucher_lines(voucher_id);
CREATE INDEX idx_voucher_lines_account_id ON voucher_lines(account_id);

-- ===== AUDIT TRAIL (Principle 14: Traceability) =====

CREATE TABLE audit_logs (
  audit_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  entity_type VARCHAR(50) NOT NULL,
  entity_id UUID NOT NULL,
  operation audit_operation NOT NULL,
  old_value JSONB,
  new_value JSONB,
  changed_by UUID NOT NULL,
  changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  reason TEXT,

  CONSTRAINT fk_audit_logs_changed_by FOREIGN KEY (changed_by) REFERENCES users(user_id)
);
CREATE INDEX idx_audit_logs_entity ON audit_logs(entity_type, entity_id);
CREATE INDEX idx_audit_logs_changed_at ON audit_logs(changed_at);
CREATE INDEX idx_audit_logs_operation ON audit_logs(operation);

-- ===== AUDIT TRIGGER (Principle 14: Automatic Traceability) =====

CREATE OR REPLACE FUNCTION audit_trigger()
RETURNS TRIGGER AS $$
DECLARE
  v_entity_type VARCHAR;
  v_operation audit_operation;
BEGIN
  v_entity_type := TG_TABLE_NAME;

  IF TG_OP = 'INSERT' THEN
    v_operation := 'CREATE'::audit_operation;
    INSERT INTO audit_logs (entity_type, entity_id, operation, new_value, changed_by, changed_at)
    VALUES (v_entity_type, NEW.id, v_operation, to_jsonb(NEW), NEW.created_by, CURRENT_TIMESTAMP);
    RETURN NEW;

  ELSIF TG_OP = 'UPDATE' THEN
    v_operation := 'UPDATE'::audit_operation;
    INSERT INTO audit_logs (entity_type, entity_id, operation, old_value, new_value, changed_by, changed_at)
    VALUES (v_entity_type, OLD.id, v_operation, to_jsonb(OLD), to_jsonb(NEW), NEW.modified_by, CURRENT_TIMESTAMP);
    RETURN NEW;

  ELSIF TG_OP = 'DELETE' THEN
    v_operation := 'DELETE'::audit_operation;
    INSERT INTO audit_logs (entity_type, entity_id, operation, old_value, changed_by, changed_at)
    VALUES (v_entity_type, OLD.id, v_operation, to_jsonb(OLD), OLD.deleted_by, CURRENT_TIMESTAMP);
    RETURN OLD;
  END IF;

  RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- Note: Trigger creation for individual tables omitted to keep schema focused.
-- In production: CREATE TRIGGER for orders, inventory, products, etc.

-- ===== VIEWS (Convenience, Principle 3: Data Consistency) =====

CREATE VIEW v_order_summary AS
SELECT
  o.order_id,
  o.order_no,
  c.customer_name,
  o.order_date,
  COUNT(ol.line_id) as line_count,
  SUM(ol.line_total) as calculated_total,
  o.total_amount,
  o.status,
  o.created_at
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
LEFT JOIN order_lines ol ON o.order_id = ol.order_id
WHERE o.deleted_at IS NULL
GROUP BY o.order_id, o.order_no, c.customer_name, o.order_date, o.total_amount, o.status, o.created_at;

CREATE VIEW v_inventory_summary AS
SELECT
  i.warehouse_id,
  w.warehouse_name,
  i.product_id,
  p.sku,
  p.product_name,
  i.qty_on_hand,
  i.qty_reserved,
  i.qty_available,
  i.status,
  i.modified_at
FROM inventory i
LEFT JOIN warehouses w ON i.warehouse_id = w.warehouse_id
LEFT JOIN products p ON i.product_id = p.product_id
WHERE i.deleted_at IS NULL;

CREATE VIEW v_voucher_totals AS
SELECT
  v.voucher_id,
  v.voucher_no,
  v.document_type,
  v.document_date,
  SUM(COALESCE(vl.debit_amount, 0)) as calculated_debit,
  SUM(COALESCE(vl.credit_amount, 0)) as calculated_credit,
  v.total_debit,
  v.total_credit,
  v.status,
  COUNT(vl.voucher_line_id) as line_count
FROM vouchers v
LEFT JOIN voucher_lines vl ON v.voucher_id = vl.voucher_id
WHERE v.deleted_at IS NULL
GROUP BY v.voucher_id, v.voucher_no, v.document_type, v.document_date, v.total_debit, v.total_credit, v.status;

-- ===== INITIAL DATA (Seed) =====

-- Create initial admin user
INSERT INTO users (user_id, email, password_hash, name, role, status, created_by, created_at)
VALUES (
  '00000000-0000-0000-0000-000000000001'::UUID,
  'admin@quantengine.dev',
  '$2b$12$R9h7cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUe', -- bcrypt: admin123!
  'System Administrator',
  'ADMIN',
  'ACTIVE',
  '00000000-0000-0000-0000-000000000001'::UUID,
  CURRENT_TIMESTAMP
) ON CONFLICT DO NOTHING;

-- Create initial warehouses
INSERT INTO warehouses (warehouse_code, warehouse_name, location, status, created_by, created_at)
VALUES
  ('WH-SEOUL', 'Seoul Main Warehouse', 'Seoul, KR', 'ACTIVE', '00000000-0000-0000-0000-000000000001'::UUID, CURRENT_TIMESTAMP),
  ('WH-BUSAN', 'Busan Distribution Center', 'Busan, KR', 'ACTIVE', '00000000-0000-0000-0000-000000000001'::UUID, CURRENT_TIMESTAMP),
  ('WH-INCHEON', 'Incheon Port Warehouse', 'Incheon, KR', 'ACTIVE', '00000000-0000-0000-0000-000000000001'::UUID, CURRENT_TIMESTAMP)
ON CONFLICT DO NOTHING;

-- Create initial product category
INSERT INTO product_categories (category_name, description, status, created_by, created_at)
VALUES
  ('Standard Products', 'Regular inventory items', 'ACTIVE', '00000000-0000-0000-0000-000000000001'::UUID, CURRENT_TIMESTAMP),
  ('Premium Products', 'High-value items', 'ACTIVE', '00000000-0000-0000-0000-000000000001'::UUID, CURRENT_TIMESTAMP)
ON CONFLICT DO NOTHING;

-- ===== GRANTS (Security - Principle 23) =====

-- Application role (read-write for normal operations)
CREATE ROLE quantengine_app LOGIN PASSWORD 'CHANGE_ME_PROD';
GRANT USAGE ON SCHEMA quantengine TO quantengine_app;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA quantengine TO quantengine_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA quantengine TO quantengine_app;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA quantengine TO quantengine_app;

-- Read-only role (for analytics/reporting)
CREATE ROLE quantengine_readonly LOGIN PASSWORD 'CHANGE_ME_PROD';
GRANT USAGE ON SCHEMA quantengine TO quantengine_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA quantengine TO quantengine_readonly;
GRANT SELECT ON ALL VIEWS IN SCHEMA quantengine TO quantengine_readonly;

-- ===== COMMENTS (Documentation - Principle 28) =====

COMMENT ON SCHEMA quantengine IS 'OMS·WMS·ERP Unified Platform - Phase 0 Database Schema';
COMMENT ON TABLE orders IS 'Order master records (OMS) - Principle 14: Complete audit trail via audit_logs';
COMMENT ON TABLE inventory IS 'Warehouse inventory positions (WMS) - qty_available computed from on_hand - reserved';
COMMENT ON TABLE audit_logs IS 'Universal change audit trail - every mutation logged for compliance + recovery (Principle 14)';
COMMENT ON TABLE vouchers IS 'Accounting journal entries (ERP) - Principle 23: NUMERIC(19,4) for decimal precision';
