{
 "migrations": {
  "file": "000001_init_schema.sql",
  "comment": "(sales_order_items.quantity stays NUMERIC(12,2)); BOOLEAN for tinyint(1); JSONB for JSON; TIMESTAMPTZ timestamps with now() defaults so INSERT ... RETURNING created_at/updated_at works; generated column for opname difference; per-day document sequences table (migration-plan.md \u00a73). 0. migration tracking + document sequences"
 },
 "document_number_sequences": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "users": {
  "file": "000001_init_schema.sql",
  "comment": "1. auth / HR (referenced by partners, sales, warehouses)"
 },
 "roles": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "employees": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "categories": {
  "file": "000001_init_schema.sql",
  "comment": "2. master data"
 },
 "units": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "suppliers": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "customers": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "warehouses": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "products": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "stocks": {
  "file": "000001_init_schema.sql",
  "comment": "3. inventory"
 },
 "stock_movements": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "stock_opnames": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "stock_opname_items": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "stock_transfers": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "stock_transfer_items": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "sales_orders": {
  "file": "000001_init_schema.sql",
  "comment": "4. sales / POS"
 },
 "sales_order_items": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "purchase_orders": {
  "file": "000001_init_schema.sql",
  "comment": "5. purchasing"
 },
 "purchase_order_items": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "goods_receipts": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "goods_receipt_items": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "invoices": {
  "file": "000001_init_schema.sql",
  "comment": "6. finance"
 },
 "payments": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "cashflows": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "vouchers": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "activity_logs": {
  "file": "000001_init_schema.sql",
  "comment": "7. activity log"
 },
 "sales_visits": {
  "file": "000001_init_schema.sql",
  "comment": "8. sales tracking"
 },
 "sales_activities": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "sales_routes": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "sales_locations": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "attendances": {
  "file": "000001_init_schema.sql",
  "comment": "9. HR"
 },
 "payrolls": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "leaves": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "performances": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "personal_access_tokens": {
  "file": "000001_init_schema.sql",
  "comment": "10. framework parity tables (unused by Go; Redis replaces cache/session)"
 },
 "sessions": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "cache": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "cache_locks": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "jobs": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "job_batches": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "failed_jobs": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "password_reset_tokens": {
  "file": "000001_init_schema.sql",
  "comment": ""
 },
 "carts": {
  "file": "000002_add_cart.sql",
  "comment": "000002_add_cart.up.sql Cart tables for B2B frontend session-based cart storage. Each user has one active cart; cart_items reference products."
 },
 "cart_items": {
  "file": "000002_add_cart.sql",
  "comment": ""
 },
 "accounting_periods": {
  "file": "000006_finance_contract_guards.sql",
  "comment": ""
 },
 "sales_order_status_history": {
  "file": "000006_finance_contract_guards.sql",
  "comment": ""
 },
 "fleet": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "delivery_orders": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "delivery_order_items": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "shipments": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "shipment_items": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "dispatches": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "delivery_status_history": {
  "file": "000008_distribution_foundation.sql",
  "comment": ""
 },
 "shipment_tracking_events": {
  "file": "000009_shipment_tracking.sql",
  "comment": ""
 },
 "brands": {
  "file": "000010_catalog_brands_units_barcodes.sql",
  "comment": "Brands, configured product units with conversion factors, unit-specific price/minimum purchase, and product barcodes as identifiers distinct from product code/SKU and document numbers. Conversion factors are configuration only; nothing here hard-codes pcs/box/carton relationships."
 },
 "product_units": {
  "file": "000010_catalog_brands_units_barcodes.sql",
  "comment": "product_units: the authoritative per-unit sales configuration. conversion_factor expresses how many base units one configured unit contains; the base unit row is always factor 1. selling_price NULL means \"fall back to products.selling_price scaled by the pricing engine\" (Phase 6 item 2 owns that resolution)."
 },
 "product_barcodes": {
  "file": "000010_catalog_brands_units_barcodes.sql",
  "comment": "product_barcodes: barcode is a globally unique identifier, separate from products.code (SKU) and from document numbers (\u00a712, \u00a716). A barcode may be scoped to one configured product unit (box vs pcs scan) or to the product."
 },
 "memberships": {
  "file": "000012_membership_identity.sql",
  "comment": "User -> Customer -> Membership split and exactly three tiers. Benefit formulas, upgrade/downgrade triggers, and expiry policy are UNRESOLVED (business-rules.md \u00a720 items 1 and 4) and are NOT modelled here - no discount percentages, no point balances, no automatic tier thresholds."
 },
 "membership_tier_history": {
  "file": "000012_membership_identity.sql",
  "comment": "Append-only tier audit. Every tier assignment and change lands here with the actor and a reason, so whichever upgrade/downgrade policy is confirmed later can be reconstructed and verified against history."
 },
 "membership_tiers": {
  "file": "000014_membership_tier_config.sql",
  "comment": "STEP 0: database-backed membership tier configuration (business-rules.md \u00a713.1)."
 },
 "membership_tier_config_history": {
  "file": "000014_membership_tier_config.sql",
  "comment": "Append-only audit of tier configuration changes."
 },
 "sales_vouchers": {
  "file": "000015_sales_vouchers.sql",
  "comment": ""
 },
 "galon_transactions": {
  "file": "000016_galon.sql",
  "comment": "DEFAULT PENDING CONFIRMATION (\u00a720 #3): deposit_amount, loan fee, penalty, due date/expiry, individual-container identity and per-customer container balance are NOT yet confirmed. deposit_amount defaults to 0 and is carried as a column so the confirmed policy can be applied later without a schema change to the transaction shape."
 },
 "sales_returns": {
  "file": "000017_sales_returns.sql",
  "comment": " DEFAULT PENDING CONFIRMATION (\u00a720 #4): refund method defaults to cash; tax/promotion allocation, damaged-return handling and quarantine stock are NOT implemented \u2014 every accepted return restocks in full and refunds the pro-rata snapshot amount until the business confirms otherwise."
 },
 "sales_return_items": {
  "file": "000017_sales_returns.sql",
  "comment": ""
 },
 "cashier_shifts": {
  "file": "000018_cashier_shifts.sql",
  "comment": "cash-method POS sales linked to the shift.  DEFAULT PENDING CONFIRMATION (\u00a720 #5): shifts are NOT bound to a register/store and a cashier may only hold one open shift at a time; register binding and cross-register movement await business confirmation."
 },
 "cashier_drawer_entries": {
  "file": "000018_cashier_shifts.sql",
  "comment": ""
 },
 "warehouse_deposits": {
  "file": "000059_warehouse_deposits.sql",
  "comment": "000059_warehouse_deposits.sql: create warehouse_deposits table for driver cash deposit workflow."
 },
 "report_templates": {
  "file": "000064_report_templates.sql",
  "comment": "000064_report_templates.sql: Table for NextReport visual templates & versioning"
 },
 "sales_targets": {
  "file": "000087_sales_targets.sql",
  "comment": "Migration 000087: sales targets and sales activities expansion"
 },
 "buyer_addresses": {
  "file": "000096_buyer_addresses.sql",
  "comment": " Default flags are enforced at the application layer (clear-others-then-set inside a transaction) and backed by partial unique indexes so a race can never leave two default rows for the same user."
 },
 "lhpp_groups": {
  "file": "000101_lhpp_manual_groups.sql",
  "comment": "valid \u2014 and then the sequence advanced past what the backfill allocated.  NO CREATE INDEX CONCURRENTLY: dbmigrate.applyRevision runs each file as one tx.Exec, and CONCURRENTLY cannot run inside a transaction block."
 },
 "lhpp_group_items": {
  "file": "000101_lhpp_manual_groups.sql",
  "comment": "membership: delivery_order_id is the invariant (at most one group, ever)."
 },
 "lhpp_group_history": {
  "file": "000101_lhpp_manual_groups.sql",
  "comment": ""
 },
 "tickets": {
  "file": "000122_support_tickets.sql",
  "comment": "000122_support_tickets.sql: Centralized Support Ticketing System  Creates tables for support tickets and comments across ERP, POS, and B2B apps. Seeds initial permissions for support.tickets.view, support.tickets.create, support.tickets.manage."
 },
 "ticket_comments": {
  "file": "000122_support_tickets.sql",
  "comment": ""
 }
}