ENGINEERING

Pickly Platform Architecture

A pickup-first commerce platform engineered around a shadow inventory ledger, idempotent payments, and POS-resilient order injection.

System overview

┌─────────────┐   ┌─────────────┐   ┌─────────────┐
│ Customer    │   │ Merchant    │   │ Admin       │
│ Mobile App  │   │ Dashboard   │   │ Console     │
└──────┬──────┘   └──────┬──────┘   └──────┬──────┘
       │                 │                 │
       └────────┬────────┴─────────┬───────┘
                ▼                  ▼
        ┌───────────────┐   ┌─────────────┐
        │ API Gateway   │◄──┤ Auth + RBAC │
        └───────┬───────┘   └─────────────┘
                │
   ┌────────────┼──────────────┬─────────────┐
   ▼            ▼              ▼             ▼
┌──────┐  ┌──────────┐  ┌────────────┐ ┌──────────┐
│Orders│  │ Inventory│  │ Payments   │ │ POS Sync │
│ Svc  │  │  Ledger  │  │ (Stripe)   │ │  Worker  │
└──┬───┘  └────┬─────┘  └─────┬──────┘ └────┬─────┘
   │           │              │             │
   └──────┬────┴──────────────┴─────────────┘
          ▼
   ┌────────────┐
   │ PostgreSQL │  + Event Bus (webhooks, retries)
   └────────────┘

Core domains

  • IdentityCustomer / Merchant / Admin RBAC
  • CatalogStores, menus, modifiers, availability
  • Cart & OrdersPickup ASAP, later, reservations
  • InventoryShadow ledger w/ event sourcing
  • PaymentsAuth → capture → refund, idempotent
  • POS SyncBi-directional w/ fallback workflow

Order lifecycle

PLACED ──▶ AUTHORIZED ──▶ ACCEPTED
   │            │              │
   │            ▼              ▼
   │       PAY_FAILED      PREPARING
   │            │              │
   ▼            ▼              ▼
CANCELLED   REFUNDED         READY
                               │
                               ▼
                           COMPLETED

Shadow inventory ledger

Every stock movement is an append-only event. Available = base − reserved − committed + restored.

AVAILABLE
RESERVED
COMMITTED
CANCELLED
REFUNDED
ADJUSTED
checkout()  →  RESERVE(qty, ttl=15min)
accept()    →  COMMIT(qty)             # decrements available
cancel()    →  CANCEL(qty)             # restores
refund()    →  REFUND(qty)             # restores
ttl_expire  →  CANCEL(qty)             # auto-restore
manual      →  ADJUST(+/-qty, reason)

Payment state machine

CREATED ─▶ AUTHORIZED ─▶ CAPTURED ─▶ SETTLED
              │              │
              ▼              ▼
          VOIDED          REFUNDED ─▶ PARTIAL_REFUND
              │              │
              ▼              ▼
           FAILED          DISPUTED
  • • Idempotency keys per checkout attempt to prevent duplicate captures.
  • • Webhook signatures verified via Stripe-Signature HMAC.
  • • No raw PAN/CVV ever touches our servers — tokenized via Stripe Elements.
  • • Refunds restore inventory atomically through the ledger.

POS integration

ORDER ─▶ POS_INJECT (attempt 1)
           │
           ├─▶ 2xx → MARK_INJECTED
           │
           └─▶ fail → retry w/ jitter (3x)
                       │
                       └─▶ FALLBACK: route to merchant tablet
                                        + alert ops + audit

User journeys

Customer
Browse → Add → Pickup → Notify → Receipt
Merchant
Accept → Prep → Ready → Complete · Stock adjust
Admin
Approve · Investigate · Refund · Audit

Entity relationships

User ──┬──< Order >── Store ──< Product >── Modifier
       │                            │
       └──< Notification             └──< StockEvent
Order ──< Payment ──< Refund
Order ──< AuditLog