Skip to content

Post-v1 architecture and maintainability follow-up #24

Description

@Phloraxx

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions