# Ghaza Operations Guide

## Health and integrity

- `/up`: process liveness only.
- `/ready`: DB/cache/storage readiness.
- `php artisan ops:health --strict-background`: scheduler, fast/heavy worker, failed-job and infrastructure operator check.
- `php artisan ops:verify-integrity`: read-only ledger/data invariant verification. It never repairs financial data automatically.

Use `X-Request-Id` and `X-Ghaza-Release` for incident correlation.

## Financial Approval

Sensitive operations are represented by an `ApprovalRequest` resolved from configurable amount/center rules. A rule contains ordered required roles. Approval authority is then checked separately using `ApprovalLimit` records scoped by user or role, optional center and operation type.

Operational rules:

- request creator cannot approve the request;
- one user cannot approve multiple steps of the same request;
- an approver must have the decision permission, required role, center access and sufficient authority limit;
- decisions are immutable;
- only a fully approved request may execute the protected operation;
- failed execution remains auditable and can be retried by an authorized operator without creating a second approval decision chain.

Default seeded thresholds are policy defaults, not hard-coded business law; administrators with the dedicated management permissions can configure them.

## Cashier operations

Flow:

1. Open a cashier session for one user and center with opening cash.
2. Register cash wallet top-ups through that open session.
3. Use approval-backed cash adjustments rather than direct balance edits.
4. Close the session with physically counted cash.
5. `difference = counted_cash - expected_cash`.
6. Differences whose absolute value exceeds `GHAZA_CASHIER_REVIEW_THRESHOLD` enter `needs_review`; the cashier cannot self-approve the review.
7. Approved differences create an accounting adjustment and immutable cashier transaction before final close.

A financial day cannot be closed while a cashier session for that center/day remains open or needs review.

## Financial day close

A center/day close snapshots reservation, wallet, cash, PSP payment/settlement, subsidy, refund, revenue and clearing figures. After close, the shared Accounting Service rejects any new posting whose `posted_at` belongs to that center/date.

Before closing a day:

```bash
php artisan ops:health --strict-background
php artisan ops:verify-integrity
```

Resolve cashier reviews and material reconciliation failures first. Never “fix” a close by editing ledger rows in SQL.

## Financial period lock

Period Lock can be global or center-specific and has an inclusive start/end date. Active overlapping locks in the same scope are rejected by the lock workflow. New accounting postings inside the lock are rejected unless the actor has the exceptional `accounting.period-override` permission; every override is written to Audit Log.

Unlock is a controlled, audited operation. Use it only for an explicit accounting reason and re-run integrity checks afterward.

## Wallet and accounting invariants

- Wallet belongs directly to `User`; Student/Employee remain profiles.
- Wallet transaction rows are immutable; corrections use reversal.
- Financial transactions are double-entry and immutable.
- `SUM(debit) = SUM(credit)` for each financial transaction.
- Approval does not create a second ledger. Protected operations ultimately call the existing Wallet/Payment/Accounting actions.

## Queue and scheduler

Fast queue handles latency-sensitive work; heavy queues handle reports/imports/reconciliation. Keep `retry_after > timeout`, supervise workers with `max-time` and `max-jobs`, and monitor independent fast/heavy heartbeats.

For a queue incident, inspect `queue:failed`, logs and request IDs; fix the cause before retrying. Do not use `queue:flush` as a shortcut.

## Payment and settlement incidents

A browser callback is never sufficient proof of payment. Verification is server-to-server and validates amount/currency. Unknown refund state stays in review; do not automatically re-credit the wallet when the PSP outcome is unknown.

Payment success and bank settlement remain distinct. Monitor PSP Clearing reconciliation with `ops:verify-integrity`.

## Backup and restore

Use the coordinated full-backup scripts under `deploy/scripts/`. A valid recovery set contains database and storage artifacts plus a manifest and SHA-256 digests. Verify checksums before restore and perform scheduled restore drills.

## Incident rule

Security, data integrity, financial integrity and auditability take precedence over convenience. If an integrity check fails, stop the affected financial/operational workflow, preserve evidence, determine the ledger-safe correction, and apply a reversal/adjustment rather than destructive edits.

## POS / PWA / offline operations

- POS is operationally separate from reservations, but shares meal-day capacity, accounting, cashier and inventory invariants.
- POS full void creates reversing accounting/wallet/cash/inventory entries; original financial records remain immutable.
- Offline operation mode is intended only for real network loss. Delivery/cashier outboxes must be synchronized and finalized before financial day close.
- PWA private operational caches must not be used as a general cache for authenticated financial pages.
- Before closing a cashier/day, confirm POS holds, offline outbox, POS voids and expected cash are reconciled.

## Hardened Redis topology

The production example isolates Redis usage by logical database: cache, fast queue, long queue and session are separate. This avoids accidental queue/session loss when a cache database is flushed. Do not run broad `FLUSHALL`/`FLUSHDB` operations without confirming the exact connection/database.

Database-backed system settings are refreshed periodically in long-lived workers (`GHAZA_SETTINGS_CACHE_TTL_SECONDS`, default 60s), so policy changes do not remain stale indefinitely. Restart workers immediately after security-critical configuration changes if you require instant propagation.

## Production smoke and certification

After each deployment run:

```bash
php artisan ops:health --strict-background
php artisan ops:verify-integrity
BASE_URL=https://your-domain.example deploy/scripts/smoke-production.sh
```

Use `scripts/production-certify.sh` only on a disposable certification database; it is intentionally destructive. Full requirements are in `docs/PRODUCTION_CERTIFICATION.md`.
