現状
なんとなくユーザー認証機能から作り始めてしまいまして、だいたい、こんな機能が実装できました
db.kiban の認証に関する仕様
- Firebase の匿名認証でお試し利用ができる
- ID + パスワード または Google認証で永久ログインユーザーを設定できる
- 匿名認証ユーザーは永久ログインユーザーに移行できる
ここまでは Firebase Authentication を利用して実装を進めていたのですが、Firebase を使いたい理由は「匿名認証」を使ってみたかったという点にありました。ID と パスワードの登録って面倒だし、素性もしれないサイトでそんなことしたくない、と誰もがお考えになることだと思います。匿名認証ができれば、気軽に利用いただけるかな、と考えました
Vercel にデプロイ済みで公開も可能なのですが、公開するには少々手直ししたい部分もありまして、こちらは今のところ非公開といたします
2025/4/8 に知ったこと
しかしつい先ほど Supabase で匿名認証が使えるということを知りました
匿名認証は Firebase にしかない機能と思い込んでいたのでかなり驚きました
db.bkiban のデータベースとして Supabase Database (PostgreSQL) を利用する想定でしたので、認証も Supabase Auth で行けるのであれば一気に開発が進みそうです
Firebase は老舗の BaaS であり、その認証機能はとても洗練されていました。日本語ドキュメントも完備されていて、公式ページの手順で迷わず実装できました。一方 Supabase はドキュメントの大半が英語という点と、Firebase と比べるとだいぶマイナー (失礼な言い方で申し訳ありませんが日本語の技術情報が少ないという意味です) なので、その点では開発スピードがマイナスされてしまいそうです
Supabase はまだ公式ドキュメントを眺めた程度の理解なのですが、Firebase で自動で行われる機能が Supabase では手動で実行 (SQL投入!) するなど洗練されていない部分がありました。逆に言うと Firebase を使っている限りブラックボックスだった機能が Supabase では確認SQLや更新SQLを実行するといった「自分が何をしているかわかる」と言う意味ではデメリットばかりでもなさそうです
私は Firebase の課金モデルが好きではないので、そういった面でも Supabase です。Supabase さんチャレンジさせてください! どうぞよろしく!
という訳で 2025/4/1 から 4/7 にやったことは以下の限定共有ページに移動して、改めて開発の記録をはじめたいと思います
github
何はなくとも github です。2つのリポジトリを使っていこうと思います
- db.bkiban.web (next.js Webブラウザアプリ)
- db.bkiban.func (Supabase Edge functions Rest API)
アーキテクチャ
さて github のおうちができたところで アーキテクチャ の検討です
こちらを参照していましたが詳しくは Firebase で 匿名認証 を実装する にあります
Web アプリケーション
ローカル開発環境の構築手順と Vercel へデプロイする部分もFirebase で 匿名認証 を実装する にあります
db.kiban の主な機能 (ログインしていない場合)
- 公開設定された DB定義 の一覧表示 (カテゴリごとに表示する)
- DB定義 のテーブルごとの詳細表示
- 公開設定された DB のデータ照会
- 公開設定された DB に対するコメント機能
db.kiban の主な機能 (ログインしている場合)
ログインしていない場合の機能に加えて、以下の機能を提供する
- DB定義
- DBへのデータ投入、メンテナンス
- DBデータのファイル出力とダウンロード
- DB公開
まずはログインしていない状態で利用可能な機能を実装していきたいと思います (2025/4/1 から 4/7 に行なった開発と逆の順序で進めます)
データモデル
こんなデータモデルを考えてみました
tables
Name | Type | Default Value | Primary | Memo |
---|---|---|---|---|
id | uuid | gen_random_uuid() | On | |
created_at | timestampz | now() | Off | |
updated_at | timestampz | Off | 注記1 | |
user_id | uuid | Off | auth.users.id | |
name | varchar | Off | ||
description | varchar | NULL | Off | NULL許可 |
is_public | bool | false | Off | |
public_at | timestamp | Off | ||
num_users | int8 | 0 | Off | |
num_cols | int8 | 0 | Off |
注記1: moddatetime という Extension で設定できそう
rows
Name | Type | Default Value | Primary | Memo |
---|---|---|---|---|
table_id | uuid | On | tables.id | |
id | int8 | Is Identity (注記2) | On | |
created_at | timestampz | now() | Off | |
updated_at | timestampz | Off | 注記1 | |
name | varchar | Off | ||
description | varchar | NULL | Off | NULL許可 |
is_public | bool | false | Off | |
is_valid | bool | true | Off |
注記2: 列に連続した一意の番号を自動的に割り当てます
cols
Name | Type | Default Value | Primary | Memo |
---|---|---|---|---|
table_id | uuid | On | tables.id | |
id | int8 | Is Identity (注記2) | On | |
rows_id | int8 | On | rows.id | |
created_at | timestampz | now() | Off | |
updated_at | timestampz | Off | 注記1 | |
value | varchar | Off | ||
is_public | bool | false | Off | |
is_valid | bool | true | Off |
データ型はテキストのみですが、これで表現できそうな気がしています
Supabase
create table
慣れるまではできるだけ Supabase コンソールからアクセスした方が無難だと思い Table Editor を使ってみたのですが、エラーが出まくってしまい、ものすごいストレスを感じたので SQL で定義しました
create table public.tables (
id uuid not null default gen_random_uuid(),
created_at timestamp with time zone not null default now(),
updated_at timestamp with time zone not null default now(),
user_id uuid not null ,
name varchar(128) not null ,
description varchar(2048),
is_public boolean not null default false,
public_at timestamp with time zone,
num_users int8 not null default 0,
num_cols int8 not null default 0,
constraint tables_pkey primary key (id)
) tablespace pg_default;
psql が今のところ使えませんので SQL でテーブル定義を確認してみました
確認用 SQL
select
isc.table_name
, isc.ordinal_position
, isc.column_name
, isc.data_type
, isc.character_maximum_length
, isc.column_default
, isc.is_nullable
from
information_schema.columns isc
where
isc.table_schema = 'public' /* ここは可変 */
and isc.table_name = 'tables' /* ここも可変 */
order by isc.ordinal_position;
実行結果
[
{
"table_name": "tables",
"ordinal_position": 1,
"column_name": "id",
"data_type": "uuid",
"character_maximum_length": null,
"column_default": "gen_random_uuid()",
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 2,
"column_name": "created_at",
"data_type": "timestamp with time zone",
"character_maximum_length": null,
"column_default": "now()",
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 3,
"column_name": "updated_at",
"data_type": "timestamp with time zone",
"character_maximum_length": null,
"column_default": "now()",
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 4,
"column_name": "user_id",
"data_type": "uuid",
"character_maximum_length": null,
"column_default": null,
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 5,
"column_name": "name",
"data_type": "character varying",
"character_maximum_length": 128,
"column_default": null,
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 6,
"column_name": "description",
"data_type": "character varying",
"character_maximum_length": 2048,
"column_default": null,
"is_nullable": "YES"
},
{
"table_name": "tables",
"ordinal_position": 7,
"column_name": "is_public",
"data_type": "boolean",
"character_maximum_length": null,
"column_default": "false",
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 8,
"column_name": "public_at",
"data_type": "timestamp with time zone",
"character_maximum_length": null,
"column_default": null,
"is_nullable": "YES"
},
{
"table_name": "tables",
"ordinal_position": 9,
"column_name": "num_users",
"data_type": "bigint",
"character_maximum_length": null,
"column_default": "0",
"is_nullable": "NO"
},
{
"table_name": "tables",
"ordinal_position": 10,
"column_name": "num_cols",
"data_type": "bigint",
"character_maximum_length": null,
"column_default": "0",
"is_nullable": "NO"
}
]
問題ないようです。Supabase コンソールから Table Editor で確認してみましたが、こちらもダイジョウブそうでした
updated_at は更新の都度更新したい (おかしな日本語な) のですが以下の手順で設定できました
こちらの記事には postgres のトリガーを Supabase GUI からトリガーを登録する手順と SQL で登録する手順が記載されていましたが、GUI からはうまく登録できず、SQL による登録を行いました
Edge Functions からのデータアクセス
こんな機能が必要になると思っています
- addTable
- getTables
- getTable
- modTable
- delTable
- isPublicTable
rows と cols についても概ね同じ構成の Rest API を用意していきたいと思います
Rest API は Supabase Edge Functions で実装しようと思っています。当初は aws Lambda function を使うつもりでしたが、以下の検討、設定、実装が必要となり、課金の対象にもなるため最初の段階では Supabase Edge Functions に丸投げしてみます
- エンドポイント (API Gateway)
- エンドポイントでの認証 (API Gateway authorizer)
- 認証基盤 (Cognito)
- 認証情報管理機能 (Rest API による)
- データベースアクセス機能API (Lambda function)
- Supabase Database へのアクセス情報管理 (Secrets Manager)
Supabase ローカル環境
データベースと連携する Edge Functions の開発を進めていきたいのですが、サーバサイドで開発する情報は見つかりませんでした。Supabase CLI というローカルの Supabase 開発環境で開発し、Cloud の Edge サーバに Deploy する手順はいくつか見つかりましたのでこれで進めてみようとしています
このページがローカルPC に Supabase 開発環境をつくる手順を示す公式ページです
ローカル開発環境が起動するとローカルの Supabase にアクセスできます
- ローカル Supabase の停止
supabase stop
- ローカル Supabase の起動
supabase start
supabase start ローカルの Supabase を起動すると以下の Key が表示されます
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: eyJhbGciOiJI......Tn_I0
service_role key: eyJhbGciOiJI......N81IU
S3 Access Key: 625729a08b95......a23c
S3 Secret Key: 850181e4652d......25907
S3 Region: local
Local で Hello World
いろいろと調べてみたのですが、公式ページ以外の情報は古くて使える手順はほぼありませんでした。英語なのでちょっと大変ですが公式ページと公式からの動画を頼りに進めていきます
以下のページの手順に従うとローカル環境で Hello World できました
Developing Edge Functions locally
% pwd
/Users/m/Dev/supabase
%
% supabase init
Generate VS Code settings for Deno? [y/N] y
Generated VS Code settings in .vscode/settings.json. Please install the recommended extension!
Finished supabase init.
/Users/m/Dev/supabase
%
% ls -la
total 0
drwxr-xr-x 4 m staff 128 4 9 21:33 .
drwxr-xr-x@ 8 m staff 256 4 9 21:28 ..
drwxr-xr-x@ 4 m staff 128 4 9 21:33 .vscode
drwxr-xr-x@ 5 m staff 160 4 9 21:33 supabase
%
hello function をつくります
% pwd
/Users/m/Dev/supabase
% supabase functions new hello
Created new Function at supabase/functions/hello
%
supabase フォルダの下に functions フォルダができ、その下に hello フォルダがつくられます。そのなかにいくつかファイルが生成されており index.ts を編集していきます
実行してみます
% curl --request POST 'http://localhost:54321/functions/v1/hello' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsIn......' \
--header 'Content-Type: application/json' \
--data '{ "name":"Functions" }'
{"message":"Hello Functions!"}%
%
Cloud で Hello World
以下のページに従います
% supabase login
Using workdir /Users/m/Dev/supabase
Hello from Supabase! Press Enter to open browser and login automatically.
Here is your login link in case browser did not open https://supabase.com/dashboard/cli/login?session_id=12c6714d-db0b-4939-be0f-dd4eff5882f5&token_name=cli_m@mopnoMac-mini.local_1744247012&public_key=0434e8adec......
Enter your verification code: edaa0e1d
Token cli_m@mopnoMac-mini.local_1744247012 created successfully.
You are now logged in. Happy coding!
% supabase projects list
Using workdir /Users/m/Dev/supabase
Cannot find project ref. Have you run supabase link?
LINKED | ORG ID | REFERENCE ID | NAME | REGION | CREATED AT (UTC)
--------|----------------------|----------------------|------------|------------------------|---------------------
| sflwwkgnxfcjqphbllcx | wpxn................ | bkiban_dev | Northeast Asia (Tokyo) | 2024-05-06 05:38:35
| sflwwkgnxfcjqphbllcx | jkon................ | db.bkibam | Northeast Asia (Tokyo) | 2025-04-07 22:08:11
%
% supabase link --project-ref jkon......
(snip)
% supabase functions deploy hello
(snip)
%
% curl --request POST 'https://jkon.......supabase.co/functions/v1/hello' \
--header 'Authorization: Bearer eyJhbG......' \
--header 'Content-Type: application/json' \
--data '{ "name":"Functions" }'
{"message":"Hello Functions!"}%
%
% curl --request POST 'https://jkon.......supabase.co/functions/v1/hello' \
--header 'Authorization: Bearer eyJhbG......' \
--header 'Content-Type: application/json' \
--data '{ "name":"db.bkiban!" }'
{"message":"Hello db.bkiban!!"}%
%
Edge Functions で CRUD
ここからはデータベースアクセス機能を提供する Rest API の開発を進めてみます
このコードがサンプルになりそうです