Context
The post-v1 logic/security review fixed immediate correctness defects in PR #23. The items below are architectural debt or product-policy decisions and should not be mixed into that bugfix.
Priority A — before meaningful traffic growth
- Make the single-writer constraint explicit. PocketBase/SQLite and the in-memory checkout rate limiter assume one application replica. Add a startup/deployment invariant or an architecture decision record; do not scale horizontally by increasing replicas.
- Order-bind public payment creation. The standalone checkout accepts any amount, so distributed clients can intentionally consume the 99 paise fingerprints for a popular price. A real commerce integration should create sessions from a signed/order-backed server request rather than an anonymous amount form.
- Revisit NAT-sensitive rate limits. Five creates per IP per five minutes and 180 status reads per IP per minute can reject legitimate users behind campus Wi-Fi or carrier-grade NAT. Replace IP-only identity with an order/session capability before raising limits.
- Minimize outgoing webhook PII. Payment webhooks currently include payer name and UPI ID, and their stored delivery bodies are outside the SMS retention redaction path. Make payer identity opt-in or remove it in a versioned event schema; define delivery-body retention.
Priority B — maintainability
- Unify durable delivery infrastructure. Payment/refund webhooks and operator-alert webhooks separately implement leases, retry backoff, stale recovery, signatures and HTTP delivery. Extract one generic outbox/delivery engine to prevent future wiring and policy drift.
- Split high-complexity files by domain.
internal/api/api.go, internal/gmessages/manager.go, reconciliation/refund services and the operator Operations/Settings pages combine unrelated flows. Split handlers/state-machine responsibilities without changing behavior.
- Stop broad writes from read paths. Payment
Get, Stats and Capacity can expire unrelated records and schedule webhooks. Keep expiry in the cron/targeted command path, or expire only the requested payment.
- Optimize suffix allocation. Allocation may issue up to 99 sequential lookups in a write transaction. Fetch the blocked suffix set once. Preserve the fail-closed 99-slot model.
- Move large reconciliation imports to jobs/chunks. A 10,000-row statement currently uses one SQLite transaction and can block payment writes.
Priority C — known edge cases and tests
- Statement rows containing only a date have unknown intraday time. Do not guess midnight/end-of-day for automated historical matching; model time precision or require operator evidence.
- Add component tests for checkout QR download/waiting/local-expiry flows and operator review/refund/reconciliation modals.
- Increase Google Messages state-machine coverage with a replaceable libgm adapter; current package coverage is much lower than the financial core.
- Add failure-injection tests for backup hooks, startup worker wiring and external alert exhaustion.
- Consider explicit timeouts for scheduled backup verification/restore drills.
Not a blocker
These items do not invalidate the current one-replica, low-volume deployment. They define the boundary beyond which the existing architecture should not be stretched without deliberate changes.
Context
The post-v1 logic/security review fixed immediate correctness defects in PR #23. The items below are architectural debt or product-policy decisions and should not be mixed into that bugfix.
Priority A — before meaningful traffic growth
Priority B — maintainability
internal/api/api.go,internal/gmessages/manager.go, reconciliation/refund services and the operator Operations/Settings pages combine unrelated flows. Split handlers/state-machine responsibilities without changing behavior.Get,StatsandCapacitycan expire unrelated records and schedule webhooks. Keep expiry in the cron/targeted command path, or expire only the requested payment.Priority C — known edge cases and tests
Not a blocker
These items do not invalidate the current one-replica, low-volume deployment. They define the boundary beyond which the existing architecture should not be stretched without deliberate changes.