In-Progress / Pending Work
An inventory of areas that are not yet production-ready. Use this as the "what's still open" list for the meeting.
Stripe payments
- Status: Scaffolded, not wired into checkout. No code path actually charges a card today.
- What exists:
- Package installed:
stripe/stripe-php: ^18.0incomposer.json(Laravel Cashier is NOT installed). - Service bindings:
StripeClientsingleton registered inapp/Providers/AppServiceProvider.php(registerStripeClient()), pulling fromconfig('services.stripe.secret'). - Config keys:
STRIPE_KEY/STRIPE_SECRETdeclared inconfig/services.php(lines 39-42). Note: these env vars are NOT in.env.example— they need to be added. - Service layer:
app/Services/PaymentService.php(~300 lines) implementsprocessStripePayment(),createPaymentIntent(),confirmPaymentIntent(),refundPayment(),getPaymentIntent(). - Data model:
app/Models/PaymentIntent.php+database/migrations/2025_07_28_123621_create_payment_intents_table.phpwithstripe_payment_intent_id,client_secret, status enum, etc. - Transaction model:
app/Models/Transaction.phphaspayment_provider,external_transaction_id,gateway_responsefields (provider-agnostic). - Payment method enum:
app/Enums/PaymentMethodEnum.phpincludesCREDIT_CARD,DEBIT_CARD,HSA_CARD,FSA_CARD,HRA_CARD,PURSE_ONLY, etc.
- Package installed:
- What's missing:
- No call site invokes
PaymentServiceanywhere — verified via grep acrossapp/androutes/. The only file referencing the class is the service itself. StoreOrderAction(app/Http/Actions/Member/Order/StoreOrderAction.php) creates an order from cart but never calls a payment step.OrderService::createOrderFromCart()defaultspayment_method = CREDIT_CARD/payment_status = PENDINGwhen total > 0, but nothing collects a card or confirms the intent.- No checkout HTTP action / route — search for "checkout" turned up nothing in
app/Http/orroutes/. - No Stripe webhook controller (
app/Http/Controllers/Webhooks/only containsShipHeroWebhookController.php). Inboundpayment_intent.succeeded/charge.refundedevents are not handled. - No
STRIPE_KEY/STRIPE_SECRET/STRIPE_WEBHOOK_SECRETentries in.env.example. - Frontend (Stripe Elements / payment-method-id collection) is not wired to a backend endpoint.
- Saved payment methods / Stripe Customer creation is not implemented (no
stripe_customer_idonUserorMember).
- No call site invokes
- Risk / blocker: The full service layer was built ahead of integration — easy to look "done" in code review but a live checkout still has to be assembled and tested end-to-end. Refund flow has the same gap (
refundPayment()exists but no admin/UI hook calls it).
WEX integration
- Status: Pending — no code yet. Blocked on partnership agreement.
- What exists:
- Enum placeholders only:
PaymentMethodEnum::HSA_CARD,FSA_CARD,HRA_CARD,PURSE_ONLYinapp/Enums/PaymentMethodEnum.php. None of these enum values are referenced by any business logic — grep forHSA_CARD/FSA_CARD/HRA_CARDreturns zero hits outside the enum file itself. - Internal "purse" system (
app/Services/PurseService.php,app/Services/PursePurchaseService.php,Pursemodel) exists and works against locally-seeded balances — this is the stand-in for what WEX will eventually back. - Business decision logged in
business-decisions.md(lines 65-71): "WEX is NOT a payment gateway like Stripe or PayPal. WEX is the entire benefits backbone… Pending: WEX partnership agreement is still being finalized."
- Enum placeholders only:
- What's missing:
- No
WexService,WexClient, noconfig/services.phpentry, no env vars, no HTTP client, no API contract. - No member lookup, balance check, eligibility check, or purse-deduction API calls.
- No settlement / reconciliation jobs.
- Purse data is currently seeded locally — there is no sync from WEX.
- No
- Risk / blocker: Per
business-decisions.md, the team does not yet know:- Which WEX APIs will be available (member lookup, balance checks, purse deductions).
- Where purse data will come from once WEX is live (today: seeded in our DB).
- Settlement terms (how/when Easy OTC gets paid). This work is fully gated on the WEX partnership being finalized — no useful code can be written until the API contract is known.
Email notifications
- Status: Partially wired. Transactional flows fire, but
MAIL_MAILER=login.env.examplemeans nothing actually leaves the box in the default config; no welcome email exists. - What exists (Mailables in
app/Mail/, all implementShouldQueue, all have matching Blade templates inresources/views/emails/):OrderConfirmationMail— dispatched byOrderPlacedListener(queued listener onOrderPlacedEvent). Event is fired fromOrderService::createOrderFromCart()andSubscriptionOrderServicewhen a subscription auto-order is generated.OrderAgentNotificationMail— dispatched byOrderPlacedAgentNotificationListeneron the sameOrderPlacedEvent(notifies assigned agent(s)).SubscriptionConfirmationMail— fired bySubscriptionCreatedListeneronSubscriptionCreatedEvent(dispatched fromSubscriptionService::create).SubscriptionPausedMail/SubscriptionResumedMail/SubscriptionCancelledMail/SubscriptionCadenceChangedMail— all wired via matching listeners on their respective subscription events fired fromSubscriptionService.SubscriptionUpcomingDeliveryMail— sent bySendUpcomingDeliveryRemindersCommand(subscriptions:send-reminders), scheduled inroutes/console.phpto rundailyAt('09:00').ContactInquiryMail— fired inline byStoreContactInquiryAction(sent toconfig('mail.to.address')).MailingListSubscriptionConfirmation— fired inline byStoreMailingListActionandMailingListController(duplicate path — see "Risk" below).- Password reset:
App\Notifications\ResetPasswordNotification(inapp/Notifications/) is wired viaUser::sendPasswordResetNotification()and triggered bySendResetLinkAction(POST /forgot-password) andapp/Filament/Actions/SendPasswordResetAction.php.
- What's missing:
- No welcome email. No
WelcomeMail, noWelcome*Mailable, no Notification fires on member/user registration.StoreMemberActionand the auth login actions do not dispatch any greeting. (Aresources/views/welcome.blade.phpexists but it's the default Laravel landing page, not an email.) - No mail driver configured for production.
.env.examplesetsMAIL_MAILER=log,MAIL_HOST=127.0.0.1,MAIL_PORT=2525— nothing points at Postmark / Resend / SES even thoughconfig/services.phphas slots forpostmark,resend, andses. Until a real driver + credentials are set in the production.env, all "wired" emails just append to the log file. - No payment-receipt / refund-confirmation / shipping-confirmation emails. (Shipping events come from ShipHero webhooks but no email Mailable is hooked to them.)
- No order-cancelled / payment-failed customer email.
- No admin "low inventory" or "new contact inquiry summary" digest.
- No email verification flow (
Usermodel has the standard fields but noMustVerifyEmailcontract / verification email is sent).
- No welcome email. No
- Risk / blocker:
- Duplicate mailing-list send path: both
app/Http/Actions/MailingList/StoreMailingListAction.phpandapp/Http/Controllers/MailingListController.phpsendMailingListSubscriptionConfirmation. Whichever route is registered will fire — risk of double-send if both are wired up. - Because everything is queued (
ShouldQueue+QUEUE_CONNECTION=redis), emails will silently sit in the queue if the worker isn't running. Worth confirming the worker / Horizon is part of the deploy. - Default
MAIL_FROM_ADDRESS="easyotc@example.com"in.env.examplewill need to be replaced before any of this hits real inboxes.
- Duplicate mailing-list send path: both