Skip to content

Commit

Permalink
V2 (#52)
Browse files Browse the repository at this point in the history
Major changes : 
* Supabase JS SDK V2 😇
* Folder structure
  * Previous module's mutations/queries are now in a `service.server` (collocate all the module's service in one place)
* Auth session is reworked to align with folder structure changes
* `requireAuthSession` no longer call Supabase Auth API by default to verify user access token (it's still safe, we signed our cookie)
  * `requireAuthSession` takes a new optional param called `verify` (boolean) to work as before 😉
* No more needing to start a shadow database to create a Prisma migration (I don't know why maybe it's thanks to Supabase). It results in a huge time saving!
  • Loading branch information
rphlmr authored Oct 23, 2022
1 parent 032a98e commit 6502e6d
Show file tree
Hide file tree
Showing 91 changed files with 937 additions and 1,963 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/build
/public/build
*.config*
/test/
74 changes: 74 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"plugins": ["tailwindcss"],
"extends": [
"@remix-run/eslint-config",
"@remix-run/eslint-config/node",
"plugin:tailwindcss/recommended",
"prettier"
],
"parserOptions": {
"project": ["./tsconfig.json"]
},
"settings": {
// Help eslint-plugin-tailwindcss to parse Tailwind classes outside of className
"tailwindcss": {
"callees": ["tw"]
},
"jest": {
"version": 27
}
},
"rules": {
"no-console": "warn",
"arrow-body-style": ["warn", "as-needed"],
// @typescript-eslint
"@typescript-eslint/no-duplicate-imports": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"vars": "all",
"args": "all",
"argsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"ignoreRestSiblings": false
}
],
//import
"import/no-cycle": "error",
"import/no-unresolved": "error",
"import/no-default-export": "warn",
"import/order": [
"error",
{
"groups": ["builtin", "external", "internal"],
"pathGroups": [
{
"pattern": "react",
"group": "external",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["react"],
"newlines-between": "always",
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}
]
},
"overrides": [
{
"files": [
"./app/root.tsx",
"./app/entry.client.tsx",
"./app/entry.server.tsx",
"./app/routes/**/*.tsx"
],
"rules": {
"import/no-default-export": "off"
}
}
]
}
110 changes: 0 additions & 110 deletions .eslintrc.js

This file was deleted.

12 changes: 6 additions & 6 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -41,7 +41,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -64,7 +64,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -87,7 +87,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand Down Expand Up @@ -137,7 +137,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand Down Expand Up @@ -198,7 +198,7 @@ jobs:

steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/for-this-stack-repo-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -41,7 +41,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -64,7 +64,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand All @@ -88,7 +88,7 @@ jobs:
needs: [lint, typecheck, vitest]
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
uses: styfle/cancel-workflow-action@0.11.0

- name: ⬇️ Checkout repo
uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pnpm-lock.yml

node_modules

/.cache
/build
/public/build
.env
Expand Down
51 changes: 16 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ npx create-remix --template rphlmr/supa-fly-stack
- [Fly app deployment](https://fly.io) with [Docker](https://www.docker.com/products/docker-desktop/)
- Production-ready [Supabase Database](https://supabase.com/)
- Healthcheck endpoint for [Fly backups region fallbacks](https://fly.io/docs/reference/configuration/#services-http_checks)
- [GitHub Actions](https://github.com/features/actions) for deploy on merge to production and staging environments
- Email/Password Authentication with [cookie-based sessions](https://remix.run/docs/en/v1/api/remix#createcookiesessionstorage)
- **NEW** : Magic Link login 🥳
- [GitHub Actions](https://github.com/features/actions) to deploy on merge to production and staging environments
- Email/Password Authentication / Magic Link, with [cookie-based sessions](https://remix.run/docs/en/v1/api/remix#createcookiesessionstorage)
- Database ORM with [Prisma](https://prisma.io)
- Forms Schema (client and server sides !) validation with [Remix Params Helper](https://github.com/kiliman/remix-params-helper)
- Styling with [Tailwind](https://tailwindcss.com/)
Expand All @@ -32,7 +31,7 @@ Not a fan of bits of the stack? Fork it, change it, and use `npx create-remix --

## Development

- Create a [Supabase Database](https://supabase.com/) (Free tiers gives you 2 databases)
- Create a [Supabase Database](https://supabase.com/) (free tier gives you 2 databases)

> **Note:** Only one for playing around with Supabase or 2 for `staging` and `production`
Expand Down Expand Up @@ -84,7 +83,7 @@ The database seed script creates a new user with some data you can use to get st

### Relevant code:

This is a pretty simple note-taking app, but it's a good example of how you can build a full stack app with Prisma, Supabase and Remix. The main functionality is creating users, logging in and out (handling access and refresh tokens + refresh on expire), and creating and deleting notes.
This is a pretty simple note-taking app, but it's a good example of how you can build a full-stack app with Prisma, Supabase, and Remix. The main functionality is creating users, logging in and out (handling access and refresh tokens + refresh on expiration), and creating and deleting notes.

- auth / session [./app/modules/auth](./app/modules/auth)
- creating, and deleting notes [./app/modules/note](./app/modules/note)
Expand Down Expand Up @@ -197,7 +196,7 @@ For lower level tests of utilities and individual components, we use `vitest`. W

### Type Checking

This project uses TypeScript. It's recommended to get TypeScript set up for your editor to get a really great in-editor experience with type checking and auto-complete. To run type checking across the whole project, run `npm run typecheck`.
This project uses TypeScript. It's recommended to get TypeScript set up for your editor to get a great in-editor experience with type checking and auto-complete. To run type checking across the whole project, run `npm run typecheck`.

### Linting

Expand All @@ -209,48 +208,30 @@ We use [Prettier](https://prettier.io/) for auto-formatting in this project. It'

## Start working with Supabase

Your are now ready to go further, congrats !

To extend your prisma schema and apply changes on your supabase database :

- Download and run [Docker Desktop](https://www.docker.com/products/docker-desktop/)

> **Note:** Needed to create a [shadow database for prisma](https://www.prisma.io/docs/concepts/components/prisma-migrate/shadow-database)
> **Note:** Shadow database is local and run by `docker-compose.yml`
You are now ready to go further, congrats!

To extend your Prisma schema and apply changes on your supabase database :
- Make your changes in [./app/database/schema.prisma](./app/database/schema.prisma)
- Prepare your schema migration

> **Note:** First time take a long moment 😅
```sh
npm run db:prepare-migration
```

- Check your migration in [./app/database/migrations](./app/database/migrations)
- Apply this migration in production
- Check your migration in [./app/database/migrations](./app/database)
- Apply this migration to production

```sh
npm run db:deploy-migration
```

## Use with Supabase RLS

> To test this stack with RLS, you can find a demo in [./app/routes/rls](./app/routes/rls)
> **Before playing, add some RLS rules for "Note" table**
| Policy name | Target roles | WITH CHECK expression |
| ---------------------------------- | :-----------: | -------------------------: |
| Creator can see their own notes | authenticated | ((uid())::text = "userId") |
| Authenticated user can add notes | authenticated | true |
| Creator can delete their own posts | authenticated | ((uid())::text = "userId") |
## If your token expires in less than 1 hour (3600 seconds in Supabase Dashboard)

> Then, go to [http://localhost:3000/rls/notes](http://localhost:3000/rls/notes)
If you have a lower token lifetime than me (1 hour), you should take a look at `REFRESH_ACCESS_TOKEN_THRESHOLD` in [./app/modules/auth/session.server.ts](./app/modules/auth/session.server.ts) and set what you think is the best value for your use case.

## Your token expires in less than 1 hour (3600 seconds in Supabase Dashboard)
## Supabase RLS
You may ask "can I use RLS with Remix".

If you have a lower token lifetime than me (1 hour), you should take a look at `REFRESH_THRESHOLD` in [./app/modules/auth/const.ts](./app/modules/auth/const.ts) and set what you think is the best value for your use case.
The answer is "Yes" but It has a cost.

Using Supabase SDK server side to query your database (for those using RLS features) adds an extra delay due to calling a Gotrue rest API instead of directly calling the Postgres database (and this is fine because at first Supabase SDK is for those who don't have/want backend).

In my benchmark, it makes my pages twice slower. (~+200ms compared to a direct query with Prisma)
Loading

0 comments on commit 6502e6d

Please sign in to comment.