Skip to content

Commit

Permalink
move config out of table
Browse files Browse the repository at this point in the history
  • Loading branch information
tiniscule committed Dec 3, 2023
1 parent 95d9087 commit b83cc1e
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 83 deletions.
38 changes: 29 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
# Basejump

> If you're looking for the original Basejump which included a NextJS SaaS starter template, [check out the legacy repo](https://github.com/usebasejump/legacy-basejump-template).
> If you're looking for the original Basejump which included a NextJS SaaS starter
> template, [check out the legacy repo](https://github.com/usebasejump/legacy-basejump-template).
Basejump adds personal accounts, team accounts, permissions and billing support to Supabase Auth.

[Learn more at usebasejump.com](https://usebasejump.com).

## Features
- **Personal accounts**: Every user that signs up using Supabase auth automatically gets their own personal account. Billing on personal accounts can be enabled/disabled.
- **Team accounts**: Team accounts are billable accounts that can be shared by multiple users. Team accounts can be disabled if you only wish to allow personal accounts. Billing on team accounts can also be disabled.
- **Permissions**: Permissions are handled using RLS, just like you're used to with Supabase. Basejump provides convenience methods that let you restrict access to rows based on a user's account access and role within an account
- **Billing**: Basejump provides out of the box billing support for Stripe, but you can add your own providers easily. If you do, please consider contributing them so others can benefit!
- **Testing**: Basejump is fully tested itself, but also provides a suite of testing tools that make it easier to test your own Supabase functions and schema. You can check it out at [database.dev/basejump/supabase_test_helpers](https://database.dev/basejump/supabase_test_helpers). You do not need to be using Basejump to use the testing tools.

- **Personal accounts**: Every user that signs up using Supabase auth automatically gets their own personal account.
Billing on personal accounts can be enabled/disabled.
- **Team accounts**: Team accounts are billable accounts that can be shared by multiple users. Team accounts can be
disabled if you only wish to allow personal accounts. Billing on team accounts can also be disabled.
- **Permissions**: Permissions are handled using RLS, just like you're used to with Supabase. Basejump provides
convenience methods that let you restrict access to rows based on a user's account access and role within an account
- **Billing**: Basejump provides out of the box billing support for Stripe, but you can add your own providers easily.
If you do, please consider contributing them so others can benefit!
- **Testing**: Basejump is fully tested itself, but also provides a suite of testing tools that make it easier to test
your own Supabase functions and schema. You can check it out
at [database.dev/basejump/supabase_test_helpers](https://database.dev/basejump/supabase_test_helpers). You do not need
to be using Basejump to use the testing tools.

## Quick Start (recommended)

Check out the getting started guide at [usebasejump.com](https://usebasejump.com).

## Contributing

Yes please! Here's how you can get started locally

#### Initialize Supabase

```bash
supabase init && supabase start
```

#### Install dependencies using dbdev

1. Install dbdev according to instructions on [database.dev](https://database.dev).
2. Install supabase_test_helpers

```sql
select dbdev.install('basejump-supabase_test_helpers');
```

#### Install local version of basejump_core

```bash
dbdev install --connection postgres://postgres:postgres@localhost:54322/postgres --path .
```

#### Enable basejump_core

```sql
CREATE EXTENSION IF NOT EXISTS basejump_core;
CREATE EXTENSION IF NOT EXISTS basejump_core with schema extensions;
```

#### Make sure tests can run

```bash
supabase test db
```

### Add your changes and write tests.
Make sure you're following the database.dev upgrade guidelines. you should NEVER be updating/changing existing version files. All changes should have valid migration files for postgres extensions. I'll try to flesh this section out more later.
### Add your changes and write tests.

Make sure you're following the database.dev upgrade guidelines. you should NEVER be updating/changing existing version
files. All changes should have valid migration files for postgres extensions. I'll try to flesh this section out more
later.
69 changes: 23 additions & 46 deletions basejump_core--2.0.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,6 @@ $$
end;
$$;

/**
* Billing providers are the different payment processors that
* we support. Currently, we only support Stripe, but we may
* add others in the future.
*/
DO
$$
BEGIN
-- check it account_role already exists on basejump schema
IF NOT EXISTS(SELECT 1
FROM pg_type t
JOIN pg_namespace n ON n.oid = t.typnamespace
WHERE t.typname = 'billing_providers'
AND n.nspname = 'basejump') THEN
create type basejump.billing_providers as enum ('stripe');
end if;
end;
$$;

/**
* Invitation types are either email or link. Email invitations are sent to
* a single user and can only be claimed once. Link invitations can be used multiple times
Expand Down Expand Up @@ -124,12 +105,10 @@ $$;

CREATE TABLE IF NOT EXISTS basejump.config
(
enable_team_accounts boolean default true,
enable_personal_account_billing boolean default true,
enable_team_account_billing boolean default true,
billing_provider basejump.billing_providers default 'stripe',
default_trial_period_days integer default 30,
default_account_plan_id text
enable_team_accounts boolean default true,
enable_personal_account_billing boolean default true,
enable_team_account_billing boolean default true,
billing_provider text default 'stripe'
);

-- create config row
Expand Down Expand Up @@ -371,11 +350,11 @@ EXECUTE PROCEDURE basejump.trigger_set_user_tracking();
create table if not exists basejump.account_user
(
-- id of the user in the account
user_id uuid references auth.users not null,
user_id uuid references auth.users on delete cascade not null,
-- id of the account the user is in
account_id uuid references basejump.accounts not null,
account_id uuid references basejump.accounts on delete cascade not null,
-- role of the user in the account
account_role basejump.account_role not null,
account_role basejump.account_role not null,
constraint account_user_pkey primary key (user_id, account_id)
);

Expand Down Expand Up @@ -467,15 +446,15 @@ execute procedure basejump.run_new_user_setup();
create table if not exists basejump.billing_customers
(
-- UUID from auth.users
account_id uuid references basejump.accounts not null,
account_id uuid references basejump.accounts (id) on delete cascade not null,
-- The user's customer ID in Stripe. User must not be able to update this.
id text primary key,
-- The email address the customer wants to use for invoicing
email text,
-- The active status of a customer
active boolean,
-- The billing provider the customer is using
provider basejump.billing_providers
provider text
);

-- Open up access to billing_customers
Expand All @@ -496,8 +475,8 @@ create table if not exists basejump.billing_subscriptions
(
-- Subscription ID from Stripe, e.g. sub_1234.
id text primary key,
account_id uuid references basejump.accounts not null,
billing_customer_id text references basejump.billing_customers (id) not null,
account_id uuid references basejump.accounts (id) on delete cascade not null,
billing_customer_id text references basejump.billing_customers (id) on delete cascade not null,
-- The status of the subscription object, one of subscription_status type above.
status basejump.subscription_status,
-- Set of key-value pairs, used to store additional information about the object in a structured format.
Expand All @@ -510,11 +489,11 @@ create table if not exists basejump.billing_subscriptions
-- If true the subscription has been canceled by the user and will be deleted at the end of the billing period.
cancel_at_period_end boolean,
-- Time at which the subscription was created.
created timestamp with time zone default timezone('utc' :: text, now()) not null,
created timestamp with time zone default timezone('utc' :: text, now()) not null,
-- Start of the current period that the subscription has been invoiced for.
current_period_start timestamp with time zone default timezone('utc' :: text, now()) not null,
current_period_start timestamp with time zone default timezone('utc' :: text, now()) not null,
-- End of the current period that the subscription has been invoiced for. At the end of this period, a new invoice will be created.
current_period_end timestamp with time zone default timezone('utc' :: text, now()) not null,
current_period_end timestamp with time zone default timezone('utc' :: text, now()) not null,
-- If the subscription has ended, the timestamp of the date the subscription ended.
ended_at timestamp with time zone default timezone('utc' :: text, now()),
-- A date in the future at which the subscription will automatically get canceled.
Expand All @@ -525,7 +504,7 @@ create table if not exists basejump.billing_subscriptions
trial_start timestamp with time zone default timezone('utc' :: text, now()),
-- If the subscription has a trial, the end of that trial.
trial_end timestamp with time zone default timezone('utc' :: text, now()),
provider basejump.billing_providers
provider text
);

-- Open up access to billing_subscriptions
Expand All @@ -550,23 +529,23 @@ alter table
create table if not exists basejump.invitations
(
-- the id of the invitation
id uuid unique not null default uuid_generate_v4(),
id uuid unique not null default uuid_generate_v4(),
-- what role should invitation accepters be given in this account
account_role basejump.account_role not null,
account_role basejump.account_role not null,
-- the account the invitation is for
account_id uuid references basejump.accounts not null,
account_id uuid references basejump.accounts (id) on delete cascade not null,
-- unique token used to accept the invitation
token text unique not null default basejump.generate_token(30),
token text unique not null default basejump.generate_token(30),
-- who created the invitation
invited_by_user_id uuid references auth.users not null,
invited_by_user_id uuid references auth.users not null,
-- account name. filled in by a trigger
account_name text,
-- when the invitation was last updated
updated_at timestamp with time zone,
-- when the invitation was created
created_at timestamp with time zone,
-- what type of invitation is this
invitation_type basejump.invitation_type not null,
invitation_type basejump.invitation_type not null,
primary key (id)
);

Expand Down Expand Up @@ -743,8 +722,6 @@ BEGIN
'billing_status', s.status,
'billing_customer_id', c.id,
'billing_provider', config.billing_provider,
'billing_default_plan_id', config.default_account_plan_id,
'billing_default_trial_days', config.default_trial_period_days,
'billing_email',
coalesce(c.email, u.email) -- if we don't have a customer email, use the user's email as a fallback
)
Expand Down Expand Up @@ -777,7 +754,7 @@ BEGIN
if customer is not null then
insert into basejump.billing_customers (id, account_id, email, provider)
values (customer ->> 'id', service_role_upsert_customer_subscription.account_id, customer ->> 'billing_email',
(customer ->> 'provider')::basejump.billing_providers)
(customer ->> 'provider'))
on conflict (id) do update
set email = customer ->> 'billing_email';
end if;
Expand All @@ -798,7 +775,7 @@ BEGIN
(subscription ->> 'cancel_at')::timestamptz,
(subscription ->> 'canceled_at')::timestamptz, (subscription ->> 'trial_start')::timestamptz,
(subscription ->> 'trial_end')::timestamptz,
subscription ->> 'plan_name', (subscription ->> 'provider')::basejump.billing_providers)
subscription ->> 'plan_name', (subscription ->> 'provider'))
on conflict (id) do update
set billing_customer_id = subscription ->> 'billing_customer_id',
status = (subscription ->> 'status')::basejump.subscription_status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ export type AUTHORIZED_BILLING_USER_INFO = {
billing_customer_id: string;
billing_email: string;
billing_enabled: boolean;
billing_default_plan_id?: string;
billing_default_trial_days?: number;
billing_provider?: string;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export default async function getBillingStatus(
const billingData = await handlers.getBillingStatus({
accountId: roleInfo.account_id,
billingEmail: roleInfo.billing_email,
defaultPlanId: roleInfo.billing_default_plan_id,
defaultTrialDays: roleInfo.billing_default_trial_days,
customerId: roleInfo.billing_customer_id,
subscriptionId: roleInfo.billing_subscription_id,
});
Expand Down
6 changes: 2 additions & 4 deletions supabase/tests/database/01-basejump-schema-tests.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ BEGIN;
create extension "basejump-supabase_test_helpers"
version '0.0.2';

select plan(25);
select plan(24);

select has_schema('basejump', 'Basejump schema should exist');

Expand All @@ -16,7 +16,7 @@ select has_table('basejump', 'billing_subscriptions', 'Basejump billing_subscrip
select tests.rls_enabled('public');

select columns_are('basejump', 'config',
Array ['enable_team_accounts', 'enable_personal_account_billing', 'enable_team_account_billing', 'billing_provider', 'default_trial_period_days', 'default_account_plan_id'],
Array ['enable_team_accounts', 'enable_personal_account_billing', 'enable_team_account_billing', 'billing_provider'],
'Basejump config table should have the correct columns');

select ok(basejump.is_set('enable_personal_account_billing')),
Expand All @@ -26,8 +26,6 @@ select ok((basejump.get_config() ->> 'enable_team_account_billing')::boolean = t
'Basejump config should have team account billing enabled');
select ok(basejump.get_config() ->> 'billing_provider' = 'stripe',
'Basejump config should have stripe as the billing provider');
select ok((basejump.get_config() ->> 'default_trial_period_days')::int = 30),
'Basejump config should have a default trial period';


select function_returns('basejump', 'generate_token', Array ['integer'], 'text',
Expand Down
11 changes: 0 additions & 11 deletions supabase/tests/database/14-public-billing-functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ update basejump.config
set enable_team_account_billing = TRUE,
enable_personal_account_billing = true;

update basejump.config
set default_account_plan_id = 'price_00000000000000';

select plan(6);

select tests.create_supabase_user('test1');
Expand Down Expand Up @@ -86,8 +83,6 @@ select row_eq(
"billing_status": "active",
"billing_customer_id": "cus_00000000000000",
"billing_provider": "stripe",
"billing_default_plan_id": "price_00000000000000",
"billing_default_trial_days": 30,
"billing_email": "[email protected]",
"billing_enabled": true
}'::jsonb),
Expand Down Expand Up @@ -115,8 +110,6 @@ select row_eq(
"billing_status": "active",
"billing_customer_id": "cus_00000000000000",
"billing_provider": "stripe",
"billing_default_plan_id": "price_00000000000000",
"billing_default_trial_days": 30,
"billing_email": "[email protected]",
"billing_enabled": true
}'::jsonb),
Expand Down Expand Up @@ -167,8 +160,6 @@ select row_eq(
"billing_status": "canceled",
"billing_customer_id": "cus_00000000000000",
"billing_provider": "stripe",
"billing_default_plan_id": "price_00000000000000",
"billing_default_trial_days": 30,
"billing_email": "[email protected]",
"billing_enabled": true
}'::jsonb),
Expand All @@ -189,8 +180,6 @@ select row_eq(
"billing_status": "active",
"billing_customer_id": "cus_00000000000001",
"billing_provider": "stripe",
"billing_default_plan_id": "price_00000000000000",
"billing_default_trial_days": 30,
"billing_email": "[email protected]",
"billing_enabled": true
}'::jsonb),
Expand Down
12 changes: 3 additions & 9 deletions supabase/tests/database/15-billing-disabled-functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ select row_eq(
"is_primary_owner": true,
"billing_customer_id": null,
"is_personal_account": false,
"billing_default_plan_id": null,
"billing_subscription_id": null,
"billing_default_trial_days": 30
"billing_subscription_id": null
}'::jsonb),
'get_account_billing_status should handle disabled billing correctly'
);
Expand Down Expand Up @@ -67,9 +65,7 @@ select row_eq(
"is_primary_owner": true,
"billing_customer_id": null,
"is_personal_account": false,
"billing_default_plan_id": null,
"billing_subscription_id": null,
"billing_default_trial_days": 30
"billing_subscription_id": null
}'::jsonb),
'get_account_billing_status should handle disabled billing correctly'
);
Expand Down Expand Up @@ -102,9 +98,7 @@ select row_eq(
"is_primary_owner": true,
"billing_customer_id": null,
"is_personal_account": false,
"billing_default_plan_id": null,
"billing_subscription_id": null,
"billing_default_trial_days": 30
"billing_subscription_id": null
}'::jsonb),
'get_account_billing_status should handle enabled team billing correctly'
);
Expand Down

0 comments on commit b83cc1e

Please sign in to comment.