Quickstart: Validating the Payment Failure Grace Period Feature

This is a validation/run guide, not implementation code. It assumes the feature has been
implemented per data-model.md and contracts/. Full source can be diffed against the existing
reference implementation on origin/feat/1023-grace-cron-userpayment
(worktree: /private/tmp/kilo/wt-grace-pr) for a working baseline.

Prerequisites

  • Local yoyacoo_be environment running (admin app), .env with a valid Stripe test-mode
    secret key and STRIPE_WEBHOOK_SECRET set.
  • MAIL_MAILER=log (or Mailtrap) so sent emails can be inspected without real delivery.
  • Test database migrated (make t-migrate) including the new grace-tracking migration(s).
  • Stripe CLI installed and logged in, for forwarding webhooks
    and triggering test events locally: stripe listen --forward-to localhost/webhook.

One-time Stripe Dashboard configuration (test mode)

Per spec.md Assumptions, this is manual operational setup, not app code:

  1. Stripe Dashboard → Settings → Billing → Subscriptions and emails.
  2. Manage failed payments → retry schedule = “Do not retry”.
  3. Subscription cancellation → enable, set to cancel 7 days after the invoice first became
    past due.

Scenario 1 — Payment fails → grace period + immediate email

  1. Create a test subscriber with an active paid subscription (existing subscribe flow, or a Stripe
    test-mode subscription attached to a seeded User).
  2. Force the next renewal invoice to fail: use a Stripe test card that always fails
    (4000000000000341) as the default payment method, or use stripe trigger invoice.payment_failed against the test subscription.
  3. Expected:
    • UserPayment.status becomes PAST_DUE (3).
    • hosted_invoice_url and grace_period_started_at are populated.
    • The subscriber immediately receives the 1st email (check the log mail driver output or
      Mailtrap inbox) with subject 【ヨヤクー】お支払い方法のご確認をお願いいたします and a working
      payment link.
    • The subscriber can still use every previously-available paid feature (spot-check one paid-only
      screen/endpoint).

Scenario 2 — Day-3 / Day-6 reminders

  1. From Scenario 1’s state, manually backdate grace_period_started_at on the test row (e.g., 3
    days in the past) or wait/advance the system clock in a test/staging environment.
  2. Run php artisan grace:send-mail.
  3. Expected: the 2nd email (【ヨヤクー】お支払い方法の更新をお願いいたします) is sent, and
    grace_mail_2_sent_at is set. Running the command again immediately does not resend it.
  4. Repeat with the anchor backdated 6 days for the 3rd email
    (【重要|ヨヤクー】有料プランのキャンセル前の最終確認です).

Scenario 3 — Manual payment recovery

  1. From a PAST_DUE state, complete payment via the hosted_invoice_url from one of the emails
    (or stripe trigger invoice.payment_succeeded / invoice.paid against the test subscription).
  2. Expected:
    • UserPayment.status returns to SETTLED.
    • grace_success_mail_sent_at is set exactly once even if both invoice.payment_succeeded and
      invoice.paid are received for the same payment.
    • The subscriber receives the payment-completed email
      (【ヨヤクー】お支払いが完了しました) with the amount paid and payment date.
    • Running grace:send-mail afterward sends no further dunning mail for this cycle.

Scenario 4 — Day-7 automatic cancellation

  1. From a PAST_DUE state with no payment, either let the Stripe test-mode subscription actually
    reach its configured 7-day cancellation, or simulate it directly:
    stripe trigger customer.subscription.deleted against the test subscription.
  2. Expected:
    • UserPayment.status becomes DELETED.
    • The existing free-plan downgrade cleanup runs (spot-check a plan-limited resource is now
      restricted per free-plan limits).
    • No further dunning mail is sent for this (now-closed) grace cycle.

Automated test suite

Run the feature’s automated tests (mirrors the reference branch’s admin/tests/Feature/Grace/*
suite):

make t-migrate
php artisan test --filter=Grace
composer phpstan

All of the above must pass with zero failures before considering the feature done, per the
project’s Test & Quality Gates (constitution principle III).