LoginSignup
1
1

Supabase専用端末を作ったときの備忘録

Posted at

以前使っていたノートPCを掘り起こし、Supabase専用端末化してみたときの備忘録です。

※画像やコンソール出力をぺたぺた貼ってたらすごい縦に長くなってしまったので、見出し以下について<details></details>で折りたたんでみました。

環境情報

PC1(Supabase用)

詳細
項目 内容
PC ThinkPad X1 Carbon (2018モデル)
OS Windows10 Home ⇒ Windows11 Home (23H2)
CPU i7-8550U
メモリ 16GB
Docker Engine 26.0.0
Docker Desktop 4.29.0
docker compose v2.26.1-desktop.1
scoop v0.4.1
  • 2018年頃に購入したPCです
  • wsl2、Ubuntu22.04導入済み(今回は使わなかった)
  • scoop導入済み
  • 今回の作業を行う前にWindows11にアップデート、Docker(wsl)は再インストール、scoopは最新にアップデートしました

PC2(アプリケーション開発用)

詳細
項目 内容
PC HP Spectre x360
OS Windows11 Pro
CPU i7-1165G7
メモリ 16GB
Docker Engine 25.0.3
Docker Desktop 4.28.0
docker compose v2.24.6-desktop.1
Node.js v20.13.1
npm 10.5.2
  • 2022年頃に購入したPCです
  • wsl2、Ubuntu20.04導入済み
  • wsl2にNode.jsを直インストール済み
nodejsインストール
$ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
$ sudo apt-get install -y nodejs

その他

詳細
項目 内容
無線LANルーター Aterm WG2600HP4
サブネットマスク 255.255.255.0
デフォルトゲートウェイ 192.168.10.1
  • 後の作業内容としてSupabase用PCのIPアドレスの固定化を行うので関係してそうな箇所を記載しました

セットアップ

以後、見出しにPC1と書いているものはSupabase用PCでの作業内容、PC2と書いているものはアプリケーション開発用PCでの作業内容となります

scoop から supabase CLI をインストール (PC1)

詳細

Windows用の supabase CLIをインストールします

cmd(管理者)
> scoop bucket add supabase https://github.com/supabase/scoop-bucket.git
> scoop install supabase
> scoop list
Installed apps:

Name     Version Source Updated             Info
----     ------- ------ -------             ----
7zip     23.01   main   2024-05-12 14:12:00
hadolint 2.10.0  main   2022-08-11 19:25:59
supabase 1.165.0 main   2024-05-12 14:12:01
  • supabase CLIについて1.165.0というバージョンがインストールできました
  • supabaseのインストールと併せて7zipがインストールされました(たぶん)
  • hadolintは今回の記事の内容とは一切関係ありません
  • ちなみに管理者として起動したコマンドプロンプトにて実行しました(不要かも)

supabaseのローカル環境起動 (PC1)

詳細
cmd
> cd /D C:\workspace_supabase
> mkdir example-app-backend
> cd example-app-backend
> supabase init
Generate VS Code settings for Deno? [y/N] N
Generate IntelliJ Settings for Deno? [y/N] N
Finished supabase init.

> dir supabase /S /B
C:\workspace_supabase\example-app-backend\supabase\config.toml
C:\workspace_supabase\example-app-backend\supabase\seed.sql
  • 今回はC:\workspace_supabase\example-app-backendディレクトリ内にsupabaseのプロジェクトの作成を行いました
  • supabase initコマンドを実行したディレクトリ内に1フォルダ、2ファイルが生成されました

続けてstartコマンドを実行

cmd
> supabase start
15.1.1.41: Pulling from supabase/postgres
17d0386c2fff: Pull complete
ec8061954605: Pull complete
e54d94900333: Pull complete

~~~省略~~~

Seeding data supabase\seed.sql...
2.8.1: Pulling from supabase/kong
213ec9aee27d: Already exists

~~~省略~~~

Started supabase local development setup.

         API URL: http://127.0.0.1:54321
     GraphQL URL: http://127.0.0.1:54321/graphql/v1
  S3 Storage URL: http://127.0.0.1:54321/storage/v1/s3
          DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
      Studio URL: http://127.0.0.1:54323
    Inbucket URL: http://127.0.0.1:54324
      JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
        anon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
   S3 Access Key: 625729a08b95bf1b7ff351a663f3a23c
   S3 Secret Key: 850181e4652dd023b7a98c58ae0d2d34bd487ee0cc3254aed6eda37307425907
       S3 Region: local
  • 初回はstartコマンド実行時にコンテナを起動するためのイメージのプルが行われるため数分掛かりました
  • startコマンド実行時にコンソールに表示される各種情報はアプリケーション開発の際、外からsupabaseに接続するのに必要となります
    • supabaseのローカルの情報はsupabase statusコマンドから再度確認できるみたいなので控えておかなくても大丈夫かも?

起動したコンテナについて確認しました

cmd
> docker ps
CONTAINER ID   IMAGE                                             COMMAND                   CREATED         STATUS                   PORTS                                              NAMES
48087ba9578d   public.ecr.aws/supabase/studio:20240422-5cf8f30   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:54323->3000/tcp                            supabase_studio_example-app-backend
dfd206489b0b   public.ecr.aws/supabase/postgres-meta:v0.80.0     "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   8080/tcp                                           supabase_pg_meta_example-app-backend
d0b516eb993a   public.ecr.aws/supabase/edge-runtime:v1.45.2      "sh -c 'mkdir -p /ho…"   2 minutes ago   Up 2 minutes             8081/tcp                                           supabase_edge_runtime_example-app-backend
5ded325e82a4   public.ecr.aws/supabase/imgproxy:v3.8.0           "imgproxy"                2 minutes ago   Up 2 minutes (healthy)   8080/tcp                                           supabase_imgproxy_example-app-backend
fdec91fa0e1d   public.ecr.aws/supabase/storage-api:v1.0.6        "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   5000/tcp                                           supabase_storage_example-app-backend
9eeca099c0be   public.ecr.aws/supabase/postgrest:v12.0.1         "/bin/postgrest"          2 minutes ago   Up 2 minutes             3000/tcp                                           supabase_rest_example-app-backend
711583b04956   public.ecr.aws/supabase/realtime:v2.28.32         "/usr/bin/tini -s -g…"   2 minutes ago   Up 2 minutes (healthy)   4000/tcp                                           supabase_realtime_example-app-backend
f30fe6d1f89d   public.ecr.aws/supabase/inbucket:3.0.3            "/start-inbucket.sh …"   2 minutes ago   Up 2 minutes (healthy)   1100/tcp, 2500/tcp, 0.0.0.0:54324->9000/tcp        supabase_inbucket_example-app-backend
966eb30b1803   public.ecr.aws/supabase/gotrue:v2.149.0           "auth"                    2 minutes ago   Up 2 minutes (healthy)   9999/tcp                                           supabase_auth_example-app-backend
cf1802ff839a   public.ecr.aws/supabase/kong:2.8.1                "sh -c 'cat <<'EOF' …"   2 minutes ago   Up 2 minutes (healthy)   8001/tcp, 8443-8444/tcp, 0.0.0.0:54321->8000/tcp   supabase_kong_example-app-backend
20c7522df8ba   public.ecr.aws/supabase/postgres:15.1.1.41        "sh -c 'cat <<'EOF' …"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:54322->5432/tcp                            supabase_db_example-app-backend

ちなみにSupabaseのDocker環境は以下のコマンドから停止できます

cmd
> supabase stop
Stopped supabase local development setup.
Local data are backed up to docker volume. Use docker to show them: docker volume ls --filter label=com.supabase.cli.project=example-app-backend
  • 環境を丸ごと削除したいときは--no-backupオプションをつけて実行することでボリュームを含むコンテナ環境の破棄ができます

IPアドレスを固定化 (PC1)

詳細

接続される側のローカルIPアドレスが変わってしまうと手間なのでおおよそ以下の手順で固定化しました。

ipconfigで自動割り当て中の設定を確認

cmd
> ipconfig
Wireless LAN adapter Wi-Fi:
~~~省略~~~
   IPv4 アドレス . . . . . . . . . . . .: 192.168.10.104
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 192.168.10.1 

設定 > ネットワークとインターネット > Wi-Fi > [Wi-FiのSSID名] と進み IP割り当ての「編集」をクリック

image.png

自動⇒手動に切り替え、IPv4のスイッチをオンに切り替える。
その後、事前に確認した内容を元に設定

image.png

image.png

今回の私の環境では以下のような設定となりました

項目 内容
IPv4 オン
IPアドレス 192.168.10.104
サブネットマスク 255.255.255.0
ゲートウェイ 192.168.10.1
優先DNS 192.168.10.1
HTTPS経由のDNS オフ
IPv6 オフ

接続確認 (PC2)

詳細

ブラウザでSupabaseのStudioにアクセスしダッシュボードが表示されることを確認

image.png

  • 具体的には http://192.168.10.104:54323/ にアクセスします
    • PC1側でsupabase startの完了時に表示されていたStudio URLを基に、IPアドレス部分(127.0.0.1)をPC1のローカルIP(192.168.10.104)に書き換えています

Inbucketというローカル環境用の仮想メールサーバーのGUIにアクセスできることを確認

image.png

  • 具体的には http://192.168.10.104:54324/ にアクセスします
    • PC1側でsupabase startの完了時に表示されていたInbucket URLを基に、IPアドレス部分(127.0.0.1)をPC1のローカルIP(192.168.10.104)に書き換えています

続けてSQLクライアントソフト(今回はA5M2)で接続できることを確認します
こちらもsupabase startの完了時に表示されていたDB URLの情報を分解し、IPアドレス部分だけ書き換えることで接続できました

image.png

image.png

デモアプリ開発 (PC1,PC2)

  • 今回は認証とサインアップとアプリ固有のテーブルを作る辺りが問題なく行えることを確認します
  • 具体的にはNuxt3を使用したTODOリストを管理するアプリケーションを作成します

TODOリスト情報を管理するtasksテーブルを作成 (PC2)

詳細

StudioのTable Editor画面を開き Create a new tableボタンをクリック

image.png

右から出てくるサイドバーでtasksテーブルの情報を入力

image.png

  • Enable Row Level Securityはチェックを入れておく(デフォルトでチェックされてるかも)

同サイドバー内でカラム情報を入力

image.png

カラム名 デフォルト 備考
id int8 null PrimaryIs Identityにチェック入れる
title text null Is Nullableにチェック入れる
completed bool false (NOT NULL)
user uuid auth.uid() ※1 (NOT NULL)
created_at timestamptz now() (NOT NULL)

※1 auth.uid()はauthスキーマのusersテーブルから認証中のユーザーIDを取得するというSupabaseが用意する関数です


外部キーの情報は特に入力せずに、Saveボタンをクリック

image.png


tasksテーブルの作成が行えました

image.png


tasksテーブル横の「...」よりView Policiesをクリック

image.png


tasksテーブルに対して「RLSが有効化されているがポリシーが存在しない」というメッセージが表示されています

image.png


RLSは↑のポリシーの一覧画面からCreate a new policyボタンをクリックした先のGUIでも作成できますが、今回はSQL Editorの画面でクエリをペーストしての設定を行います。サイドバーからSQL Editorページに遷移

image.png

image.png


以下のクエリをクエリ欄にペーストし、Runボタンをクリック

tasksテーブルのRLSポリシー
create policy "Individuals can create tasks." on tasks for
    insert with check (auth.uid() = user);
create policy "Individuals can view their own tasks. " on tasks for
    select using ((select auth.uid()) = user);
create policy "Individuals can update their own tasks." on tasks for
    update using ((select auth.uid()) = user);
create policy "Individuals can delete their own tasks." on tasks for
    delete using ((select auth.uid()) = user);

image.png

image.png

  • エラーっぽいトーストメッセージが表示されいますが、クエリ自体は正しく実行できてそうなログが出ました
  • ちなみに↑のクエリはINSERT、DELETE、UPDATE、SELECTのそれぞれについて認証中のユーザーの自身に紐づく情報のみ操作(登録、削除、更新、取得)可能とするRLSです

tasksテーブルのポリシーを確認するページに戻るとINSERT、DELETE、UPDATE、SELECTのそれぞれについてRLSが設定されていることが確認できます

image.png


A5M2の方からもpublicスキーマ内にtasksテーブルの存在を確認

image.png

Supabaseのダンプを取得 (PC1)

詳細

supabace CLIのdb dumpコマンドを使用して↑の手順で作成したtasksテーブルに関する定義を含むダンプを取得

cmd
> supabase db dump --local --file supabase/seed.sql
Dumping schemas from local database...
Dumped schema to supabase/seed.sql.

image.png

image.png

image.png

  • PC2側でブラウザを経由して作成したtasksテーブルに関する情報を含むダンプが取得できることを確認できました

Nuxt3のアプリケーション作成1 (PC2)

  • Nuxt3の新規プロジェクトを作成しプロジェクト内で利用するモジュールを導入するとこまで実施します
詳細
wsl2
$ cd ~/
$ mkdir example-app-frontend && cd $_
$ npx nuxi@latest init .
$ npm install -D @nuxtjs/supabase supabase
$ npm install -D nuxt-primevue primeflex primeicons sass

package.jsonの中身は以下の通りとなりました

package.json
{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "dependencies": {
    "nuxt": "^3.11.2",
    "vue": "^3.4.27",
    "vue-router": "^4.3.2"
  },
  "devDependencies": {
    "@nuxtjs/supabase": "^1.2.2",
    "nuxt-primevue": "^0.3.1",
    "primeflex": "^3.3.1",
    "primeicons": "^7.0.0",
    "sass": "^1.77.1",
    "supabase": "^1.165.0"
  }
}

プロジェクトのルートに.envを作成

.env
SUPABASE_URL="http://192.168.10.104:54321"
SUPABASE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0"

インストールしたモジュールの設定をnuxt.config.tsに追加

nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
-  devtools: { enabled: true }
+  devtools: { enabled: true },
+
+  modules: [
+    '@nuxtjs/supabase',
+    'nuxt-primevue'
+  ],
+
+  supabase: {
+    redirectOptions: {
+      login: '/',
+      callback: '/confirm',
+    },
+  },
+
+  primevue: {
+    usePrimeVue: true,
+    components: {
+      include: '*',
+    },
+    directives: {
+      include: '*',
+    },
+    composables: {
+      include: '*',
+    },
+  },
+
+  css: [
+    'primevue/resources/themes/mira/theme.css',
+    'primeflex/primeflex.css',
+    'primeicons/primeicons.css',
+  ],
})
  • primevueに含まれるテーマCSS、primeflexとprimeiconsのcssも追加

Nuxt3の開発サーバーを起動

wsl2
$ npm run dev

> dev
> nuxt dev

Nuxt 3.11.2 with Nitro 2.9.6                                                                                                                                                       9:43:52 PM
                                                                                                                                                                                   9:43:53 PM
  ➜ Local:    http://localhost:3000/
  ➜ Network:  use --host to expose

  ➜ DevTools: press Shift + Alt + D in the browser (v1.3.1)                                                                                                                        9:43:54 PM

ℹ Vite client warmed up in 2702ms                                                                                                                                                 9:43:58 PM
ℹ Vite server warmed up in 3409ms                                                                                                                                                 9:43:59 PM
✔ Nuxt Nitro server built in 2281 ms                                                                                                                                        nitro 9:44:01 PM

ブラウザで http://localhost:3000/ にアクセス

image.png

  • Nuxt3のWelcomeページが見れることを確認
  • レイアウトが少し崩れてるのはPrimeVueのテーマCSSとかを読み込んでいることが関係しているかもしれません(このページは後の手順で消すので問題なし)

TypeScript用の型情報を生成 (PC2)

詳細

npmでインストールしたsupabase CLIのgen types typescriptコマンドよりTypeScript用の型情報を生成します

wsl2
$ mkdir types
$ npx supabase gen types typescript --db-url postgresql://postgres:postgres@192.168.10.104:54322/postgres > types/database.types
Connecting to 192.168.10.104 54322
v0.80.0: Pulling from supabase/postgres-meta

~~~省略~~~

Status: Downloaded newer image for public.ecr.aws/supabase/postgres-meta:v0.80.0
(node:1) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

image.png

  • tasksテーブルに関する情報を含む型情報が生成されました
  • --db-urlオプションにはPostgreSQLへの接続文字列を指定します
    • PC1側でsupabase startの完了時に表示されていたDB URLを基に、IPアドレス部分(127.0.0.1)をPC1のローカルIP(192.168.10.104)に書き換えています

(不要) TypeScript用の型情報をPC1側で生成 (PC1)

詳細
  • 最初はPC1側で--localオプション付きで以下のようなコマンドを実行して型情報を生成し、USBメモリ経由でPC2側にコピーという方法をとっていました。
cmd
> mkdir types
> supabase gen types typescript --local > types\database.types.ts
Connecting to db 5432
(node:1) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
  • 実際には TypeScript用の型情報を生成 (PC2) に記載した通り --db-url オプション付きで実行することでPC2側でgen types typescriptコマンドを実行できるため不要な手順であることがわかりました。

Nuxt3のアプリケーション開発2 (PC2)

  • 型情報の生成後の続きとして各画面の開発を実施します
詳細

app.vueを以下の通り書き換え

app.vue
<template>
-  <div>
-    <NuxtWelcome />
-  </div>
+  <ClientOnly>
+    <Toast />
+  </ClientOnly>
+  <Body class="m-0">
+    <div class="w-screen h-screen surface-ground">
+      <NuxtPage />
+    </div>
+  </Body>
</template>

ログイン画面を新規作成

pages/index.vue
<template>
  <div class="flex align-items-center justify-content-center h-full flex-wrap">
    <Card class="flex justify-content-center w-20rem">
      <template #title>
        <div class="text-center">
          <SelectButton
            v-model="state.authType"
            :allow-empty="false"
            :options="authTypes"
            :pt="{
              button: () => ({
                class: 'w-7rem p-button-sm'
              })
            }"
          />
        </div>
      </template>
      <template #content>
        <Password v-model="state.dummyPassword" class="hidden"/>

        <label class="block w-full">Email</label>
        <InputText v-model="state.email" />

        <label class="mt-2 block w-full">Password</label>
        <Password v-model="state.password" />
      </template>
      <template #footer>
        <Button
          :label="state.authType === 'login' ? 'Login' : 'Signup'"
          class="w-full"
          :disabled="!state.email || !state.password"
          @click="execLoginOrSignup"
        />
      </template>
    </Card>
  </div>
</template>

<script setup lang="ts">
const toast = useToast()

const state = reactive<{
  authType: 'login' | 'signup'
  email: string
  password: string
  dummyPassword: string
}>({
  authType: 'login',
  email: '',
  password: '',
  dummyPassword: ''
})

const authTypes = ['login', 'signup']

const user = useSupabaseUser()
const { auth } = useSupabaseClient()

const execLoginOrSignup = async () => {
  if (state.authType === 'login') {
    const { error } = await auth.signInWithPassword({
      email: state.email,
      password: state.password,
    })
    if (error) {
      toast.add({
        severity: 'error',
        summary: 'Login error',
        detail: error.message,
        life: 5000,
      })
    }
  } else {
    const { error } = await auth.signUp({
      email: state.email,
      password: state.password,
    })
    if (error) {
      toast.add({
        severity: 'error',
        summary: 'Signup error',
        detail: error.message,
        life: 5000,
      })
    }
  }
}

watchEffect(() => {
  if (user.value) {
    navigateTo('/tasks')
  }
})
</script>
  • nuxt.config.tssupabase.redirectOptions.loginで設定したログインページのパスと揃える必要があります

TODOリストの管理画面を作成

pages/tasks.vue
<template>
  <div class="flex align-items-center justify-content-center w-full py-4 flex-wrap">
    <Card class="flex justify-content-center w-30rem">
      <template #title>
        <div class="text-3xl">
          Todo List.
        </div>
      </template>
      <template #content>
        <div class="grid">
          <div class="col-12">
            <div class="grid align-items-center">
              <div class="col">
                <InputText v-model="state.newTask" class="w-full" />
              </div>
              <div class="col-fixed">
                <Button icon="pi pi-plus" label="Add" size="small" @click="addTask" />
              </div>
            </div>
          </div>
          <div class="col-12">
            <template v-if="tasks">
              <DataView :value="tasks" data-key="id">
                <template #list="slotProps">
                  <div class="grid grid-nogutter">
                    <div v-for="(task, index) in slotProps.items" :key="index" class="col-12">
                      <div class="grid">
                        <div class="col">
                          {{ task.title }}
                        </div>
                        <div class="col-fixed">
                          <div class="flex align-items-center justify-content-between flex-wrap">
                            <div class="flex mr-2">
                              <InputSwitch v-model="task.completed" @change="completeTask(task as Task)" />
                            </div>
                            <div class="flex">
                              <Button icon="pi pi-trash" severity="danger" size="small" @click="removeTask(task as Task)" />
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </template>
                <template #empty>
                  <div>
                    No tasks registered
                  </div>
                </template>
              </DataView>
            </template>
          </div>
        </div>
      </template>
    </Card>
  </div>
</template>

<script setup lang="ts">
import type { Database } from '~~/types/database.types'

interface Task {
  id: number
  title: string
  completed: boolean
  user?: string
  created_at?: string
}

const client = useSupabaseClient<Database>()
const user = useSupabaseUser()

const state = reactive({
  newTask: '',
  loading: false
})

const { data: tasks } = await useAsyncData('tasks', async () => {
  const { data } = await client.from('tasks').select('id, title, completed').eq('user', user.value!.id).order('created_at')

  return data
})

async function addTask() {
  if (state.newTask.trim().length === 0) return

  state.loading = true

  const { data } = await client.from('tasks')
    .upsert({
      user: user.value!.id,
      title: state.newTask,
      completed: false,
    })
    .select('id, title, completed')
    .single()

  tasks.value?.push(data!)
  state.newTask = ''
  state.loading = false
}

const completeTask = async (task: Task) => {
  await client.from('tasks').update({
    completed: task.completed,
  }).match({
    id: task.id,
  })
}

const removeTask = async (task: Task) => {
  tasks.value = tasks.value?.filter(t => t.id !== task.id) ?? []
  await client.from('tasks').delete().match({
    id: task.id,
  })
}
</script>
  • この画面はnuxt.config.tssupabase.redirectOptions.excludeで除外URLとして設定していないため認証が必須として扱われます
  • 認証を済ませていない状態でpages/tasks.vueに直アクセスした場合、モジュール内のルートミドルウェア処理によってsupabase.redirectOptions.loginで指定したパスに遷移します

デモアプリの動作確認 (PC2)

詳細

nuxt devで起動する開発用のサーバーが起動している状態で http://localhost:3000/ にアクセス

pages/index.vueのログイン&サインアップ画面が表示できることを確認

image.png


存在しないユーザーを入力しログインを試みた状態でSupabaseの認証結果としてエラーを受け取り、トーストメッセージとして表示できることを確認

image.png


サインアップを実行 (Emailにtestuser@example.com、Passwordにpassword)と入力

image.png


StudioのAuthentication > Users画面で登録したサインアップしたユーザーが存在することを確認

image.png


サインアップ成功後、ログイン&サインアップの画面コンポーネント内のwatchEffectの処理によりTODOリストの管理画面に遷移したことを確認

pages/index.vue (抜粋)
<script setup lang="ts">
const user = useSupabaseUser()

watchEffect(() => {
  if (user.value) {
    navigateTo('/tasks')
  }
})
</script>

image.png


TODOリストの管理画面で1件のタスクを登録できることを確認

image.png

image.png


StudioのTable Editor画面でtasksテーブルのデータとして登録した内容が閲覧できることを確認

image.png


TODOリストの管理画面で1件のタスクを更新できることを確認(スイッチをONにする)

image.png

image.png


TODOリストの管理画面で1件のタスクを削除できることを確認(ゴミ箱ボタンクリック)

image.png

image.png

Supabaseのバックアップを含まないプロジェクトの破棄 (PC1)

せっかくなので--no-backupを付けたstopコマンドを実行してみました

詳細
cmd
> supabase stop --no-backup
Stopped supabase local development setup.

ボリュームが空になっていることを確認

image.png

再度Supabaseのローカル環境立ち上げ (PC1)

バックアップ済みのsupabase/seed.sqlを元にtasksテーブルとtasksテーブルのRLSポリシーが作成されることを確認します

詳細
cmd
> supabase start
Seeding data supabase\seed.sql...
Started supabase local development setup.

         API URL: http://127.0.0.1:54321
     GraphQL URL: http://127.0.0.1:54321/graphql/v1
  S3 Storage URL: http://127.0.0.1:54321/storage/v1/s3
          DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
      Studio URL: http://127.0.0.1:54323
    Inbucket URL: http://127.0.0.1:54324
      JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
        anon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
   S3 Access Key: 625729a08b95bf1b7ff351a663f3a23c
   S3 Secret Key: 850181e4652dd023b7a98c58ae0d2d34bd487ee0cc3254aed6eda37307425907
       S3 Region: local

PC1側でブラウザからStudioのTable Editor画面にアクセス

image.png

  • tasksテーブルが出来上がっていることが確認できました

続けてRLSのポリシーを確認

image.png

image.png

  • INSERT、DELETE、UPDATE、SELECTのそれぞれのRLSポリシーについて以前の状態が復元できていることを確認できました

まとめ

詳細
  • SupabaseのDockerコンテナを利用したローカル環境の初歩的な部分について複数台のPCを使った環境でおおよそ問題なく使えることがわかりました。
  • 実際にアプリケーションの開発を進めていくうえで必要となるSupabase本番とのプロジェクトのリンクやマイグレーション周りの動作確認は行えていません。。

この記事の中で紹介しているSupabase側と開発したアプリケーションのコードはそれぞれ以下のリポジトリで公開しています。

https://github.com/imo-tikuwa/nuxt-supabase-example-app-backend

https://github.com/imo-tikuwa/nuxt-supabase-example-app-frontend

参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1