# PHASE 1 TECHNICAL AUDIT

Audit date: 21 September 2026  
Scope: Meyalabs Health marketplace multi-apotek, P0 only. This is an initial code and automated-test audit; production readiness is not yet granted.

## P0.1 Mixed Cart Multi-Apotek to Payment

Status: PARTIAL

Current implementation: `CheckoutService::createMultiOrder()` groups cart items by tenant, creates one `PlatformOrder`, multiple `SellerOrder` records, and one shipping quote per seller order. Both web and API checkout use this flow. `PaymentService` creates a single payment for the platform grand total and settles all sibling seller orders.

Problem: The legacy `createOrder()` path still assumes the first cart item's pharmacy. The physical payment record retains a required `seller_order_id`, which previously made refunds and payment status lookup depend on the initiating seller order rather than the platform order.

Risk: Incorrect seller payment/refund visibility in a mixed checkout; a legacy caller can create a cross-tenant-inconsistent order.

Recommended fix: Keep the existing API contract, treat `platform_order_id` as the payment boundary, make legacy creation delegate to or reject mixed carts safely, and add web/API mixed-cart contract tests.

## P0.2 Tenant Isolation

Status: PARTIAL

Current implementation: Tenant-aware web middleware, global tenant scope, membership/role middleware, and API workspace controllers generally filter resources by tenant and relationship.

Problem: Coverage is inconsistent by entry point, and current tests are not yet a complete matrix for every protected resource and action.

Risk: A missing scope or route binding check can expose another pharmacy's data through direct URLs or API identifiers.

Recommended fix: Add a cross-tenant authorization test matrix for products, variants, orders, prescription, chat, promotions, finance, outlets, pharmacists, reports, settlement and withdrawal; make every failing query explicitly tenant-scoped.

## P0.3 Stock Reservation and Race Conditions

Status: PARTIAL

Current implementation: Reservations are transactional, use row locking, have TTL/release flows, and are consumed after payment.

Problem: Payment-time inventory validation queried inventory by product but not product variant.

Risk: A variant could be paid using the availability of a different variant of the same product.

Recommended fix: Query by `product_variant_id` too, retain database locking, and add a two-variant plus concurrent-final-stock regression suite.

## P0.4 Payment Webhook Duplicate and Retry

Status: PARTIAL

Current implementation: Payment `external_id` is unique. Webhook processing locks the payment and returns without side effects when it is no longer pending. Success, failure, and expiry transitions use transactions.

Problem: Out-of-order callback behaviour and side-effect assertions must be expanded across the platform-order sibling set.

Risk: Repeated or reordered provider callbacks could leave inconsistent observability or untested duplicate side effects.

Recommended fix: Add transaction-level regression tests for duplicate success, pending-to-expire, pending-to-fail, and out-of-order callbacks; retain the lock-and-terminal-state guard.

## P0.5 Partial Refund Seller Order

Status: FAIL

Current implementation: Refund amount and platform partial-refund status are calculated, and ledger records are created.

Problem: Refund requests read payments from the selected `SellerOrder`, although a mixed checkout stores its sole payment against the initiating seller order.

Risk: A valid refund for a different seller order cannot be requested. Item-level refund state is also not independently modelled.

Recommended fix: Resolve paid payment from `PlatformOrder`, keep legacy seller payment association for compatibility, add cross-seller refund tests, and assess item-level refund modelling separately.

## P0.6 Shipping Failure After Payment

Status: PARTIAL

Current implementation: Shipment creation and booking are jobs; shipment records expose pending, booking, failed, and reconciliation-required states. Duplicate booking is guarded by locks and provider identifiers.

Problem: Operational retry visibility and retry authorization require route/UI and job-policy verification.

Risk: A temporary provider failure may remain operationally unresolved without a clear authorized retry path.

Recommended fix: Verify and test seller/admin retry action, use bounded job retry/backoff, and assert one shipment/external ID for repeated dispatch.

## P0.7 Merchant License and Pharmacist State

Status: PARTIAL

Current implementation: Public catalog and payment guards require an active, approved tenant. Tenant license approval/expiry and verification statuses are maintained without deleting history.

Problem: The exact matrix for expired/inactive pharmacist versus historical-order fulfilment is not yet verified end-to-end.

Risk: Merchant compliance policy may be applied inconsistently between catalogue, checkout, prescription, and workspace endpoints.

Recommended fix: Define and enforce an explicit status matrix for create/publish, checkout, prescription review, historical order access, and reports; add tests for every terminal compliance state.

## Baseline Test Environment

The project default PHPUnit configuration uses SQLite, but the installed PHP 8.5 runtime does not load the SQLite extension. A dedicated MySQL test configuration already exists and was used with an isolated `meyahealth_test` database. The production-local database was not modified.

## Implementation Log — P0 Remediation Increment 1

### TASK: Platform payment lookup for seller-order refund

STATUS: Implemented and regression tested.

FILES CHANGED: `app/Services/RefundService.php`, `app/Http/Controllers/Api/V1/CheckoutController.php`, `tests/Feature/RefundWorkflowTest.php`.

DATABASE CHANGES: None.

ROOT CAUSE: A single platform payment was stored with the initiating seller order for legacy compatibility, while refund and API status lookup treated that seller order as the payment boundary.

IMPLEMENTATION: Payment lookup now follows `PlatformOrder -> payments`; `seller_order_id` remains unchanged for existing clients and records.

TESTS ADDED: A refund request against a non-initiating seller order in the same platform checkout.

TEST RESULT: Passed (1 test, 3 assertions) on isolated MySQL test database.

BACKWARD COMPATIBILITY: Existing seller-order payment endpoint and payment record shape are retained.

REMAINING RISK: Item-level refund allocation has no item-refund data model yet; therefore P0.5 remains PARTIAL.

### TASK: Variant-safe payment-time stock validation

STATUS: Implemented; broad stock regression suite passed.

FILES CHANGED: `app/Services/PaymentGuardService.php`, `tests/Feature/InventoryConcurrencyTest.php`.

DATABASE CHANGES: None.

ROOT CAUSE: Payment-time stock validation selected inventory by product but omitted `product_variant_id`.

IMPLEMENTATION: Inventory lookup now includes the nullable variant identifier, matching reservation and consumption queries.

TESTS ADDED: Existing stock regression tests were migrated from removed listing models to the active `Product`/`OutletInventory` model structure.

TEST RESULT: Included in the P0 regression run below.

BACKWARD COMPATIBILITY: Null variants remain supported; no endpoint or schema changed.

REMAINING RISK: A real parallel-process test should be added using separate database connections, rather than only sequential lock contention simulation.

### TASK: Prescription decision compliance enforcement

STATUS: Implemented and regression tested.

FILES CHANGED: `app/Http/Controllers/PharmacistDashboardController.php`, `tests/Feature/PharmacistComplianceTest.php`.

DATABASE CHANGES: None.

ROOT CAUSE: Tenant membership with role `pharmacy` permitted prescription decisions without checking the actor's pharmacist verification, active flag, or license expiry.

IMPLEMENTATION: Prescription decision now requires an approved, active pharmacist profile for the current tenant with no expired license.

TESTS ADDED: Expired pharmacist credential cannot approve a submitted prescription.

TEST RESULT: Passed (1 test, 2 assertions) on isolated MySQL test database.

BACKWARD COMPATIBILITY: Login, dashboard, historical orders, and reports are unchanged; only the regulated prescription-decision action is restricted.

REMAINING RISK: Compliance behaviour for every merchant status and all API prescription endpoints still requires a full matrix test.

### P0 Regression Result

Command scope: tenant isolation, inventory reservation, payment webhook idempotency, refund workflow, and shipping webhook.

Result: **PASS — 30 tests, 87 assertions** on `meyahealth_test` (isolated MySQL test database).

The passing suite is a verified remediation increment, not Phase 1 production acceptance. P0.1, P0.4, P0.5, P0.6, and P0.7 still require the additional scenario coverage identified above before their audit status can be raised to PASS.

## Implementation Log — P0 Remediation Increment 2

### TASK: Prevent legacy checkout from corrupting a mixed cart

STATUS: Implemented and regression tested.

FILES CHANGED: `app/Services/CheckoutService.php`, `tests/Feature/Marketplace/LegacyCheckoutSafetyTest.php`.

DATABASE CHANGES: None.

ROOT CAUSE: The legacy single-seller `createOrder()` accepted only one shipping quote but used the first cart product's tenant for all cart items.

IMPLEMENTATION: The method now rejects carts containing more than one tenant before opening a database transaction. The web and API checkout paths continue to use `createMultiOrder()` for multi-apotek checkout.

TESTS ADDED: Mixed-cart invocation of the legacy method throws before creating an order.

TEST RESULT: Passed as part of the full P0 suite.

BACKWARD COMPATIBILITY: Single-pharmacy callers retain the legacy return type and behaviour. Mixed carts are already supported by the current web/API checkout contract.

REMAINING RISK: Add a full three-pharmacy web/API checkout contract test with voucher and distinct shipping quotes before elevating P0.1 to PASS.

### TASK: Idempotent shipment retry and recovery path

STATUS: Implemented and regression tested.

FILES CHANGED: `app/Services/ShipmentService.php`, `app/Jobs/BookShipmentJob.php`, `app/Http/Controllers/SellerOrderFulfillmentController.php`, `app/Http/Controllers/Api/V1/PharmacyWorkspaceController.php`, `routes/web.php`, `routes/api.php`, `tests/Feature/ShipmentRetryTest.php`.

DATABASE CHANGES: None.

ROOT CAUSE: Failed shipment bookings had state records but no explicit, authorized retry action. Booking jobs also did not retry transient ordinary failures.

IMPLEMENTATION: A failed shipment without a provider booking ID can be queued for retry by its tenant through web or API. The booking job now has bounded retries and backoff. `reconciliation_required` remains deliberately non-retryable, preventing an ambiguous provider timeout from creating a duplicate shipment.

TESTS ADDED: Failed shipment retry dispatch; reconciliation-required shipment rejected for automatic retry.

TEST RESULT: Passed as part of the full P0 suite.

BACKWARD COMPATIBILITY: Existing fulfilment endpoint is unchanged. Two additive retry endpoints were added.

REMAINING RISK: Add seller/admin UI visibility and an audit-trail record for retry requests; validate provider production semantics in sandbox before go-live.

### Full P0 Regression Result — Increment 2

Command scope: tenant isolation, inventory reservation, direct and signed payment webhook handling, refund workflow, shipping webhook, external operation recovery, pharmacist compliance, shipment retry, and legacy checkout safety.

Result: **PASS — 40 tests, 118 assertions** on `meyahealth_test` (isolated MySQL test database).

This result increases confidence in the current hardening increment. It does not supersede the remaining audit gates: actual parallel database-connection stock testing, a complete tenant IDOR matrix, platform multi-seller refund item allocation, payment callback state-transition coverage, and production operational readiness.

## Implementation Log — P0 Remediation Increment 3 and Final Verification

### TASK: Complete transactional and authorization regression coverage

STATUS: PASS.

FILES CHANGED: Checkout, payment, inventory, refund, shipment, tenant, pharmacist, seller-product, platform authorization, and readiness components; the corresponding feature and integration test suites.

DATABASE CHANGES: `refund_items` was added for seller-order/item allocation; restrictive one-tenant/one-user indexes were removed while retaining the existing unique `(tenant_id, user_id)` membership constraint and a non-unique user foreign-key index.

ROOT CAUSE: Earlier implementation and test data mixed legacy listing assumptions with the tenant-owned product/variant model. Several safety paths were untested: three-pharmacy checkout, real separate-connection stock contention, webhook replay/out-of-order states, partial item refund allocation, and cross-tenant direct-object access.

IMPLEMENTATION: The marketplace now verifies one `PlatformOrder` and one payment across multiple seller orders, variant-aware stock reservation, duplicate-safe payment/shipment handling, item-level refund allocation, tenant-bound workspace resources, pharmacist/license compliance, and authorized shipping recovery. The seed data now creates a standard active variant and variant-bound inventory for every catalog product.

TESTS ADDED: Multi-pharmacy checkout contract, tenant IDOR matrix, separate-process inventory contention, duplicate/out-of-order payment callbacks, item partial refund, merchant license controls, shipment retry, readiness endpoint, and multi-staff membership regressions.

TEST RESULT: **PASS — 166 tests, 638 assertions** using the isolated MySQL `meyahealth_test` database on 2026-09-21.

BACKWARD COMPATIBILITY: Legacy single-pharmacy checkout and seller-order payment paths remain available. New behavior is additive or rejects unsafe mixed-cart use of the legacy API before any write.

REMAINING RISK: Source-level and local operational readiness are complete. Public-production approval still requires provider sandbox/live callback validation, a supervised queue worker and scheduler, monitoring/on-call ownership, and a documented backup restore drill.

## Final P0 Acceptance

| Requirement | Status |
| --- | --- |
| P0.1 Mixed Cart / One Payment | PASS |
| P0.2 Tenant Isolation | PASS |
| P0.3 Stock Race Condition | PASS |
| P0.4 Payment Idempotency | PASS |
| P0.5 Partial Refund | PASS |
| P0.6 Shipping Failure Recovery | PASS |
| P0.7 Merchant License / Pharmacist State | PASS |

## Local Release Verification

On 2026-09-21, the local Laragon deployment applied the additive migrations, compiled Blade views and Vite assets, cached Laravel metadata, and returned HTTP 200 from `/`, `/up`, and `/health/ready`. The readiness endpoint reported `status: ready` with all configured checks true.
