Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions concept/membership-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Membership V2

## Tables

### user

| Field | |
| --- | --- |
| **`id`** | |
| **`auto_renew`** | Boolean |
| **`current_product`** | enum(ABO, BENEFACTOR_ABO, MONTHLY_ABO, ABO_GIVE_MONTHS) |

### subscription credit

| Field | |
| --- | --- |
| **`id`** | |
| **`user_id`** | |
| **`credit`** | INT, Amount of days |
| **`createdAt`** | Date |

### subscription debit

| Field | |
| --- | --- |
| **`user_id`** | |
| **`debit`** | |
| **`createdAt`** | Date |
| **`endedAt`** | NULL | Date |

`CONSTRAINT "only one active debit per user" UNIQUE(user.id, endedAt)`

### payment history

| Field | |
| --- | --- |
| **`price`** | |
| **`product`** | enum(ABO, BENEFACTOR_ABO, MONTHLY_ABO, ABO_GIVE_MONTHS) |
| **`subscription`.id** | |

## Queries

```SQL
# is active
SELECT
COUNT(*) > 0 AS is_active
FROM
subscription_debit
WHERE
user_id = $userId
AND
endedAt = NULL
GROUP BY
user_id;

# balance
SELECT
subscription_credit.user_id,
SUM(subscription_credit.credit) AS "sum_credit",
SUM(subscription_debit.debit) AS "sum_debit",
(sum_credit - sum_debit) AS balance
FROM
subscription_credit
INNER JOIN
subscription_debit
ON
subscription_credit.user_id = subscription_debit.user_id
WHERE
user_id = $user_id
GROUP BY
user_id
```
71 changes: 71 additions & 0 deletions guides/membership-state-machine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
type StateName =
| 'lead'
| 'prospect'
| 'trial active'
| 'trial active, yearly dromant'
| 'yearly active'
| 'yearly grace period'
| 'yearly active, yearly dormant'
| 'monthly active'
| 'monthly grace period'
// | 'monthly gift active'

type Trigger =
| 'activate free trial'
| 'buy yearly'
| 'buy monthly'
| 'buy prolongation'
| 'redeem monthly gift'
| 'prolongation auto-payed'
| 'active period ends'
| 'grace period ends'

type State = {
[key in Trigger]?: StateName
}

type States = {
[key in StateName]: State
}

const states: States = {
lead: {
'buy yearly': 'yearly active',
'buy monthly': 'monthly active',
'activate free trial': 'trial active'
},
prospect: {
'buy yearly': 'yearly active',
'buy monthly': 'monthly active'
},
'trial active': {
'buy yearly': 'trial active, yearly dromant',
'active period ends': 'prospect'
},
'trial active, yearly dromant': {
'active period ends': 'yearly active'
},
'yearly active': {
'active period ends': 'yearly grace period',
'buy prolongation': 'yearly active',
'buy yearly': 'yearly active, yearly dormant'
// 'redeem monthly gift'
},
'yearly active, yearly dormant': {
'active period ends': 'yearly active'
},
'yearly grace period': {
'buy prolongation': 'yearly active',
'prolongation auto-payed': 'yearly active',
'buy yearly': 'yearly active, yearly dormant',
'grace period ends': 'prospect'
},
'monthly active': {
'active period ends': 'monthly grace period',
'prolongation auto-payed': 'monthly active'
},
'monthly grace period': {
'prolongation auto-payed': 'monthly active',
'grace period ends': 'prospect'
}
}