001-quality-init.xml 3.67 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-quality initial schema (P5.8 — v1 recording-only).

        Owns: quality__inspection_record.

        Append-only record of "item X was inspected under source
        reference Y, decision was APPROVED/REJECTED, inspected/
        rejected quantities, who recorded it". No FK to item or
        source — cross-PBC references by code, validated at the
        application layer (CatalogApi on record()).

        Constraints:
          * decision IN (APPROVED, REJECTED)
          * inspected_quantity > 0
          * rejected_quantity >= 0
          * rejected_quantity <= inspected_quantity
          * decision=APPROVED  ↔  rejected_quantity = 0
          * decision=REJECTED  ↔  rejected_quantity > 0
        The application service enforces the biconditional; the
        schema enforces the weaker "rejected is within bounds" rule
        so a direct DB insert can't fabricate nonsense.
    -->

    <changeSet id="quality-init-001" author="vibe_erp">
        <comment>Create quality__inspection_record table</comment>
        <sql>
            CREATE TABLE quality__inspection_record (
                id                      uuid PRIMARY KEY,
                code                    varchar(64)   NOT NULL,
                item_code               varchar(64)   NOT NULL,
                source_reference        varchar(128)  NOT NULL,
                decision                varchar(16)   NOT NULL,
                inspected_quantity      numeric(18,4) NOT NULL,
                rejected_quantity       numeric(18,4) NOT NULL,
                inspector               varchar(128)  NOT NULL,
                reason                  varchar(512),
                inspected_at            timestamptz   NOT NULL,
                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 quality__inspection_record_decision_check
                    CHECK (decision IN ('APPROVED', 'REJECTED')),
                CONSTRAINT quality__inspection_record_inspected_pos
                    CHECK (inspected_quantity &gt; 0),
                CONSTRAINT quality__inspection_record_rejected_nonneg
                    CHECK (rejected_quantity &gt;= 0),
                CONSTRAINT quality__inspection_record_rejected_bounded
                    CHECK (rejected_quantity &lt;= inspected_quantity)
            );
            CREATE UNIQUE INDEX quality__inspection_record_code_uk
                ON quality__inspection_record (code);
            CREATE INDEX quality__inspection_record_item_idx
                ON quality__inspection_record (item_code);
            CREATE INDEX quality__inspection_record_source_idx
                ON quality__inspection_record (source_reference);
            CREATE INDEX quality__inspection_record_decision_idx
                ON quality__inspection_record (decision);
            CREATE INDEX quality__inspection_record_inspected_at_idx
                ON quality__inspection_record (inspected_at);
        </sql>
        <rollback>
            DROP TABLE quality__inspection_record;
        </rollback>
    </changeSet>

</databaseChangeLog>