Skip to content

feat: per-plan cancellation reasons, renewal reminders, lifecycle history, regional tax - #1846

Merged
github-actions[bot] merged 4 commits into
Smartdevs17:mainfrom
OkeyAmy:feat/plan-reasons-reminders-lifecycle-tax
Oct 19, 2026
Merged

github-actions[bot] merged 4 commits into
Smartdevs17:mainfrom
OkeyAmy:feat/plan-reasons-reminders-lifecycle-tax

Conversation

@OkeyAmy

@OkeyAmy OkeyAmy commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements four Stellar Wave features as four self-contained commits:

Issue Commit Scope
#1728 566aac1 Per-plan cancellation reasons + reporting
#1730 22ff7ab Configurable renewal reminder intervals + notification preferences
#1729 9cacf01 Timestamped lifecycle state history timeline + export
#1732 f1f65c9 Per-region tax/VAT applied at invoice time

No dependency, lockfile or build-config changes.


#1728 — Add per-plan cancellation reasons

  • Reasons configurable — CancellationService.configurePlanReasons() registers a per-plan vocabulary (with optional requireReason), exposed as GET/PUT /cancellation/plans/:planId/reasons
  • Aggregated in reports — analytics now carry byPlan and byPlanReason; GET /cancellation/analytics accepts an optional ?planId= filter
  • Optional — unconfigured plans keep the default reason list, and a reason is only enforced when a plan opts in via requireReason

#1730 — Add renewal reminders at T-7 and T-1

  • Intervals configurable — defaults to 30/7/1 days, editable at runtime via GET/PUT /api/v1/calendar/reminders/config (getConfig() / configure() on the scheduler)
  • Respects notification preferences — per-subscription notificationsEnabled plus an injectable isReminderEnabled(userId, eventType) preference hook
  • Tested — new specs cover custom intervals, runtime reconfiguration, disabled event types and the notifications kill switch
  • Also fixed a pre-existing collision where two lead times sharing an event type overwrote each other (the dedup key now includes the lead time), which is what made custom "T-N" intervals actually produce one calendar event each

#1729 — Add lifecycle state history timeline

  • Each transition timestamped — subscriptionStore records created/updated/price_changed/plan_changed/paused/resumed/cancelled events with timestamps and details, persisted alongside subscriptions (with migration/normalisation of stored state)
  • Visible in the UI — "Lifecycle history" timeline card on the subscription detail screen
  • Exportable — CSV export via the share sheet, built by pure helpers in src/utils/lifecycleHistory.ts

#1732 — Add regional tax and VAT calculation

  • Rates configurable per region — TaxService.configureRegionRate() / getRegionRate() / listRegionRates() overrides, resolved ahead of the existing state/city lookup (resolveRegionTaxRate)
  • Applied at invoice time — generateInvoice accepts region, resolves the rate when no explicit taxRate is given, and persists tax_region / tax_type via db/migrations/016_invoice_tax_region.sql (with a -- @down rollback section)
  • Reported separately — tax is shown as its own labelled line (Tax (VAT 19.0% · DE)) on the generated PDF and in the invoice email, keeping it distinct from the subtotal/total

Verification

  • Backend tests — 5 affected suites, 105 tests, all pass: cancellationService, RenewalReminderScheduler, taxService, invoiceGeneration, invoiceController
  • Frontend tests — 2 pure-TS suites, 16 tests, all pass (via the backend jest config workaround, as the RN preset is currently broken per AGENTS.md): lifecycleHistory, subscriptionLifecycleHistory
  • Prettier — clean on all changed files
  • ESLint — no new issues on changed frontend files vs main (the 4 errors / 5 warnings reported there are identical on main)
  • TypeScript — no new errors vs main on both configs: root tsc --noEmit (616 pre-existing) and backend/tsconfig.json (215 pre-existing)
  • Android build / Rust gates — not run locally (the Expo/RN dependency install could not complete in this environment; no smart-contract code touched)

Checklist

  • Lint: ESLint and Prettier checked on changed files
  • Type Check: no new errors introduced
  • Tests: new features have tests, affected suites green
  • Build: not run locally (see above)
  • Rust gates: N/A — no smart-contract changes
  • New code has appropriate TypeScript types
  • No hardcoded secrets or credentials
  • New features have corresponding tests
  • Documentation: not updated (no docs cover these domains yet)

Notes

  • cancellationRouter and invoiceController are still not mounted in createApiServer.ts (pre-existing); the new routes/behaviour follow the existing conventions of those modules.
  • The Add renewal reminders at T-7 and T-1 #1730 config endpoints are mounted at /api/v1/calendar/reminders/config.

Closes #1728
Closes #1730
Closes #1729
Closes #1732

…tdevs17#1728)

Plans can register their own cancellation-reason vocabulary and opt in to
requiring a reason; unconfigured plans keep the default list and stay
optional. Analytics aggregates cancellations by plan and reason and can be
filtered to a single plan via GET /cancellation/analytics?planId=.

Closes Smartdevs17#1728
…es (Smartdevs17#1730)

Reminder lead times (default 30/7/1 days) are now readable and updatable at
runtime through GET/PUT /api/v1/calendar/reminders/config. A per-subscription
notificationsEnabled flag and an isReminderEnabled(userId, eventType) hook let
account-level notification preferences suppress individual reminder types.

Closes Smartdevs17#1730
…s17#1729)

Every subscription state transition (created, updated, price changed, plan
changed, paused, resumed, cancelled) is recorded with a timestamp in the
subscription store and shown as a timeline on the detail screen. The history
is persisted with the store and exportable as CSV from the UI.

Closes Smartdevs17#1729
Region rates are configurable in TaxService (configureRegionRate) with
overrides taking precedence over built-in rates and falling back across
state/city keys. generateInvoice accepts a region, applies the resolved rate
at invoice time, records tax_region/tax_type (migration 016) and labels tax
separately on the PDF and in invoice emails.

Closes Smartdevs17#1732
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@OkeyAmy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@github-actions
github-actions Bot merged commit 990b17f into Smartdevs17:main Oct 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add regional tax and VAT calculation Add renewal reminders at T-7 and T-1 Add lifecycle state history timeline Add per-plan cancellation reasons

1 participant