Kulcare Docs

Inventory Ledger Foundation QA

Unit 1 checks for Inventory identities, schema constraints, immutable history, and tenant isolation.

This guide covers local Unit 1 of the source-ledger plan. Use the API contract for the full stock rules. The Inventory developer guide records accepted recommendations, source implementation, and open release gates. Unit 1 adds schema and models. It does not add stock commands, Inventory HTTP endpoints, or live Hospital inventory workflows. Later U2-U6 add source policies, commands, APIs, and pilot controls. This checklist keeps the U1 boundary; run it against the final schema as well. Do not use the mock Hospital inventory screen to accept this unit.

Test Setup

Use a disposable local test database. Do not point these checks at development, staging, or production data. Use Ruby 3.4.9 and the repository's installed gems. Apply migrations through the supported Rails task. Do not add schema objects by hand.

From backend/, set DATABASE_URL to the disposable database, then run:

RAILS_ENV=test bin/rails db:migrate
RAILS_ENV=test bin/rails db:test:prepare
RAILS_ENV=test bin/rails db:rls_test_role:provision
PARALLEL_WORKERS=1 bin/rails test domains/inventory/test
bundle exec rubocop domains/inventory config/initializers/domains.rb test/test_helper.rb lib/tasks/db_rls_test_role.rake

The RLS checks must run with no skips. The provision task must grant Inventory schema and table access. A permission-denied error caused by missing schema grants is not evidence of tenant isolation. If the schema snapshot changes, repeat preparation and role provisioning before tests. Rails can reload a changed snapshot and remove its table grants. Do not accept a passing result with skipped security checks. db:migrate can rewrite structure.sql. Keep only the additive Inventory objects and migration version in the proposed change.

Unit-End Manual Checklist

Record the branch or commit, database name, PostgreSQL version, tester, and test output with the issue or PR. These boxes record future QA acceptance, not automated tests already passed.

  • Load the schema into an empty disposable database. Verify all 13 foundation tables exist and migration 20261011000001 is recorded. The complete U6 schema has 16 Inventory tables.
  • Confirm UUID identities and non-null tenant/facility fields on every Inventory table.
  • Confirm every table has ENABLE and FORCE RLS, with tenant predicates for reads and writes.
  • Under kulcare_rls_test, verify an owning tenant can read every populated Inventory table and insert its own stock item.
  • Clear tenant context. Verify raw SQL reads expose no Inventory rows and a stock-item insert fails.
  • Set another tenant's context. Verify raw SQL reads expose no rows, inserts fail, and updates/deletes affect no rows. Restore the owning context and confirm the records remain.
  • Create two facilities in one test tenant. Try to mix their item, location, operation, reservation, and balance IDs. Verify database constraints reject the writes.
  • Verify item and location codes are facility-scoped. Duplicate display names remain allowed.
  • Insert a second untracked balance with the same identity and null lot/serial IDs. Verify rejection. A separate location must remain valid.
  • Test negative on-hand, negative reserved quantity, and reserved quantity above on-hand. Verify rejection without rounding or adjustment.
  • Test fractional countable stock, an invalid item increment, excess decimal precision, and quantity overflow. Verify rejection. A valid exact fractional item quantity must persist unchanged.
  • Place one serial in two locations or conditions with positive stock. Verify rejection. An atomic source-zero/destination-one transfer must leave exactly one physical unit.
  • Record an unresolved-expiry lot. Verify no cutoff is inferred. Persist test expiry revisions and verify source label, precision, rule/version, approval reference, timezone, reason, and prior revision are retained.
  • Try to link a current or prior expiry validation from another lot. Verify rejection. Do not treat this storage check as approval verification; that command is Unit 3 work.
  • Attempt raw updates/deletes of operations, movement entries, conversion versions, expiry validations, and reservation events under the application test role. Verify append-only rejection.
  • Confirm projection quantities can still be updated under valid constraints. A source command, not manual edits, will own these writes after Unit 3.
  • Try to change base units or tracking rules after stock history exists. Verify rejection and preservation of history.
  • Repeat an operation key or an opening/receipt source line under a different key. Verify database uniqueness rejects duplicate identities. Idempotent response behavior remains Unit 3 work.
  • Write a movement with a conversion ID but no version, then with the wrong version. Verify both writes fail. The matching conversion and version must remain valid.
  • Write a reservation allocation event with no quantity or a fractional countable quantity. Verify rejection. Header events have no allocation or quantity; allocation events use exact item base units.
  • Roll back and reapply the migration on an unused schema. Verify no schema objects remain after rollback. Try rollback with confirmed history under a table owner subject to forced RLS and no tenant context. Verify it refuses to delete the ledger and leaves FORCE RLS active.
  • Compare the schema snapshot with the migration. Verify no existing schema objects were removed or changed.
  • Attach test results and remaining limits to issue #2517. Leave the issue open for QA.

Release Limits

Do not seed Inventory permissions without the real policies and RBAC agreements from Unit 2. Do not expose stock mutations until command, retry, expiry, and concurrency checks from Units 3 and 4 pass. U1's stored approval reference alone is not a server-verified expiry approval workflow. U3 adds that verification. Units 5 and 6 add source APIs and reconciliation evidence. Hospital U10 connects the UI only after source-ledger delivery. This unit does not complete D1, Hospital inventory, pharmacy readiness, MAR stock integration, or package billing.

Local Evidence

The first foundation run failed on the missing domain registration and factories. Regression tests reproduced missing and mismatched conversion versions. The check and scoped foreign key were corrected. Another regression test reproduced a rollback guard that missed history under forced RLS. The guard now locks stock tables and checks history across tenants within the migration transaction. The migration applied on an isolated PostgreSQL 17.11 test database. Unused-schema rollback and forward application passed. The final focused suite passed on both disposable databases: 27 tests, 335 assertions, no failures, errors, or skips. The scoped Ruby lint check passed for all 22 files. CodeRabbit reviewed 24 scoped files. Its reservation-event quantity finding was reproduced and fixed. The second review completed with no findings. The full CE review could not finish under the repository's main-thread-only rule. The approved CodeRabbit review is the recorded fallback, not a completed CE review.

Hospital and identity RBAC regression tests ran without skips: 440 tests, 1,738 assertions, four failures, and no errors. All four failures concern missing or stale entries in the role-check catalog for unchanged Connect and staff code. They are not stock-ledger tests. The full backend run attempted 1,130 files in four shards. It produced no valid aggregate. Logs showed missing local configuration and keys, other test failures, and incomplete shards. Do not call backend CI green or activate Inventory writes from these results. The verification evidence is local. Deployment and operator QA are pending.

On this page