Files
member-console/design/documents/issue-24-subscription-module-extraction.md
T
cgalo5758 bfe9cee0fe Consolidate design docs into documents directory
- Remove per-module projection files (README, architecture, companion,
  interfaces, model) under design/<module>/
- Add design/documents/ with numbered design docs, references, policies,
  and manifest
- Update design/README.md to describe the directory as a mirror of
  membcons-db's normative surfaces
- Record Decisions 140-141 in companion and glossary; update
  data-model.md schema organization
2026-08-21 00:55:42 -05:00

11 KiB
Raw Blame History

Issue 24 — Subscription Management Module Extraction

Status: RESOLVED by Document 38 (Decisions 127128). Trigger #1 fired (Issue 26 placed a contract-versioning apparatus — subscription_scheduled_changes and the commitment attributes of Decisions 123/126 — provisionally in billing), advancing the issue to assessment via the Stage-3 brief (prompts/issue-24-subscription-module-extraction.md). The assessment kept the subscription lifecycle within billing as a named internal seam rather than extracting a subscriptions schema (the structural-dependency analysis was decisive: billing's financial core holds inbound FKs to the seam). This file is retained as the historical record of the issue's development; the decision authority is Document 38. Authoritative issue entry: modules/companion.mdIssue 24 Surfaced by: Document 31 (Plan Enrollment — Architectural Recommendation), §"Related architectural consideration" Related: Documents 27 (Module Boundary Proposal), 28 (Grants Module Placement), 29 (Product Entitlement Rules Placement), 30 (Schema-Per-Module Adoption); Document 36 (Subscription-Change Economics — source of the triggering apparatus) Advanced by: Issue 26's resolution (Document 36, Decisions 123126), which satisfied trigger #1 (contract-versioning apparatus)


Purpose of this document

This document collects the context accumulated around the question "should subscription management occupy its own module, distinct from billing?" without attempting to answer it. Its role is to preserve the reasoning already developed — so that when the question is taken up, the investigation starts from a loaded position rather than recapitulating Document 31's aside and the companion.md Issue 24 entry.

Nothing in this document is a decision. Nothing in this document proposes schema change. When the issue is assessed, the output will be a numbered design document (the next available doc-*-subscription-module-extraction.md), not a revision of this file. This file is reference material; the decision apparatus lives elsewhere.


The question in one sentence

Does the governing-question test distinguish billing ("what is owed, by whom, for what, and has it been paid?") from a not-yet-extracted subscriptions module ("what is the state of this customer's ongoing commercial agreement, and how has it changed?") sharply enough to justify a schema-per-module split?


Governing questions

Module Governing question
billing (as currently scoped) "What is owed, by whom, for what, and has it been paid?"
Hypothetical subscriptions "What is the state of this customer's ongoing commercial agreement, and how has it changed?"
entitlements "What does this entity have?"

The current arrangement collapses the first two questions into billing. This is defensible — subscriptions are the dominant invoice generator and sit operationally close to invoices, prices, and billing accounts — but may be load-bearing in ways that merit a dedicated module boundary.

Signals that a split may be warranted

  1. Rate-card dissolution trend (industry). reference-plan-enrollment-modeling.md §6 documents Metronome and Stripe v2 decomposing "plan" into Rate Card (pricing), License Fee (recurring commitment), and Contract (the customer-to-rate-card binding). The Contract role is structurally what a subscription module would own — the industry treats it as a first-class concern separable from pricing mechanics.

  2. Definiteness test applied to subscriptions themselves. A subscription is neither a capability ("what does this entity have?" — entitlements) nor, strictly, a billing fact ("who owes what?" — billing). It is the temporal agreement that generates billing facts over time. Invoices answer "who owes?"; subscriptions answer "on what recurring basis?" These are adjacent, not identical, governing questions.

  3. Change-log weight. subscription_changes is a substantial audit surface with its own lifecycle vocabulary (item_added, trial_started, paused, resumed, canceled, etc.) distinct from the audit trails of invoices or payments. A module boundary would make this independence explicit.

  4. Cross-module write direction is coherent. A subscription module would consume billing.products and billing.prices (catalog), produce entitlements.pool_provisions (via materialization), and feed billing.invoices (generated on billing-cycle close). It would sit cleanly downstream of the catalog and upstream of both entitlement materialization and invoice generation — a well-defined dependency direction.

Signals that the current collapse may be load-bearing

  • Operational proximity. Subscriptions, invoices, and prices are co-queried constantly in invoice-generation pipelines. A module boundary introduces cross-schema joins for very frequent operations.
  • Historical convention. Stripe, Recurly, Paddle, and Lago all treat subscription management as part of billing rather than adjacent to it. The industry terminology "Billing Module" typically includes subscriptions. Divergence requires affirmative justification.
  • Duplicate catalog boundary. The ladder-and-price catalog already defines a natural arch between "what we sell" (products, prices, plan_ladders) and "what is sold to whom" (subscriptions). Whether that arch should be a module boundary or an internal seam within billing is precisely the open question.

Candidate set boundaries (preliminary, from Document 31 §"Scope notes")

  • Clearly in the new module, if it is extracted: subscriptions, subscription_items, subscription_changes.
  • Ambiguous: purchases — a completed one-time agreement. Subscription-module by governing-question alignment ("a commercial agreement is in force"), or billing-module by lifecycle simplicity (single transaction, no ongoing state)?
  • Ambiguous: prices — catalog pricing. Likely stays in billing despite being subscription-consumed, because pricing answers "what does this cost?" not "what agreement is in force?"
  • Clearly out of the new module: invoices, payments, billing_accounts, credit_grants, credit_transactions — all answer "who owes / paid / holds credit" rather than "what agreement is in force."

Relationship to adjacent decisions and issues

  • Issue 23 (Plan Enrollment — RESOLVED by Document 31). Orthogonal. plan_ladders stays in billing in either arrangement; the exclusion constraint stays on entitlements.pool_provisions; the canonical enrollment query does not reference subscriptions directly. The only induced changes are clerical FK relocations. Issue 24 does not block and was not blocked by Issue 23.

  • Issue 25 (Trial Handling — RESOLVED by Document 34). Orthogonal. Trials remain at the price and subscription layers; extraction would relocate subscriptions.trial_start/trial_end to the new schema but not alter trial semantics. No interaction.

  • Issue 22 (Consumption Tracking Module Extraction — DEFERRED). Potentially related. Both issues concern whether an operationally heavy sub-domain currently inside a larger module warrants its own schema. A precedent set by one would inform the other.

  • Decision 106 (Grants moved from billing to entitlements). Methodological precedent. Grants were relocated on governing-question grounds (answered "what does this entity have?" not "who pays?") without schema change — module assignment is a documentation/development concern. The same apparatus — definiteness test, governing-question test, structural dependency analysis, module-coherence accounting — applies here.

  • Decisions 107, 108 (Product Entitlement Rules placement). Methodological precedent. A table was moved across a module boundary on the strength of module-coherence analysis.

  • Decision 113 (Schema-per-module adoption). Any extraction would produce a new PostgreSQL schema (subscriptions) with its own _writer role (Decision 88 pattern). Cross-module FKs retained per Decision 114.


Trigger conditions for advancing to assessment

Per modules/companion.mdIssue 24, assessment should begin when one or more of the following concrete triggers appears:

  1. A concrete subscription-lifecycle concern arises that is awkward to express with billing-module placement — e.g., a rating engine, a contract-versioning apparatus, or a subscription-state projection required by a non-billing consumer.

  2. A second module begins consuming subscription_changes as an audit source, making its billing placement misleading in cross-module documentation.

  3. Billing module table count or internal heterogeneity reaches the threshold that motivated prior extractions. At time of writing, billing holds 20 tables — the largest of any module. This alone is not dispositive (table count is a symptom, not a diagnosis), but continued growth without a clean internal seam is a symptom worth tracking.

  4. An external research pass specifically on subscription-vs-billing module boundaries surfaces patterns the project has not yet considered. The reference-plan-enrollment-modeling.md synthesis touched on this incidentally (§6, rate-card dissolution); a dedicated pass would be warranted if triggers 13 accumulate.


What the investigation, when it runs, should produce

When assessed, the investigation should follow the Document 33 methodology and produce:

  • Stage 3 brief: A new prompts/issue-24-subscription-module-extraction.md parameterizing the decision space.
  • Stage 4 recommendation: A numbered document (the next available doc-*-subscription-module-extraction.md) rendering the decision under the apparatus of Documents 27, 28, and 29 — definiteness test, governing-question test, structural dependency analysis, module-coherence accounting.
  • Stage 5 framing memo (conditional): Only if new terminology or unresolved scope emerges.

The investigation should not begin from this holding document's framing as though it were neutral. The signals enumerated in §Background are weighted toward extraction because they are the signals that surfaced the issue in the first place. A rigorous assessment must also enumerate, and weigh, the signals against extraction — of which the strongest, at present, is industry convention.


Status of this document

This is not a design document. It is a pointer file preserved to ensure that:

  1. The Document 31 aside does not become orphaned context as that document is further amended.
  2. The companion.md Issue 24 entry has a linkable home for the extended reasoning that would otherwise expand the companion beyond its proper size.
  3. Future assessment begins from accumulated context, not from scratch.

When Issue 24 is assessed and resolved, this file may be superseded by or folded into the resulting numbered document, or retained as a historical record of the issue's development trajectory. The disposition is itself a question for that future investigation.