Giter Club home page Giter Club logo

basejump's Introduction

Basejump

Basejump adds personal accounts, team accounts, permissions and billing support to Supabase Auth.

Learn more at usebasejump.com. Ask questions on X / Twitter

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. You do not need to be using Basejump to use the testing tools.



Quick Start

Check out the getting started guide at usebasejump.com.

Optional Nextjs starter template

We've got a fleshed out starter template ready to go for Basejump built using NextJs. You can install it by running:

yarn create next-app -e https://github.com/usebasejump/basejump-next

Then add your Supabase URL and anon key to your .env.local file. There's an example in the .env.example file.

Note: create-next-app forces you to install the template into a nested directory. You can move the contents of the directory to the root of your project if you'd like.



Running tests

Basejump includes comprehensive pgtap testing for all included functionality - but it's not enabled by default in case that's not your jam. To run the tests, you'll need to add a few dependencies.

Install pgtap

create extension pgtap with schema extensions;

Install dbdev

Follow the directions at database.dev to install dbdev.

Install supabase_test_helpers

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

Run the tests

supabase test db



Contributing

Yes please! Please submit a PR with your changes to the basejump github repo. Please make sure your changes are well tested and documented.

You can contribute in the following places:

basejump's People

Contributors

cayblood avatar isaacharrisholt avatar knajjars avatar markusremplbauer avatar tiniscule avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

basejump's Issues

'withApiAuth' is deprecated

thank you so much for such a great framework

Are you planning to upgrade the withApiAuth with createServerSupabaseClient?

This project should use the same copy-paste logic as the UI components

I've been using the new Basejump package since its release. First, I wanted to say that it's great work and I appreciate you built this to assess Supabase's needs for a native(ish) organization system. Tho I think, dbdev (and the project being a package) greatly limits the ability of it to be truly useful.

First, the maintainers are already unable to publish the first big update, due to an issue with dbdev.

Second, this makes local development impossible if you're not connected to the internet.

Third, is that the project provides an awesome starter set of functions and tables for a team system but makes it unnecessarily complex to extend it. I have to dig into the Basejump SQL file on GitHub, search for the relevant sections and copy-paste that part into a new migration in my project. This is way less productive than just a simple copy-paste when integrating Basejump.

A few examples that came up where I needed to extend:

  • Use the generated usernames as slugs throughout a site. Then I found out that it is not guaranteed to be unique. Or let Basejump use the usernames set by users or my app on sign-up.
  • Personal accounts to also use the slug column.
  • Add new application-wide roles plus RLS.
  • Access Basejump account IDs on auth.users or in a custom public.profiles
  • Adding a trigger function to the same event targeting the same table as Basejump (ex.: run_new_user_setup() on auth.users) gets very confusing because of how postgres handles the function execution order. Especially if I want to have access to the Basejump account_id in my function. It'd be way simpler if we could just extend the already existing Basejump function.

So, I recommend making the core functionality copy-pastable and extensible by default, just as the UI components (as the shadcn/ui components). The command @usebasejump/cli@latest init should create a migration file (or ideally multiple files by feature) with the chosen functionality, instead of a dbdev HTTP call.

Confused on how to use RPC to get account info.

Hi, so I am confused how to use the RPC methods to get the account info. What I'm trying to do is just have a single function to get the account for me, and it automatically determines whether the account selector is on a team or not. Currently is what I have below, and basically, it just checks to see if there is a slug in the URL. Basically im wondering if theres a better way to do this, because its very sloppy and its a huge mess. A huge issue too is that the RPCs dont get types when generated with the supabase CLI. Basically I'd like advice on how to implement this with it being disaster. Thanks.

EDIT: Even more so, it seems like Supabase is trying to find these RPC on the public schema, where they dont exist. Dont know how to fix that either or something like that
Searched for the function public.get_account_by_slug without parameters or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache

`import { createClient } from "@/utils/supabase/server";

export interface AccountData {
account_id: string;
account_role: string;
is_primary_owner: boolean;
name: string;
slug: string;
personal_account: boolean;
billing_enabled: boolean;
billing_status: string;
created_at: string; // Assuming timestamp is a string, adjust if it's a Date object
updated_at: string; // Same assumption as created_at
metadata: {
[key: string]: any; // Adjust according to the known structure or keep it flexible
};
}

export async function getAccountData({ params }: { params: { slug: string } }) {
const supabase = createClient();
if (params.slug === "personal") {
const { data, error } = await supabase.rpc("get_personal_account");
return { data: data as unknown as AccountData, error };
}

const { data, error } = await supabase.rpc("get_account_by_slug", {
slug: params.slug,
});
return { data: data as unknown as AccountData, error };
}
`

I can't create a team from my deploy version

Hello,

I have a problem with my deploy version.

On my local server when I sign up it automatically creates an 'account_user'

Yet when I deployed the project on Vercel and I sign up, I only have a profile user but no 'account-user associated'

(I have not setup Stripe, don't know if it has an impact on the deploy version, in addition, I 'enable_personal_accounts' in my db.

Could you help me with it? :)

Package issue with vite/react causes build error

Hi all, when installing @usebasejump/react in a project with vite, it looks like there's some issues with the npm package that causes the import to fail.

Error: (when importing anything with the package)

[ERROR] Failed to resolve entry for package "@usebasejump/react". The package may have incorrect main/module/exports specified in its package.json. [plugin vite:dep-scan]

Minimum Reproduction:

  1. npm create vite
  2. select react, typescript + swc
  3. npm install @usebasejump/react
  4. npm install
  5. add an import to App.tsx - import { usePersonalAccount } from "@usebasejump/react";
  6. then just use it so the the bundler grabs it, you don't need to get a Supabase client or anything set up first as an argument, it doesn't matter for this error - const personalAccount = usePersonalAccount();
  7. npm run dev, experience error.

I tried figuring this issue out with the package, but wasn't quite able to. I ended up just taking the hooks and types and placing directly in my repo and it all works great for now in the meantime. Thanks for making this project, it's a huge timesaver.

error: Module not found lib/types/supabase.ts".

when i try to deploy the function to supabase, I get

Error: failed to load 'https://deno.land/x/[email protected]/billing-functions/lib/types/supabase.ts': Module not found "https://deno.land/x/[email protected]/billing-functions/lib/types/supabase.ts". error running container: exit 1

this error in
at https://deno.land/x/[email protected]/billing-functions/lib/create-supabase-client.ts:2:26

is trying to import file supabase.ts but it doesn't exist

"ReferenceError: window is not defined" error while depoling to vercel.

When I deploy to vercel I get an error "ReferenceError: window is not defined".

next-translate - compiled page: /blog/[...slug] - locale: en - namespaces: content - used loader: getStaticProps
--
23:00:14.541 | next-translate - compiled page: /docs/[...slug] - locale: en - namespaces: content - used loader: getStaticProps
23:00:14.553 | ReferenceError: window is not defined
23:00:14.553 | at getFullRedirectUrl (/vercel/path0/.next/server/chunks/392.js:78:40)
23:00:14.554 | at ContentMeta (/vercel/path0/.next/server/chunks/392.js:54:115)
23:00:14.554 | at Wc (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
23:00:14.554 | at Zc (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
23:00:14.555 | at Z (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
23:00:14.555 | at $c (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
23:00:14.562 | at bd (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
23:00:14.562 | at Z (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:217)
23:00:14.562 | at $c (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
23:00:14.562 | at Zc (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:71:145)

It works fine on the my local machine.

Blogs should support pagination

Right now blogs are displayed in full on a single page.

Need to swap to pagination with X articles per page (configurable).

Error creating team: «new row violates row-level security policy for table "accounts"»

After generating a boilerplate project and setting up supabase to run locally, I get the following error when trying to create a team for a newly-created user:

Screenshot 2023-01-17 at 8 37 10 PM

If I understand correctly, this new user should be a primary account and therefore should be able to create a team according to the security policies.

I'm also struggling to figure out how to debug postgres issues when running locally. Tailing the logs doesn't really reveal much about why a security policy is failing. Any tips you have here would be greatly appreciated. Thanks!

get_personal_account doesn't include email

The example on this page shows the page accessing data.email from the get_personal_account RPC response: https://usebasejump.com/docs/react/user-account-button. For context i'm using the RSC example.

When in fact the response does not contain email. Here's an example response:

{
  account_id: '3360b947-c0d2-4873-a145-64d5f6e399cf',
  account_role: 'owner',
  is_primary_owner: true,
  name: 'ian',
  slug: null,
  personal_account: true,
  billing_enabled: true,
  billing_status: null,
  created_at: '2024-01-11T00:02:55.986862+00:00',
  updated_at: '2024-01-11T00:02:55.986862+00:00',
  metadata: {}
}

Which matches the API docs: https://usebasejump.com/docs/accounts#retrieve-personal-account. My understanding is "Account" refers to a grouping of users, in which case it makes sense that email isn't included.

`/dashboard/teams/[accountId]/settings/*` pages not protected from team members

Great project so far.

Found an edge case when I have a team member (not owner) that is able to access settings pages. Even though the sidebar hides the menu item Settings, a member can simply enter the URLs for the settings.

RLS prevents a team member from updating settings, but they should not be able to view/interact with the pages at all.

Here is a screenshot of a team member that is able to view the the settings/members page:

CleanShot 2023-09-08 at 01 05 20

If a member accesses a nested Settings page, they should be redirected to the Team Dashboard.
Even though RLS is taking care of the data, what is a good pattern to protect routes?

Audit log (supa_audit)

Hey! First thing, great work with basejump! I started on a similar project myself, but found that you have done a lot of the thing I was planning (but better), so I've decided to try and contribute to basejump instead.

I'm thinking about adapting https://github.com/supabase/supa_audit for the basejump multi tenancy setup and create a frontend-view for it. Would you be open for submission for such a feature?

The edge runtime does not support Node.js 'buffer' module.

After I signup or try to login I get this

: getStaticProps
Failed to parse cookie string: [Error: The edge runtime does not support Node.js 'buffer' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime]

Can't start (pg_tle)

After clonning i am trying supabase start and have error that pg_tle not exist. How to fix it? I use wsl2 with ubuntu.


2023/07/01 10:54:38 PG Recv: {"Type":"BindComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"NoData"}
2023/07/01 10:54:38 PG Recv: {"Type":"CommandComplete","CommandTag":"DROP EXTENSION"}
2023/07/01 10:54:38 PG Recv: {"Type":"ParseComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"BindComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"NoData"}
2023/07/01 10:54:38 PG Recv: {"Type":"CommandComplete","CommandTag":"CREATE EXTENSION"}
2023/07/01 10:54:38 PG Recv: {"Type":"ParseComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"BindComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"NoData"}
2023/07/01 10:54:38 PG Recv: {"Type":"CommandComplete","CommandTag":"RESET"}
2023/07/01 10:54:38 PG Recv: {"Type":"ReadyForQuery","TxStatus":"I"}
Applying migration 00000000000000_dbdev_temp_install.sql...
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"/**\n  This should be automatically installed, but handling here manually until it is\n  https://database.dev/installer\n */\ncreate extension if not exists http with schema extensions","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"create extension if not exists pg_tle","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"select pgtle.uninstall_extension_if_exists('supabase-dbdev')","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"drop extension if exists \"supabase-dbdev\"","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"select pgtle.install_extension(\n               'supabase-dbdev',\n               resp.contents -\u003e\u003e 'version',\n               'PostgreSQL package manager',\n               resp.contents -\u003e\u003e 'sql'\n           )\nfrom http(\n             (\n              'GET',\n              'https://api.database.dev/rest/v1/'\n                  || 'package_versions?select=sql,version'\n                  || '\u0026package_name=eq.supabase-dbdev'\n                  || '\u0026order=version.desc'\n                  || '\u0026limit=1',\n              array [\n                  ('apiKey',\n                   'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhtdXB0cHBsZnZpaWZyYndtbXR2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODAxMDczNzIsImV4cCI6MTk5NTY4MzM3Mn0.z2CN0mvO2No8wSi46Gw59DFGCTJrzM0AQKsu_5k134s')::http_header\n                  ],\n              null,\n              null\n                 )\n         ) x,\n     lateral (\n         select ((row_to_json(x) -\u003e 'content') #\u003e\u003e '{}')::json -\u003e 0\n         ) resp(contents)","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"create extension \"supabase-dbdev\"","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"select dbdev.install('supabase-dbdev')","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"drop extension if exists \"supabase-dbdev\"","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Parse","Name":"","Query":"create extension \"supabase-dbdev\"","ParameterOIDs":null}
2023/07/01 10:54:38 PG Send: {"Type":"Bind","DestinationPortal":"","PreparedStatement":"","ParameterFormatCodes":null,"Parameters":[],"ResultFormatCodes":[]}
2023/07/01 10:54:38 PG Send: {"Type":"Describe","ObjectType":"P","Name":""}
2023/07/01 10:54:38 PG Send: {"Type":"Execute","Portal":"","MaxRows":0}
2023/07/01 10:54:38 PG Send: {"Type":"Sync"}
2023/07/01 10:54:38 PG Recv: {"Type":"ParseComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"BindComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"NoData"}
2023/07/01 10:54:38 PG Recv: {"Type":"CommandComplete","CommandTag":"CREATE EXTENSION"}
2023/07/01 10:54:38 PG Recv: {"Type":"ParseComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"BindComplete"}
2023/07/01 10:54:38 PG Recv: {"Type":"NoData"}
2023/07/01 10:54:38 PG Recv: {"Type":"ErrorResponse","Severity":"ERROR","SeverityUnlocalized":"ERROR","Code":"0A000","Message":"extension \"pg_tle\" is not available","Detail":"Could not open extension control file \"/usr/share/postgresql/15/extension/pg_tle.control\": No such file or directory.","Hint":"The extension must first be installed on the system where PostgreSQL is running.","Position":0,"InternalPosition":0,"InternalQuery":"","Where":"","SchemaName":"","TableName":"","ColumnName":"","DataTypeName":"","ConstraintName":"","File":"extension.c","Line":539,"Routine":"parse_extension_control_file","UnknownFields":null}
2023/07/01 10:54:38 PG Recv: {"Type":"ReadyForQuery","TxStatus":"I"}
2023/07/01 10:54:38 PG Send: {"Type":"Terminate"}
Error: ERROR: extension "pg_tle" is not available (SQLSTATE 0A000)
At statement 1: create extension if not exists pg_tle

Feature suggestion: offer graphql instead of supabase sdk

One of the reasons I chose supabase is because at its core, it is just postgres. I want to build faster by leveraging a managed database, but I always want to preserve my ability to revert to plain old postgres if I need to. For example, if supabase goes out of business or if it becomes overpriced etc. So I want to build my app using protocols that will continue to work on a more standard installation of postgres. PostgREST and pg_graphql seem like good projects for achieving this. I'd like to suggest that you consider offering a version of basejump that demonstrates how to build a project based on supabase that doesn't rely on any supabase-specific features, like their js libraries.

Accessibility Issue on Mobile

Thank you for this project!! I was struggling to get teams management to work for my next app.

One small issue I found however, is scrolling on mobile:

OS: iOS 15.6.1
Browser: Safari

Current Behavior: Tapping the top of the page does not automatically scroll.
Expected Behavior: Tapping the top of the page on mobile should automatically scroll the page to the top.

Haven't looked too much into the tailwind utilities yet, so I wanted to see if anyone else was getting this bug as well.

Thank you!

Question about teams feature

Just want to say thank you again for your amazing work. Wanted to see if I could get some feedback on an idea I have to extend the teams functionality. This might actually just be a SQL question... but figured it might help someone else.

My application is requiring an organization feature. An organization can have many teams, and its purpose is for admin of the organization to view all data within a team. For example, a school (organization) would have many classes (teams), which would have many users (students/teachers). An organization would have admin users that wouldn't necessarily belong to any team.

I'm not sure if there would be a way to "bolt" this onto basejump.

One of the approaches I thought of is to keep the accounts and account_user tables as-is and create a new table called teams. The teams table would have a foreign key account_id to associate it with an account (organization). Doing so would keep the roles/permissions in place. I would only need to create similar roles/permissions for the teams table.

Appreciate any feedback, thank you.

Joins on accounts from public schema

When using created_by and updated_by columns, the relation points to auth.users table.

I would have liked to be able to retrieve the name of the account through this relation, but it is not possible to query relations across different schemas.

The same issue arises with account_id columns in public schema tables.

What approach do you recommand for this ?

Update plan settings

Can you create a demo with a pricing page? The link Update plan settings inside Billing is redirecting to a 404 page

RFC: Migrate Basejump to a set of UI Components and API Endpoints

In an effort to make Basejump more useful to people and remove some of the dependency on Next, I'm looking at converting it into a selection of UI components and rpc functions that can be used in any language / framework.

Goals

  • Make Basejump easier to use and more useful as applications scale
  • Provide a basic set of UI components, themable with the same appearance prop as Supabase AuthUI
  • Remove the dependency on NextJS and allow it to be used in any framework
  • Abstract away account features to make it easier to add new functionality without risking security
  • Add additional component libraries for vue and svelte

UI Components

Instead of a full starter template, Basejump would provide a set of UI components that make creating and managing accounts easy. As your startup scales, you could take control over the UI components by creating your own using the API endpoints in the next section.

All components are customized using the same appearance prop as Supabase AuthUI. This allows you to customize the look and feel of the components to match your application.

Account Switcher

import { AccountSwitcher } from '@usebasejump/account-ui-react';

const supabaseClient = useSupabaseClient();

<AccountSwitcher 
    supabaseClient={supabaseClient} 
    appearance={{{theme: ThemeSupa}}} 
    onAccountChange={(account) => router.push(`/accounts/${account.id}`)}
    currentAccount={currentAccount}
/>

Account Settings

Shows an account overview, members and invitations. Let's you create new invitations

import { AccountSettings } from '@usebasejump/account-ui-react';

const supabaseClient = useSupabaseClient();

<AccountSettings 
    supabaseClient={supabaseClient} 
    appearance={{{theme: ThemeSupa}}} 
    currentAccount={currentAccount}
/>

Account Billing

Shows the current billing status and allows you to change the plan

import { AccountBilling } from '@usebasejump/account-ui-react';

const supabaseClient = useSupabaseClient();

<AccountBilling 
    supabaseClient={supabaseClient} 
    appearance={{{theme: ThemeSupa}}} 
    currentAccount={currentAccount}
/>

Account Status Bar

Shows a banner if account status is inactive or delinquent. Allows user to correct the issue.

import { AccountStatusBar } from '@usebasejump/account-ui-react';

const supabaseClient = useSupabaseClient();

<AccountStatusBar 
    supabaseClient={supabaseClient} 
    appearance={{{theme: ThemeSupa}}} 
    currentAccount={currentAccount}
/>

Account Pricing Plans

Shows a list of available pricing plans and allows user to select one

import { AccountPricingPlans } from '@usebasejump/account-ui-react';

const supabaseClient = useSupabaseClient();

<AccountPricingPlans 
    supabaseClient={supabaseClient} 
    appearance={{{theme: ThemeSupa}}} 
    currentAccount={currentAccount} // Optional field
    onPlanClick={(plan) => router.push(`/accounts/${currentAccount.id}/billing`)}
/>

Abstracting away the data model

Proposing that we clean up the public tables and move them into the basejump schema. Only editable tables would remain, such as profiles and a new table called account_settings. This would allow us to hide away the accounts/members/invitations functionality.

  • [x ] Move accounts, account_users, invitations, billing_subscriptions, billing_customers tables to basejump schema and out of public
  • Create account_settings table in public schema for changeable account information
  • [ x] All interactions with accounts would be through rpc functions with permissions
  • Migrate config table to key/value instead of single row

RPC / Edge Functions

Loading accounts for the current user

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('get_accounts');
[
  {
    "account_id": "00000000-0000-0000-0000-000000000000",
    "name": "My Account",
    "personal_account": true,
    "created_at": "2021-01-01T00:00:00.000000Z",
    "updated_at": "2021-01-01T00:00:00.000000Z",
    "role": "owner",
    "is_primary_owner": true
  },
  {
    "account_id": "00000000-0000-0000-0000-000000000000",
    "name": "My Team Account",
    "personal_account": false,
    "created_at": "2021-01-01T00:00:00.000000Z",
    "updated_at": "2021-01-01T00:00:00.000000Z",
    "role": "member",
    "is_primary_owner": false
  }
]

Loading a single account

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('get_account', { account_id: '00000000-0000-0000-0000-000000000000' });
{
    "account_id": "00000000-0000-0000-0000-000000000000",
    "name": "My Account",
    "personal_account": true,
    "created_at": "2021-01-01T00:00:00.000000Z",
    "updated_at": "2021-01-01T00:00:00.000000Z",
    "role": "owner",
    "is_primary_owner": true,
    "billing_status": "active",
    "members": [
        {
            "user_id": "00000000-0000-0000-0000-000000000000",
            "email": "[email protected]",
            "role": "owner",
            "is_primary_owner": true,
        }
    ],
    "invitations": [
        {
            "expiration": "2021-01-01T00:00:00.000000Z",
            "email": "[email protected]",
            "role": "owner"
        }
    ]
}

Creating an account

Create a new account. The current user will be automatically added as the primary account owner

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('create_account', { name: 'Account 2', slug: 'account-2' });
{
    "account_id": "00000000-0000-0000-0000-000000000000",
    "name": "Account 2",
    "personal_account": false,
    "created_at": "2021-01-01T00:00:00.000000Z",
    "updated_at": "2021-01-01T00:00:00.000000Z",
    "role": "owner",
    "billing_status": "active",
    "is_primary_owner": true,
    "members": [
        {
            "user_id": "00000000-0000-0000-0000-000000000000",
            "email": "[email protected]",
            "role": "owner",
            "is_primary_owner": true
        }
    ],
    "invitations": []
}

Invite account member

Invite a new member to an existing account.

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('invite_account_member', { email: '[email protected]', role: 'member' });
{
  "expiration": "2021-01-01T00:00:00.000000Z",
  "email": "[email protected]",
  "role": "member"
}

Accept an account invitation

Allows a user to accept an invitation by providing their invitation token.

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('accept_account_invitation', { token: '00000000-0000-0000-0000-000000000000' });
{
  "account_id": "00000000-0000-0000-0000-000000000000"
}

Update account member role

Allows an account owner to update the role of a member. If the current user is the primary owner, the owner can also transfer ownership to another member.

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .rpc('update_account_role', { user_id: '00000000-0000-0000-0000-000000000000', role: 'owner', make_primary_owner: true });
{
  "user_id": "00000000-0000-0000-0000-000000000000",
  "role": "owner",
  "is_primary_owner": true
}

Account billing status

Returns the current billing status of an account

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .functions.invoke('account_billing_status', { account_id: '00000000-0000-0000-0000-000000000000' });
{
  "subscription_id": "00000000-0000-0000-0000-000000000000",
  "subscription_active": true,
  "status": "active",
  "is_primary_owner": true,
  "billing_email": "[email protected]",
  "account_role": "owner",
  "billing_enabled": true
}

Available billing plans

Returns available billing plans

const supabaseClient = useSupabaseClient();

const { data, error } = await supabaseClient
  .functions.invoke('account_billing_plans', { account_id: '00000000-0000-0000-0000-000000000000' });
[
  {
    "product_name": "Monthly Basic",
    "product_description": "Our most basic plan",
    "currency": "usd",
    "price": 1900,
    "price_id": "price_00000000000000",
    "interval": "monthly",
    "active": true
  },
  {
    "product_name": "Monthly Premium",
    "product_description": "Our most premium plan",
    "currency": "usd",
    "price": 3900,
    "price_id": "price_00000000000001",
    "interval": "monthly",
    "active": false
  }
]

Any plans to check for billing status in RLS ?

Is there any plan to enable RLS at the billing level ?

E.g. Restrict row creation if billing status is not active ?

More generally, I was wondering how you handle restriction based on billing status ?

Ways to get account ID in API routes for teams or personal.

I'm trying to add in a value to a table that I made by generating a table with Basejump npx command. But I can't figure out how to populate the account ID part. Do I just have to keep passing down the value from the slug through the components?

00000000000000_dbdev_temp_install.sql fails to apply

I installed supabase v1.77.9 on windows, cloned the basejump repo and ran supabase start but getting this error:

Applying migration 00000000000000_dbdev_temp_install.sql...
ERROR: Resolving timed out after 1000 milliseconds (SQLSTATE XX000)
At statement 5: create extension "supabase-dbdev"

I tried removing that 00000000000000_dbdev_temp_install.sql file after reading some notes that perhaps dbdev already exists but get another error

Applying migration 00000000000001_utility_functions.sql...
ERROR: schema "dbdev" does not exist (SQLSTATE 3F000)                 
At statement 1: select dbdev.install('basejump-supabase_test_helpers')

Is there a version of superbase this no longer works with?

Invitation should have a reference to the invited user

It would be good if the basejump.invitations had a reference to the user who has been invited.

There are two reasons why this could be useful:

  1. With a constraint, it can prevent spamming of the user to join the same group
  2. As an account owner, it is then possible to see a list of users who have been invited. And, as an account owner, if I cannot see who I've invited, I'm likely to invite the again.

Create tests for various account support types

Paid plan with trial enabled

  • Personal accounts only
  • Team accounts only
  • Both personal and team accounts

Paid plan with trial disabled

  • Personal accounts only
  • Team accounts only
  • Both personal and team accounts

Free plan with trial enabled

  • Personal accounts only
  • Team accounts only
  • Both personal and team accounts

Paid plan with trial disabled

  • Personal accounts only
  • Team accounts only
  • Both personal and team accounts

Error running Stripe Sync command

Hello,

Running a local version, when attempting to sync strip products using yarn sync-stripe i get the following error:

Error: supabaseUrl is required.
at SupabaseClient (c:\Users\Bureau\Desktop\BF-Next\BFBJ\BF\node_modules@supabase\supabase-js\dist\main\SupabaseClient.js:55:19)
at createClient (c:\Users\Bureau\Desktop\BF-Next\BFBJ\BF\node_modules@supabase\supabase-js\dist\main\index.js:35:12)
at (c:\Users\Bureau\Desktop\BF-Next\BFBJ\BF\src\utils\admin\supabase-admin-client.ts:4:30)
at Object. (c:\Users\Bureau\Desktop\BF-Next\BFBJ\BF\src\utils\admin\supabase-admin-client.ts:7:1)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Object.F (C:\Users\Bureau\AppData\Local\npm-cache_npx\fd45a72a545557e9\node_modules@esbuild-kit\cjs-loader\dist\index.js:1:941)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Module.require (node:internal/modules/cjs/loader:1143:19)
at require (node:internal/modules/cjs/helpers:121:18)

Migrate from Legacy to Latest !

We are currently building BaseJump legacy for our app. We find it incredibly limiting and it seems a lot of stuff have been upgraded.
Please share steps on how to upgrade to latest version from Legacy.

Recommended way to get account_id throughout project?

Hey all, thanks for building this library! I'm currently doing something like this:

  • User signs up with some provider (Google for example)
  • We create a team account for that user using the RPC 'create_account' since personal accounts are disabled
  • Access the account_id throughout other components that need it?

I'm stuck on step 3 right now. I'm currently debating on creating a bespoke provider to pass this account_id where needed to other client components in my application, but wasn't sure if there was a better way to do this. I'm essentially creating an app that has projects (folders) and documents that are owned by each project. Each project should be owned by only one account and each user should only be able to belong to one team account. Would appreciate any guidance on how to move forward!

Cannot run db reset on remote database

Running supabase db reset --linked fails with this error:

ERROR: cannot drop schema basejump because extension basejump-basejump_core requires it (SQLSTATE 2BP01)
At statement 0: DROP SCHEMA IF EXISTS basejump CASCADE                                                  
Try rerunning the command with --debug to troubleshoot the error.

`new row violates row-level security policy for table "accounts"`

Hi,

I've just found the project and started playing around with it. Let me walk through my process of how I got here:

  1. I span up a local supabase as recommended, and signed up, created my team, etc
  2. I then set up and pushed to my live supabase to test a deployment however the migration completed, it doesn't bring across the user data, just the tables. I thought no big deal, I'll just sign up again
  3. I signed up again, but when I go to add a team name I get the error listed in the title.

pg_tests GitHub action failing with "ERROR: function pgtle.install_extension_version_sql does not exist"

Hello!

I am running a fresh copy of basejump, trying to get Github Actions working for a full CI/CD flow.

Currently I am experiencing this error with the pg_tests Supabase start command:

Starting database...
Starting containers...
Setting up Edge Functions runtime...
Setting up local schema...
Applying migration 00000000000000_dbdev_temp_install.sql...
Error: ERROR: function pgtle.install_extension_version_sql(text, text, text) does not exist (SQLSTATE 42883)
At statement 7: drop extension if exists "supabase-dbdev"
Try rerunning the command with --debug to troubleshoot the error.
Error: Process completed with exit code 1.

It seems there is a function (pgtle.install_extension_version_sql) that doesn't exist.

One thing worth noting, my local supabase CLI is v1.88.0, whereas it looks like this action is hardcoded to an older 1.5 version. Going to try and upgrade the action to see if that helps, but figure I would ask here too.

Webhook doesnt exist even though its in documentation?

When I run this edge function, I get a 404 error.
Screenshot 2024-03-27 at 9 39 59 PM
These are the only Supabase edge function there are. Is this a mistake in the docs?

const {data, error} = await supabase.functions.invoke('current_user_account_role', {
    body: {
        action: "get_plans",
        args: {
            account_id: "uuid"
        }
    }
});
 FunctionsHttpError {
    name: 'FunctionsHttpError',
    context: Response {
      type: 'basic',
      url: 'http://localhost:54321/functions/v1/current_user_account_role',
      redirected: false,
      status: 404,
      ok: false,
      statusText: 'Not Found',

Add STRIPE_WEBHOOK_SECRET to sample env

STRIPE_SECRET_KEY=generated-by-stripe

Struggled to figure out while my web hooks were failing but noticed that it was due to not having the STRIPE_WEBHOOK_SECRET env set which isn't mention in the docs or referenced in the sample .env. Perhaps it makes since to add it.

How can I integrate Basejump in an existing DB

Hello, thank you for this incredible work!!

I have a question, I am currently developing a web app where all the data from my various Supabase tables is linked to a user through a user_id that is found in almost all the tables.

I don't manage a team system yet, but I need to integrate one, which is why Basejump could save me a lot of time.

My question is, is it possible to create a Basejump account for each existing user so they can create teams?

I'm not sure if I should completely change everything, gradually integrate the Basejump system into my current database, or start from scratch (which would be a huge job).

If you could give me some advice, I would be very grateful.

Also, I would love to help develop features if there is a roadmap or something planned, I'm willing to help!

By the way, I've read in other issues that we're waiting on a blocking issue from Dbdev for version 2.1.0. Any updates on that?

Small documentation update

I'm looking into how to Default users into a free plan. The docs for setting up stripe (https://usebasejump.com/docs/billing-stripe) suggest that this setting is in the basejump.config table but that table only has these columns:
image

The docs later link to an environment variables page that returns a 404 (https://usebasejump.com/docs/environment-variables). The .env file does have a var for STRIPE_DEFAULT_TRIAL_DAYS. I'm guessing I could hack this default into a free plan by setting STRIPE_DEFAULT_TRIAL_DAYS to 0 and setting the STRIPE_DEFAULT_PLAN_ID to a free plan?

Either way some details on how to do that would be useful.

I would probably also change this:
Endpoint URL: https://<your-instance>.com/billing-webhooks

To:
Endpoint URL: https://<yourSupabaseProjRef>.supabase.co/functions/v1/billing-webhooks

Also, with my wsl setup, when I run supabase link, I get the warning:
Failed to save database password: Keyring is not supported on WSL

And as a result, I have to supply --project-ref flags for each of these commands to make the edge functions deploy correctly:
supabase secrets set --project-ref myrefid STRIPE_API_KEY=sk_test_mykey
supabase functions deploy --project-ref myrefid billing-webhooks --no-verify-jwt

Finally, I've tried clearing my npm cache with npm cache clean --force and still, when I run:
npx @usebasejump/cli@latest init

It puts an index.ts file in supabase/functions/billing-functions that has this line in it:
import {billingFunctionsWrapper, stripeFunctionHandler} from "https://deno.land/x/[email protected]/billing-functions/mod.ts";

Which isn't the latest version of basejump and doesn't deploy correctly. The current main branch of this repo uses:
import {billingFunctionsWrapper, stripeFunctionHandler} from "../deno-packages/billing-functions/mod.ts";

Apologies for the lack of organization here or standard process. I'm a finance bro trying to hack together a web app and haven't gotten around to learning git/github yet so this is the best I could do for now!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.