Commit graph

7 commits

Author SHA1 Message Date
Snider
4e4337e412 feat(commerce): implement RFC.md — billing, subscriptions, Stripe + BTCPay, Commerce Matrix (#845)
Extends prior #860 DunningService with the full RFC.md surface.

Lands across 44 modified/new files:
* Contracts/PaymentGatewayContract.php — implemented by both
  Services/StripeGateway.php and Services/BTCPayGateway.php
* Boot.php — provider bindings + route groups + Commerce Matrix training
  mode middleware
* Services/WebhookService.php — DB::transaction wrapping + ProcessWebhookEvent
  job dispatched ->afterCommit; idempotency via webhook_events unique
  (gateway, event_id) — duplicates rejected silently
* Jobs/ProcessWebhookEvent.php
* DTOs/ — readonly PHP 8.2+ classes per RFC.dto.md
* Services/SubscriptionStateMachine.php — active → suspended (failed
  payment) → cancelled → expired transitions
* Services/ProrationService.php — credit unused old plan time, charge
  new plan remainder, applied via CreditNote + Invoice
* DunningService extended — 1d/3d/7d/14d retry config + cancel
* Migrations — guarded migrations for missing short-name billing tables
  (orders/payments/invoices) + RFC compatibility columns
* routes/api.php — /v1/* endpoints
* Checkout success/cancel routes
* Commerce Matrix training-mode endpoint + record-permissions logic
* Console/Commands — RFC.commands.md signatures
* Events per RFC.events.md
* Models extended

php -l clean. composer validate passes. pest unrunnable in sandbox.

Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=845
2026-04-25 22:55:51 +01:00
Snider
6d83c32114 fix(referral): drop FKs to nonexistent 'orders' + 'invoices' tables
The referral_commissions migration FK-referenced 'orders' and 'invoices'
tables, but neither is ever created by any migration in the codebase.
MariaDB silently accepted the FKs (checks disabled during migration),
Postgres rejects strictly.

Changed both columns to plain nullable unsignedBigInteger — same column
shape, no FK constraint. Data still references orders/invoices by id
via application logic. Proper FKs can be added in a follow-up migration
once orders/invoices migrations land.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-22 22:06:44 +01:00
Snider
301fdb152a fix(migration): remove FK constraints on non-existent orders/subscriptions tables
Some checks failed
CI / PHP 8.2 (push) Has been cancelled
CI / PHP 8.3 (push) Has been cancelled
CI / PHP 8.4 (push) Has been cancelled
CI / Assets (push) Has been cancelled
webhook_events referenced orders and subscriptions tables that don't
exist yet (billing module). Switched to plain unsignedBigInteger columns
with indexes — FKs can be added when the billing tables are created.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-08 18:08:20 +00:00
Snider
c19e467735 security: add webhook idempotency and payment amount verification
Idempotency (replay attack protection):
- Add WebhookEvent model for tracking processed events
- Add webhook_events migration with unique constraint
- Add isAlreadyProcessed() to BTCPay and Stripe controllers
- Reject duplicate events with 200 response

Payment amount verification (BTCPay):
- Add verifyPaymentAmount() method
- Reject underpayments (mark order failed, create audit record)
- Reject currency mismatches
- Log overpayments for manual review
- Add 0.01 tolerance for floating point precision

Add comprehensive tests for both features.
Update TODO.md to mark P1 issues as fixed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 12:32:25 +00:00
Snider
9113cede8a fix: remove FK to non-existent invoice_items, shorten index names
- Remove FK constraint to invoice_items table (not yet created)
- Shorten index names to avoid MariaDB 64-char limit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:46:15 +00:00
Snider
eca97466b8 fix: remove FK constraints to non-existent orders/refunds tables
Credit notes can exist independently of orders. Foreign keys will be
added when orders and refunds modules are implemented.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 17:23:48 +00:00
Snider
a74a02f406 monorepo sepration 2026-01-27 00:24:22 +00:00