feat(db): audit schema hardening (onDelete, unique doc-numbers, indexes)

From the 2026-06-09 full-codebase audit. Warehouse line->header relations
CASCADE on delete; line->master-data and the financial FKs are explicit
RESTRICT; UNIQUE on receipt/issue/session numbers; new indexes on hot FK
columns (sklad_issues/receipts, bank_accounts); dropped a duplicate
audit_logs created_at index. Applied to dev `app` and `app_test`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-09 06:45:04 +02:00
parent b1f21a1f48
commit c454d1a3fc
2 changed files with 178 additions and 36 deletions

View File

@@ -0,0 +1,137 @@
-- Audit schema hardening (from the 2026-06-09 codebase audit).
--
-- ⚠️ PENDING — NOT YET APPLIED. Review, then apply with the dev server stopped:
-- npx prisma migrate deploy (prod / already-tracked)
-- -- or, in dev, `npx prisma migrate dev` will pick it up as pending.
--
-- What this does:
-- • Warehouse line→header relations now CASCADE on delete (deleting a
-- receipt/issue/inventory session removes its lines/attachments).
-- • Warehouse line→master-data (item/batch/location) and the financial FKs
-- (invoices/orders/projects/quotations → customer/order/quotation) are now
-- explicit ON DELETE RESTRICT — preventing deletion of a referenced master
-- record / orphaning of a financial record. (Some of these were previously
-- the optional-relation default SET NULL; RESTRICT is the safer intent.)
-- • UNIQUE on warehouse document numbers (receipt_number/issue_number/
-- session_number) — like every other document-number column.
-- • New indexes on hot FK filters (sklad_issues/receipts, bank_accounts).
--
-- ⚠️ BEFORE APPLYING ON PRODUCTION, verify existing data won't violate the new
-- constraints: no DUPLICATE non-null receipt/issue/session numbers (else the
-- UNIQUE index fails), and no rows that would break the RESTRICT FKs. Test on
-- a copy first.
--
-- DropForeignKey
ALTER TABLE `invoices` DROP FOREIGN KEY `invoices_ibfk_1`;
-- DropForeignKey
ALTER TABLE `invoices` DROP FOREIGN KEY `invoices_ibfk_2`;
-- DropForeignKey
ALTER TABLE `orders` DROP FOREIGN KEY `orders_ibfk_1`;
-- DropForeignKey
ALTER TABLE `orders` DROP FOREIGN KEY `orders_ibfk_2`;
-- DropForeignKey
ALTER TABLE `projects` DROP FOREIGN KEY `projects_ibfk_1`;
-- DropForeignKey
ALTER TABLE `projects` DROP FOREIGN KEY `projects_ibfk_2`;
-- DropForeignKey
ALTER TABLE `projects` DROP FOREIGN KEY `projects_ibfk_3`;
-- DropForeignKey
ALTER TABLE `quotations` DROP FOREIGN KEY `quotations_ibfk_1`;
-- DropForeignKey
ALTER TABLE `sklad_receipt_lines` DROP FOREIGN KEY `sklad_receipt_lines_receipt_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_receipt_lines` DROP FOREIGN KEY `sklad_receipt_lines_location_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_receipt_attachments` DROP FOREIGN KEY `sklad_receipt_attachments_receipt_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_issue_lines` DROP FOREIGN KEY `sklad_issue_lines_issue_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_issue_lines` DROP FOREIGN KEY `sklad_issue_lines_location_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_inventory_lines` DROP FOREIGN KEY `sklad_inventory_lines_session_id_fkey`;
-- DropForeignKey
ALTER TABLE `sklad_inventory_lines` DROP FOREIGN KEY `sklad_inventory_lines_location_id_fkey`;
-- CreateIndex
CREATE INDEX `idx_bank_accounts_is_default` ON `bank_accounts`(`is_default`);
-- CreateIndex
CREATE UNIQUE INDEX `sklad_receipts_receipt_number_key` ON `sklad_receipts`(`receipt_number`);
-- CreateIndex
CREATE INDEX `sklad_receipts_supplier_id` ON `sklad_receipts`(`supplier_id`);
-- CreateIndex
CREATE INDEX `sklad_receipts_received_by` ON `sklad_receipts`(`received_by`);
-- CreateIndex
CREATE UNIQUE INDEX `sklad_issues_issue_number_key` ON `sklad_issues`(`issue_number`);
-- CreateIndex
CREATE INDEX `sklad_issues_project_id` ON `sklad_issues`(`project_id`);
-- CreateIndex
CREATE INDEX `sklad_issues_issued_by` ON `sklad_issues`(`issued_by`);
-- CreateIndex
CREATE UNIQUE INDEX `sklad_inventory_sessions_session_number_key` ON `sklad_inventory_sessions`(`session_number`);
-- AddForeignKey
ALTER TABLE `invoices` ADD CONSTRAINT `invoices_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `invoices` ADD CONSTRAINT `invoices_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `orders` ADD CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`quotation_id`) REFERENCES `quotations`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `orders` ADD CONSTRAINT `orders_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `projects` ADD CONSTRAINT `projects_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `projects` ADD CONSTRAINT `projects_ibfk_2` FOREIGN KEY (`quotation_id`) REFERENCES `quotations`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `projects` ADD CONSTRAINT `projects_ibfk_3` FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `quotations` ADD CONSTRAINT `quotations_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `sklad_receipt_lines` ADD CONSTRAINT `sklad_receipt_lines_receipt_id_fkey` FOREIGN KEY (`receipt_id`) REFERENCES `sklad_receipts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_receipt_lines` ADD CONSTRAINT `sklad_receipt_lines_location_id_fkey` FOREIGN KEY (`location_id`) REFERENCES `sklad_locations`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_receipt_attachments` ADD CONSTRAINT `sklad_receipt_attachments_receipt_id_fkey` FOREIGN KEY (`receipt_id`) REFERENCES `sklad_receipts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_issue_lines` ADD CONSTRAINT `sklad_issue_lines_issue_id_fkey` FOREIGN KEY (`issue_id`) REFERENCES `sklad_issues`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_issue_lines` ADD CONSTRAINT `sklad_issue_lines_location_id_fkey` FOREIGN KEY (`location_id`) REFERENCES `sklad_locations`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_inventory_lines` ADD CONSTRAINT `sklad_inventory_lines_session_id_fkey` FOREIGN KEY (`session_id`) REFERENCES `sklad_inventory_sessions`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `sklad_inventory_lines` ADD CONSTRAINT `sklad_inventory_lines_location_id_fkey` FOREIGN KEY (`location_id`) REFERENCES `sklad_locations`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;