114 lines
3.8 KiB
Markdown
114 lines
3.8 KiB
Markdown
# License & Entitlement Contracts
|
||
|
||
> **Contracts only.** Integrates services by reference — no cross-service ownership.
|
||
> ADR: [ADR-023](../architecture/adr/ADR-023.md) · [ADR-021](../architecture/adr/ADR-021.md)
|
||
> Contract version: `license-entitlement.v1`
|
||
|
||
---
|
||
|
||
## 1. Layering (aligned with Payment L1/L2/L3)
|
||
|
||
| Layer | Name | Owner | Example |
|
||
| --- | --- | --- | --- |
|
||
| L1 | Service / module / feature entitlement | Core Platform | `payment.module.enabled` |
|
||
| L2 | Service capability pack | Owning service | `payment.byo_psp.basic` |
|
||
| L3 | Feature toggle / capability flag | Owning service | `refunds_enabled` |
|
||
|
||
Commercial License grants **L1** (and may *request* L2 activation via events). Services remain authoritative for L2/L3.
|
||
|
||
---
|
||
|
||
## 2. Contracts
|
||
|
||
### 2.1 ServiceEntitlement
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `tenant_id` | uuid | |
|
||
| `service_identifier` | string | Manifest id |
|
||
| `enabled` | bool | L1 gate |
|
||
| `license_id` | uuid? | Source license |
|
||
| `visible_to_tenant` | bool | Tenant Visibility |
|
||
| `source` | enum | `subscription` \| `trial` \| `admin_grant` \| `legacy` |
|
||
|
||
### 2.2 ModuleEntitlement
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `tenant_id` | uuid | |
|
||
| `module_key` | string | |
|
||
| `service_identifier` | string | |
|
||
| `enabled` | bool | |
|
||
| `license_id` | uuid? | |
|
||
|
||
### 2.3 FeatureEntitlement
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `tenant_id` | uuid | |
|
||
| `feature_key` | string | |
|
||
| `enabled` | bool | |
|
||
| `license_id` | uuid? | |
|
||
|
||
### 2.4 Quota
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `quota_key` | string | e.g. `sms.monthly`, `seats` |
|
||
| `tenant_id` | uuid | |
|
||
| `limit` | int \| `unlimited` | |
|
||
| `period` | enum | `monthly` \| `yearly` \| `lifetime` \| `rolling_30d` |
|
||
| `license_id` | uuid? | |
|
||
|
||
### 2.5 UsageLimit
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `limit_key` | string | |
|
||
| `tenant_id` | uuid | |
|
||
| `max_value` | int | |
|
||
| `enforcement` | enum | `hard` \| `soft` \| `observe` |
|
||
|
||
### 2.6 CapabilityFlag
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `capability_key` | string | Discovery / UI gate |
|
||
| `tenant_id` | uuid | |
|
||
| `value` | bool \| string \| number | |
|
||
| `owner_service` | string | Who evaluates |
|
||
|
||
### 2.7 TenantVisibility
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `tenant_id` | uuid | |
|
||
| `resource_kind` | enum | `service` \| `module` \| `bundle` \| `admin_nav` \| `capability` |
|
||
| `resource_key` | string | |
|
||
| `visible` | bool | Hide inactive commercial surfaces |
|
||
| `reason` | string? | |
|
||
|
||
---
|
||
|
||
## 3. Integration matrix (contracts only)
|
||
|
||
| Service | How commercial foundation integrates |
|
||
| --- | --- |
|
||
| **Identity** | AuthN/session; role checks use permissions exposed when L1+visibility allow; Identity does not own licenses |
|
||
| **Payment** | L1 `payment.module.enabled` from Core; L2/L3 remain Payment; activation may emit `payment.activation.requested` |
|
||
| **Accounting** | Opaque `accounting.contract.requested`; Accounting owns books |
|
||
| **Experience** | Workspace/dashboard shells after entitlement; Experience does not own subscription |
|
||
| **CRM** | Optional L1 `crm.module.enabled`; CRM owns CRM data |
|
||
| **Communication** | Quotas (e.g. SMS) via Quota contracts; Communication owns send engines |
|
||
| **Delivery / Hospitality / Healthcare / Sports / Loyalty** | Same pattern: L1 from Core license; service owns domain |
|
||
|
||
Events that invalidate caches: reuse / extend Core `feature_access.changed` semantics (existing platform pattern).
|
||
|
||
---
|
||
|
||
## 4. Invariants
|
||
|
||
1. No service writes another service’s L2/L3 rows.
|
||
2. Hidden / disabled entitlements MUST not expose admin nav, APIs, or capabilities (same isolation rule as ADR-021).
|
||
3. Quotas are commercial limits; usage metering engines remain future/service-owned.
|