# Phase 14 — Withdrawal System Report

## Outcome

Phase 14 is complete. The web runtime now supports dynamic manual withdrawal methods and destination fields, server-owned quotes and eligibility checks, atomic balance holds, encrypted destination evidence, idempotent requests, permission-separated Admin review, optional dual approval, full rejection refunds, and manual payout settlement through the immutable ledger.

No live provider integration is enabled. The manual provider records evidence for an externally verified transfer; it does not send funds. Withdrawals remain disabled by default behind both a feature flag and a versioned setting.

## Delivered components

- Migration `019_harden_withdrawal_workflow.sql` adds method/field optimistic versions, immutable quote/request snapshots, fingerprints, encrypted-detail integrity hashes, approval/time constraints, one-payout-per-request uniqueness, queue/user indexes, a withdrawal-fee system account, sensitive permissions, and protection triggers.
- The public service exposes active methods, five-minute quotes, atomic request creation, idempotent replay, user-owned list/detail, and masked destination output.
- Eligibility uses authoritative task/referral/account/ban/ledger/daily/cooldown state and is rechecked under row locks before the hold posts.
- Request creation commits the available debit, held credit, encrypted evidence, quote consumption, request, and initial history together.
- Admin review enforces exact approve/reject/hold permissions and optimistic request versions. Rejection returns the entire gross hold in the same transaction.
- High-value configuration can require two distinct approvals; no ledger movement occurs while the first approval leaves a request under review.
- Manual paid confirmation stores a unique provider reference fingerprint and settles held gross into payout-clearing net plus withdrawal-fee credit.
- Method activation verifies settlement currency, field schema, global processing mode, provider support, and a valid minimum quote. Only the manual provider is registered.
- Global withdrawal settings retain previous values in `setting_versions` and use per-setting optimistic versions.

## Security invariants

- All money is `BIGINT` minor units and JSON string output; floating-point arithmetic is absent.
- The client can submit only quote amount/method and request quote/destination details. It cannot choose fee, net, status, approvals, ledger references, or payout evidence.
- Raw idempotency keys are HMAC-digested, and request fingerprints bind replays to the original canonical input.
- AES-256-GCM associated data binds destination ciphertext to the exact user/request pair; a canonical SHA-256 hash is verified before privileged disclosure.
- Request/quote/method/user/rule state is locked and revalidated before money moves.
- Unique database constraints, append-only ledger entries, protected workflow evidence, immutable approval/history rows, and optimistic versions provide independent concurrency defenses.
- Admin list/search queries remain parameterized, sensitive reads have a separate permission, and state-changing routes retain CSRF, Admin IP, rate-limit, and audit controls.

## Verification

Phase 14 adds 30 focused unit, integration, and security tests. They cover fee rounding, rule composition, account/task/referral/balance/daily/cooldown eligibility, dynamic field validation, destination masking and integrity, request idempotency, quote conflicts, transaction rollback, gross refunds, dual approval, exact payout splitting, public authentication, CSRF, strict payloads, distinct Admin permissions, SQL parameterization, migration protections, and the manual-only provider boundary.

The full suite contains **262 tests** after the Phase 14 additions. The database verifier confirms **19 migrations, 6 seeds, 72 domain tables, 188 named foreign/check constraints, 131 up statements, 124 down statements, and 19 seed statements**.

## Operational boundary

Migration and runtime checks were executed only offline or against test doubles. No deployment `.env`, live MySQL instance, Telegram environment, external payout account, or real balance was accessed. Operators must follow `docs/WITHDRAWAL-SYSTEM.md` and `docs/DATABASE-OPERATIONS.md`, validate staging reconciliation, and explicitly enable the feature after deployment.

## Next phase

Phase 15 will implement content and global settings management: themes, currencies, banners, announcements, tutorials, managed public URLs, feature controls, and maintenance-facing configuration.

**Phase 14 status: COMPLETE — focused tests 30/30; full quality gate passed 262/262.**
