Commit Graph

12 Commits

Author SHA1 Message Date
3420c8dce0 feat(sca): add retry-auth endpoint for failed 3ds challenges (#31)
* feat(sca): add retry-auth endpoint for failed 3ds challenges

* fix(sca): retry-auth unexpected-state branch out of card-decline

just fixes up in some of the things the review of the last commit
noticed
2026-06-03 23:42:27 +02:00
67e19eca98 feat(sca): expire inactive saved cards (#29)
* feat(sca): expire inactive saved cards

* fix(sca): address card ttl review feedback

- Correct sql typos breaking GET /cards and /view/init (used_id, id_default)
- Stop swallowing backfillCardStorageExpiration error in Migrate
- Wrap expireStoredCard local writes in a transaction and run stripe
  detach + audit only after commit, preventing double-fire on retry
- Drop redundant ttl refresh in ConvertCart; webhook is authoritative
- Rename validation_expired_at metric label to validation_card_expired
- Fix CardStorageExpiresAt doc comment and test failure message typos
- Add handler-level tests for expireStoredCards (user scoping + cart deref)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(sca): move card expiration to periodic reconciler

Read paths (GetCards, GetViewInit) now filter expired cards from
query results instead of detaching them inline, so request handlers
no longer block on Stripe API calls. Physical deletion runs in a
new ReconcileExpiredCards goroutine on an hourly ticker, mirroring
the existing ReconcileOrders / ReconcileUnshipped jobs. Per-card
action sites (SetCard, SetDefaultCard, ConvertCart) still expire
synchronously since they operate on one row the user is acting on.

ViewHandler's stripeKey dependency is dropped now that GetViewInit
no longer touches Stripe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sca): address card ttl review feedback

- guard zero order.CardID before refreshing card storage ttl in
  payment_intent.succeeded webhook to avoid noisy warn logs on payment
  paths that did not use a saved card
- delete unused Card.RefreshStorageTTL model method; the SQL-only
  refreshCardStorageTTL helper is the single canonical path
- clarify duplicate-card webhook path: storage_expires_at reset is a
  card-add refresh, not a payment-success refresh, so last_used_at
  intentionally stays untouched

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(sca): cover card ttl read paths and expired-card sync sites

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:49:48 +02:00
95b9fa91b1 feat(sca): add order status endpoint adn SCA error code mapping (#14)
* feat(sca): add order status endpoint adn SCA error code mapping

adds server-side infra for the upcoming SCA / 3DS challenge flow im
working on. No behavior change to existing checkout paths.

* fix(sca): suppress unused lint on SCA scaffolding helpers
2026-05-27 19:23:29 +02:00
2e6dda190f feat(audit): persist every order-scoped audit.X(...) call to a new order_events table alongside the existing slog line, builds the foundation for an admin order timeline view without changing the slog primary path 2026-05-22 20:01:29 +02:00
96e76f7e5b feat(slack): add slack mark status buttons for bring orders, post-label thread now block kit, synthesize shippo webhook over loopback to reuse state-date guard and delivered transition 2026-05-20 18:09:34 +02:00
2966474ff5 feat(notify): render slack order notification as block kit receipt with line items 2026-05-15 12:11:16 +02:00
f6eed76456 feat(notify): post Slack message when an order is paid 2026-05-15 08:54:23 +02:00
ee6e14a424 feat(shipping): shippo webhook fro tracking status updates 2026-05-14 13:30:37 +02:00
c22b64d6fa feat(shipping): shippo label purchase endpoint
Adds POST /api/v1/orders/{id}/label (admin-only) that buys a shipping
  label through Shippo and writes carrier + tracking + label fields back
  onto the order, transitioning paid -> shipped.
2026-05-12 20:57:11 +02:00
1849e324fc feat: add admin tracking updates 2026-05-08 10:47:57 +02:00
ae7eaa8e97 feat: route audit + recovery through slog levels
Audit events now emit at Info/Warn/Error so the log-level counter has variety
instead of being pinned to info. Panic recovery uses structured slog.Error
with method/path/stack attrs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 13:55:54 +02:00
062242e346 feat: add browser-based card collection via Stripe Checkout Session
adds a /pay/{token} redirect endpoint that generates a short URL
pointing to a stripe checkout sessions in setup mode. The TUI shows a QR
code and URL on the payment page so users can add a card via the browser
instead of entering raw card data over SSH.

the checkout.session.completed webhook saves the card to the database.
the TUI polls GET /api/v1/cards every second and auto-proceeds to
confirmation once the new card is detected.

also adds a dev.sh startup script that runs all four required processes.
(SSH server, API server, Stripe CLI listener, ngrok) in a single
terminal
2026-04-08 01:03:43 +02:00