003-production-v3.xml 4.8 KB
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                                       https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd">

    <!--
        pbc-production v3 schema additions — routings & operations.

        Creates production__work_order_operation — each row is one
        step on a work order's routing. An empty list is legal and
        preserves the v2 behavior exactly (no gating on complete).
        A non-empty list gates WorkOrder.complete() behind every
        operation's COMPLETED status and enforces a strict sequential
        walk of started-then-completed.

        Per-operation state machine:
          PENDING      — created but not yet started
          IN_PROGRESS  — the current operation (at most ONE per WO)
          COMPLETED    — done; predecessor for the next operation to start

        Sequential rule, enforced in WorkOrderService:
          - startOperation(op N)   requires parent WO = IN_PROGRESS,
                                   op N = PENDING,
                                   op [1..N-1] all COMPLETED.
          - completeOperation(op N) requires parent WO = IN_PROGRESS
                                   and op N = IN_PROGRESS. Writes
                                   actual_minutes + completed_at.
          - WorkOrder.complete()   refuses if ANY op is not COMPLETED.

        NOT MODELLED at v3:
          - Parallel operations. v3 enforces a strict linear chain so
            the shop floor walks one step at a time. Parallel routings
            (two presses running in parallel) wait for a real consumer.
          - Capacity / scheduling. work_center is just a free-form
            label; v3 does not reserve anything.
          - Operator assignment / labor logging. actual_minutes is the
            only time value stored on completion; who did the work
            is inferred from the standard audit columns.
          - Machine FK. work_center is a varchar label, not a FK to
            a future pbc-equipment table. Same rationale as every
            other cross-PBC identifier in pbc-production: refs are
            application-enforced, not DB-enforced (CLAUDE.md #9).
    -->

    <changeSet id="production-v3-001-work-order-operation" author="vibe_erp">
        <comment>Create production__work_order_operation (routing step child table)</comment>
        <sql>
            CREATE TABLE production__work_order_operation (
                id                      uuid PRIMARY KEY,
                work_order_id           uuid           NOT NULL
                    REFERENCES production__work_order(id) ON DELETE CASCADE,
                line_no                 integer        NOT NULL,
                operation_code          varchar(64)    NOT NULL,
                work_center             varchar(64)    NOT NULL,
                standard_minutes        numeric(10,2)  NOT NULL,
                status                  varchar(16)    NOT NULL,
                actual_minutes          numeric(10,2),
                started_at              timestamptz,
                completed_at            timestamptz,
                created_at              timestamptz    NOT NULL,
                created_by              varchar(128)   NOT NULL,
                updated_at              timestamptz    NOT NULL,
                updated_by              varchar(128)   NOT NULL,
                version                 bigint         NOT NULL DEFAULT 0,
                CONSTRAINT production__work_order_operation_status_check
                    CHECK (status IN ('PENDING', 'IN_PROGRESS', 'COMPLETED')),
                CONSTRAINT production__work_order_operation_line_no_pos
                    CHECK (line_no &gt; 0),
                CONSTRAINT production__work_order_operation_std_min_pos
                    CHECK (standard_minutes &gt;= 0),
                CONSTRAINT production__work_order_operation_act_min_pos
                    CHECK (actual_minutes IS NULL OR actual_minutes &gt;= 0),
                CONSTRAINT production__work_order_operation_line_uk
                    UNIQUE (work_order_id, line_no)
            );
            CREATE INDEX production__work_order_operation_wo_idx
                ON production__work_order_operation (work_order_id);
            CREATE INDEX production__work_order_operation_status_idx
                ON production__work_order_operation (status);
            CREATE INDEX production__work_order_operation_work_center_idx
                ON production__work_order_operation (work_center);
        </sql>
        <rollback>
            DROP TABLE production__work_order_operation;
        </rollback>
    </changeSet>

</databaseChangeLog>