Problem/Motivation
Subscription Manager is at 1.0.0-beta2 with a queue of known work spanning Drupal 12 compatibility, an access-control bug, multi-connector support, and pre-stable hardening. This meta orders that work into a dependency-aware sequence so contributors know what to pick up next and what blocks what. Everything listed below should land (or be explicitly deferred with a comment here) before tagging 1.0.0.
Proposed resolution
Resolve in this order. Within a phase, issues are independent and can proceed in parallel; phases are ordered by dependency.
Phase 1: Foundation. Land first because nearly every later patch touches the same files, and because subsequent work deserves trustworthy role handling and a testable admin UI.
- #3603421: Automated Drupal 12 compatibility fixes for subscription_manager 1.0.x-dev Drupal 12 compatibility (hook class conversion plus manual fixes). First because the OOP hook conversion rewrites the
.modulefile; landing it before everything else avoids rebasing every subsequent patch across the conversion. The|| ^12constraint flip waits for 12.0.0-beta1 testing (week of 14 September 2026) and may land separately. - #3616929: Role revocation depends on a live plan lookup, so users can keep paid roles after expiry or cancellation Role-revocation snapshots (critical). The one access-control bug; everything that follows assumes role handling can be trusted.
- #3616930: Entity annotations and route providers reference four permissions that are never defined, locking admin UI to user 1 Undefined permission strings. Small and independent; unblocks non-uid-1 admin testing of all later work.
- #3616932: Subscribe routes fatal on fresh installs: default_connector is absent from config/install and passed unguarded to createInstance() Fresh-install default_connector guard. Small; removes a fatal that bites every clean test environment.
Create a release node for the beta3 release. (This was accidentally forgotten, and needed additional maintainer permisssions.)Cut a beta 4 tag.Create a release node for the beta4 release. (It was only tagged due to lack of maintainer permissions)
.
Phase 2: Multi-connector correctness. The structural work that makes multiple simultaneous connectors safe.
- #3616880: Move _subscription_manager_sync_remote_subscriptions() into SubscriptionManagerService and convert the cron queue drain to a QueueWorker plugin Move the sync helper into SubscriptionManagerService and convert the cron drain to a QueueWorker. Lands before the sync rewrite so that fix has an injectable, testable home (also resolves the queue's poison-item stall noted in its comments).
- #3616778: Define and enforce single-active-subscription semantics (loadLocalSubscription() returns an arbitrary first match) Single-active-subscription semantics. The Option A/B decision gates #3616770: Self-healing remote subscription sync only queries the default connector's short-circuit and shapes #3616769: Add a connector chooser to the subscribe flow when multiple connectors provide plans's switch flow, so decide early even if enforcement lands with this issue.
- #3616770: Self-healing remote subscription sync only queries the default connector Multi-connector self-healing sync (implemented in the refactored service method).
- #3616776: SubscriptionEntity::getPlan() ignores connector_plugin_id, allowing cross-connector plan_id collisions getPlan() connector-aware lookup.
- #3616773: shouldRedirectCurrentUserOnLogin() only consults the default connector Login-redirect polling across connectors.
Cut abeta5tag.Create a release node for the beta5 release. (It was only tagged due to lack of maintainer permissions.)
Phase 3: Features.
- #3618739: Add a charge-based connector mode with a local billing cycle engine
- #3616769: Add a connector chooser to the subscribe flow when multiple connectors provide plans Subscribe-flow connector chooser. Depends on Phase 2 for safe coexistence; composes with #3616932: Subscribe routes fatal on fresh installs: default_connector is absent from config/install and passed unguarded to createInstance()'s single-connector auto-default.
- #3615735: Add a rating step for usage-based charges, delivered per connector scheduling mode Usage-based (metered) billing support. Interface addition; sequenced here so connector implementations (including #3616779: GoCardless connector module (bank debit: Bacs, SEPA, ACH, PAD)) target a settled connector interface.
- #3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core
- #3621282: Show subscribers their invoice history in the membership portal
Cut abeta6tag.Create a release node for the beta6 release. (It was only tagged due to lack of maintainer permissions.)
Phase 4: Pre-tag hardening and cleanup. Ordered last but required before 1.0.0; several change the public surface and are cheapest to change pre-stable.
- #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications
- #3619074: Succeeded charge records are terminal, so payer-initiated reversals (SEPA refunds, Bacs indemnity claims, chargebacks) have nowhere to land: Sequenced directly after the dunning framework because it consumes both the charge records from #3618739: Add a charge-based connector mode with a local billing cycle engine and the state machine from #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications.
- #3616931: /subscription-manager/api/my-subscription returns full entity arrays including raw remote data, and responds 202 to GET Curate the my-subscription API response (response-shape change: must precede stable).
- #3616933: Harden post-purchase auto-login tokens: single-use and a shorter default TTL Single-use, shorter-TTL post-purchase tokens (coordinate connector follow-ups).
- #3616934: Deleting a user deletes local subscription entities but never cancels the remote contract, so billing continues Remote cancellation on user deletion.
- #3616936: SubscribeMenuLink declares the user.roles cache context but varies per user, leaking Join/Upgrade labels across users SubscribeMenuLink cache context and label translatability.
- #3616937: Cleanup omnibus: dead config keys, missing token dependency, per-role user saves, page_attachments overhead, drush alias, field length, translatability, misc Cleanup omnibus (dead config keys, drush alias, field length, translatability, misc).
- #3627571: Build the membership portal page on capability interfaces, replacing the unused inline-actions API
- #3621280: Add update-path test coverage from a pre-roadmap database fixture
- Add full documentation for the module (e.g. for users, admins, connector maintainers, etc.) to the (now empty)
README.md. - Cut a
beta7tag. - Create a release node for the beta7 release.
- File a catch-up issue in each connector module's queue — Stripe Subscription, Recharge Subscription, the Chargebee Subscription and Shopify Subscription sandboxes — so each is updated against 1.0.0-beta7 before 1.0.0 is tagged. Generate the shared issue text at this point, from the final beta7 change-record list and the connector interfaces as tagged: it should enumerate every Phase 1–4 change a connector may need to adapt to (breaking items first — token signatures, the removed
default_connectorsetting, multi-connector polling semantics, snapshot-based roles, the curated my-subscription API; then the optional dunning, tax-seam, reversal, and charge-based integrations), each with its change record. An earlier draft of this text exists in the maintainers' working notes and may be updated instead if it is still around, but the change-record list is the source of truth. Connector maintainers do the work in their own queues (e.g. Recharge still calls the pre-beta3 two-argumentverifyToken()); this step replaces per-issue coordination notes in the roadmap issues.
Tracked here but not blocking 1.0.0:
- #3616779: GoCardless connector module (bank debit: Bacs, SEPA, ACH, PAD) GoCardless connector: a separate project, sequenced after #3615735: Add a rating step for usage-based charges, delivered per connector scheduling mode settles the interface. Ecosystem goal, not a core-module release blocker.
- #3618742: Helcim connector module (charge-based card payments, CAD/USD)
- The
|| ^12compatibility claim from #3603421: Automated Drupal 12 compatibility fixes for subscription_manager 1.0.x-dev, which can ship in a 1.0.x patch release once tested against Drupal 12 betas. - Update the project page
Release criteria for 1.0.0: all Phase 1 through 4 issues Fixed or explicitly deferred with rationale in this meta; test suite green on supported cores; Upgrade Status clean apart from intentionally deferred items; change records published for every API or behavior change; and, immediately after tagging, opt in to security-team coverage. Note the venue change that opt-in brings: security-relevant reports move from this public queue to the security team once a stable, covered release exists.
Remaining tasks
Set this issue as parent on the child issues above; keep this summary updated as issues close or new blockers are filed; close #3275714: Mailchimp entity in the way as outdated separately (its hardcoded Mailchimp requires were removed before beta1 and are absent from 1.0.0-beta2).
User interface changes
Per child issue.
API changes
Per child issue; all pre-stable, so no BC obligations beyond change records.
Data model changes
Per child issue.
Comments
Comment #2
colanComment #3
colanComment #4
colanComment #5
colanAdded #3618739: Add a charge-based connector mode with a local billing cycle engine.
Comment #6
colanComment #7
colanComment #8
colanComment #9
colanComment #10
colanComment #11
colanAdded #3619074: Succeeded charge records are terminal, so payer-initiated reversals (SEPA refunds, Bacs indemnity claims, chargebacks) have nowhere to land to Phase 4, immediately after #3618740: Add a dunning framework: past_due state, scheduled retries, grace period, and lifecycle notifications: every scheme the charge-based rails target allows the payer to reverse a charge after it succeeds (SEPA's eight-week refund right, Bacs indemnity claims, ACH/PAD consumer returns, card chargebacks), so the charge-record lifecycle needs a terminal reversed state that suppresses automatic retries and emits a credit through the #3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core seam. Also corrected the child-issue count in Remaining tasks (the phase lists now hold twenty issues).
Comment #12
colanNeed to wait for release-cutting permission. Request sent to @grasmash.
Comment #13
colanComment #14
colanPhase 2 done,
beta5release tagged.As soon as I get permission, I'll create release nodes for
beta3,beta4, andbeta5.Comment #15
colanUpdated releases.
Comment #16
colanUpdated the name/ID of an upcoming release.
Comment #17
colanAdded #3621280: Add update-path test coverage from a pre-roadmap database fixture, and did some cleanup.
Comment #18
colanAdded #3621282: Show subscribers their invoice history in the membership portal.
Comment #19
colanUpdated now that
beta6is tagged.Comment #20
colanI got the proper access as per #3622722: Offering to maintain Subscription Manager. Published beta3, 4, 5 & 6 release nodes & notes.
Comment #21
colanDunning is in!
Comment #22
colanAdded a step at the end to create an issue in each connector queue to update as per this roadmap.
Comment #23
colanUpdating list (crossing out fixed issues).
Comment #24
colanAdded another issue to do for
beta7: #3627571: Build the membership portal page on capability interfaces, replacing the unused inline-actions APIComment #25
colanAdded step to write documentation.
Comment #26
colanAdded step to update the project page.