sinfactura-types 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -65,57 +65,123 @@ declare global {
65
65
  /** Resolved entitlements for a specific tenant (matrix + overrides applied). */
66
66
  type ResolvedEntitlements = Record<FeatureKey, Entitlement>;
67
67
  /**
68
- * A sellable plan in the catalog. Seeded into DynamoDB by api#626 and
69
- * served to the frontend via GET /subscription/plans.
68
+ * Implementation status of a feature on a plan row. Informational
69
+ * gating still happens via `enabled` / `limit`. `'service'` rows
70
+ * (e.g. prioritySupport) are human-delivered but still gated like
71
+ * booleans.
72
+ */
73
+ type PlanFeatureStatus = 'live' | 'planned' | 'future' | 'service';
74
+ /**
75
+ * A single feature row in a Plan's `features[]` array. Matches the
76
+ * BE wire format from `GET /subscription/plans` exactly — boolean
77
+ * features carry `enabled`, numeric/metered carry `limit` (-1 =
78
+ * unlimited).
79
+ */
80
+ interface PlanFeature {
81
+ key: FeatureKey;
82
+ type: EntitlementType;
83
+ status: PlanFeatureStatus;
84
+ /** User-facing Spanish description. */
85
+ description: string;
86
+ /** Set on `boolean` features; `null` on numeric/metered. */
87
+ enabled: boolean | null;
88
+ /** Set on `numeric`/`metered` features; `null` on boolean. -1 = unlimited. */
89
+ limit: number | null;
90
+ }
91
+ /**
92
+ * A sellable plan in the catalog. Aligned with the BE wire format from
93
+ * `GET /subscription/plans` (api#859). Source of truth lives in
94
+ * DynamoDB (`PLAN#{tier}` partition), administered via `POST /sa/plans`
95
+ * + `PATCH /sa/plans/{tier}` (api#859).
96
+ *
97
+ * Prices are integers in the `currency` smallest unit (centavos for ARS,
98
+ * cents for USD). `null` = "Contactar ventas" (AVANZADO annual at launch
99
+ * is sales-led; basico/fundador are free) per spec §6.4.
100
+ *
101
+ * **Breaking change vs 1.1.x:** the catalog Plan interface was reshaped
102
+ * to match the BE wire format. Renames & removals:
103
+ * - `label` → `name`
104
+ * - `blurb` → `description`
105
+ * - `priceMonthly` → `priceMonthlyCents` (number | null)
106
+ * - `priceAnnual` → `priceAnnualCents` (number | null)
107
+ * - `currency` widened to `'ARS' | 'USD' | null`
108
+ * - `entitlements: Record<FeatureKey, Entitlement>` → `features: PlanFeature[]`
109
+ * - `isPublic` removed (use `isActive` for visibility gating)
110
+ * - `stripeMonthlyPriceId` / `stripeAnnualPriceId` /
111
+ * `mpPreApprovalPlanIdMonthly` / `mpPreApprovalPlanIdAnnual` removed
112
+ * (BE-internal — not on the public wire format)
113
+ * - `createdAt` / `updatedAt` removed (not on the public wire format)
70
114
  *
71
- * Prices are integers in ARS cents (e.g. $40 000 = 4_000_000).
72
- * `null` = "Contactar ventas" (AVANZADO, pre-unlock).
115
+ * Added per api#859:
116
+ * - `displayOrder` (number)
117
+ * - `color` (single hex string, FE derives `soft`/`border` shades)
118
+ * - `isPopular` (now required, was optional)
73
119
  */
74
120
  interface Plan {
75
121
  tier: PlanTier;
76
- /** Display label "BÁSICO", "EMPRENDEDOR", "PROFESIONAL", "AVANZADO", "FUNDADOR". */
77
- label: string;
78
- /** Short marketing tagline (Spanish). */
79
- blurb?: string;
80
- /** Price in the plan's `currency` smallest unit for monthly billing. `null` = contactar. */
81
- priceMonthly: number | null;
82
- /** Price in the plan's `currency` smallest unit for annual billing (total / 12; ~20% discount). `null` = contactar. */
83
- priceAnnual: number | null;
122
+ /** Display name in Spanish (e.g. "Profesional"). */
123
+ name: string;
124
+ /** Short marketing one-liner in Spanish. */
125
+ description: string;
84
126
  /**
85
- * Currency the prices are denominated in. `'ARS'` at launch; `'USD'`
86
- * is the migration target (api#841). Widened from the launch-only
87
- * `'ARS'` literal in api#842 so the FE can render either currency
88
- * without a type change once the platform flips.
127
+ * Whether the plan is shown on the pricing page and accepting new
128
+ * subscribers. Closed-cohort plans (e.g. Founders after the cutoff)
129
+ * and pre-launch tiers (e.g. AVANZADO until ≥2 Planned features ship)
130
+ * set this to `false` without deleting the plan row.
89
131
  */
90
- currency: 'ARS' | 'USD';
132
+ isActive: boolean;
91
133
  /**
92
- * Whether the plan is accepting new subscribers. Closed-cohort plans
93
- * (e.g. Founders after 2026-05-31) set this to `false` without deleting
94
- * the plan row.
134
+ * Anchor / recommended tier on the pricing page. The FE typically
135
+ * renders the "Más elegido" pill on the plan(s) flagged here. The
136
+ * BE does not enforce uniqueness — admins can flag any number of
137
+ * plans, but the canonical convention is exactly one.
95
138
  */
96
- isActive: boolean;
97
- /** Marked as the anchor / recommended tier on the pricing page. PROFESIONAL at launch. */
98
- isPopular?: boolean;
139
+ isPopular: boolean;
140
+ /** Sort order on the pricing page (ascending). Ties allowed. */
141
+ displayOrder: number;
142
+ /** Monthly price in `currency` smallest units. `null` = sales-led / free. */
143
+ priceMonthlyCents: number | null;
144
+ /** Annual price in `currency` smallest units. `null` = sales-led / free. */
145
+ priceAnnualCents: number | null;
146
+ /**
147
+ * Currency the prices are denominated in. `'ARS'` at launch; `'USD'`
148
+ * is the migration target (api#841). `null` on free / off-billing
149
+ * tiers (basico, fundador).
150
+ */
151
+ currency: 'ARS' | 'USD' | null;
99
152
  /**
100
- * Visibility on the public pricing page. AVANZADO = `false` until
101
- * ≥2 Planned features ship (per SUBSCRIPTION_TIERS_BEST_PRACTICES §0).
153
+ * Single brand hex color (e.g. '#590d82'). The FE derives `soft`
154
+ * (light tint) and `border` shades via MUI's `alpha()` helper.
155
+ * `null` on plans created/seeded before the api#859 backfill.
102
156
  */
103
- isPublic: boolean;
104
- /** Stripe Price IDs once the plan is wired to Stripe Products (api#627). */
105
- stripeMonthlyPriceId?: string;
106
- stripeAnnualPriceId?: string;
157
+ color: string | null;
107
158
  /**
108
- * MercadoPago PreApprovalPlan IDs populated by the future
109
- * `seed-mercadopago-plans` Lambda (api#843). Coexist with the Stripe
110
- * IDs above on the same Plan row so both providers' state can live
111
- * in one place; unused fields stay dormant.
159
+ * Per-feature configuration. Every `FeatureKey` appears exactly once.
160
+ * Boolean features carry `enabled`; numeric/metered carry `limit`.
112
161
  */
113
- mpPreApprovalPlanIdMonthly?: string;
114
- mpPreApprovalPlanIdAnnual?: string;
115
- /** Per-tier entitlement configuration. */
116
- entitlements: Record<FeatureKey, Entitlement>;
162
+ features: PlanFeature[];
163
+ }
164
+ /**
165
+ * One audit row per SUPER_ADMIN-driven plan mutation. Returned by
166
+ * `GET /sa/plans/{tier}/audit` (api#859). The same row shape is used
167
+ * for the sibling `STORE` audit partition (api#827).
168
+ *
169
+ * `before` and `after` carry only the fields that changed (diff slice),
170
+ * not the full row blob.
171
+ */
172
+ interface PlanAuditEntry {
173
+ entity: 'PLAN';
174
+ entityId: string;
175
+ timestamp: number;
176
+ actor: {
177
+ userId: string;
178
+ fullName: string;
179
+ };
180
+ action: string;
181
+ before: Record<string, unknown>;
182
+ after: Record<string, unknown>;
183
+ reason: string;
117
184
  createdAt: number;
118
- updatedAt: number;
119
185
  }
120
186
  /**
121
187
  * A tenant's current subscription row. One per `tenantId`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinfactura-types",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",