github
何はなくとも github です。db.bkiban リポジトリをつくりましたので clone してみました
Personal access tokens (2025/4/1)
- GitHubにログイン
- 右上の自分のアカウントアイコンをクリック
- Setttings
- Developper settings
- Personal access tokens > Tokens (classic)
- Generate new token > Generate new token (classic)
- Note: repo_20250401
- Expiration: 90 days
- Select scopes: repo > Generate token
% git clone https://github.com/unrcom/db.bkiban.git
Cloning into 'db.bkiban'...
Username for 'https://github.com': xxxxxx <- Username
Password for 'https://xxxxxx@github.com': <- Personal access token
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (3/3), done.
% ls
apache-tomcat-9.0.98 db.bkiban sirokuro-dev7 termlog openjdk proc supa-edgy unrwebpagemui
% cd db.bkiban
% ls
README.md
% cat README.md
# db.bkiban%
%
このページのコードで github の README.md を更新しておきます
% git branch
* main
% git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
% git add README.md
% git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
% git commit -m "1st commit"
[main 7220d44] 1st commit
1 file changed, 51 insertions(+), 1 deletion(-)
% git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
% git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 1.06 KiB | 1.06 MiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/unrcom/db.bkiban.git
bb36280..7220d44 main -> main
%
github.com 側も更新されて、いい感じになりました
今日はここまで。また明日がんばります
アーキテクチャ
さて github のおうちができたところで Day1 は終了しました。Day2 ではゴリゴリ開発環境をつくっていこうと思っていたのですが、過去メールを整理していたら気になる記事のリンクがありました。
AWS におけるマルチテナント SaaS の実装パターン ~ サーバーレス編
なんというタイムリーな記事なんでしょう。さっそく内容を確認してみました。
理解できたこと (記事からの引用)
- SaaS とはビジネスモデルです。運用の効率性を高め、俊敏性を獲得し、ビジネスのスケールを図るための手段として、SaaS というデリバリーモデルがここ数年で急速にその地位を確立してきました
- 技術的な観点から SaaS を特徴づける要素の最たるものが、いわゆる「コントロールプレーン」と呼ばれる存在です。SaaS では、新しく「テナント」という概念が登場します。複数のテナントが同じシステムを利用するため、それらの管理・運用を効率的に行うメカニズムが必要になります。このコントロールプレーンに含まれる機能は、
- オンボーディング
- テナント管理
- アイデンティティ管理
- メータリング
- 請求
- 階層化 (契約するプランなどに応じてテナントを複数の階層 (tier) に分け、異なる価値や体験を提供する SaaS の構築モデルのこと)
- Amazon ECS SaaS リファレンスアーキテクチャ には3つの構成要素がある
- Web アプリケーション
- コントロールプレーン (SBT: SaaS Contool Plane)
- アプリケーションプレーン
この図は単なるポンチ絵にあらずでして git clone https://github.com/aws-samples/saas-reference-architecture-ecs.git
して、特定のシェルスクリプトを実行すると、実際に動作する環境が自分の aws アカウントにつくれてしまいます (SaaS Builder Toolkit ワークショップ に入門するのが近道思われます)
理解できないこと
- このアイコンはなに?
aws のドキュメントは素晴らしいのですが壮大すぎて、こちらの手が止まってしまいます。いつもの試行錯誤に戻って開発環境を用意したいと思います
Web アプリケーション (2025/4/2)
いつもの Node.js + React + Vercel で進めてみようと思います。しかしながら以前開発環境を構築したのは3年以上前だったと思います。React公式 によると現在では create-react-app は使わないとのこと。Googleで「React 開発環境」で検索すると、さまざまな解説ページや記事がヒットしますが、その多くが create-react-app を使っていますので注意が必要です
現在の状態確認
% git --version
git version 2.39.5 (Apple Git-154)
% python3 -V
Python 3.9.6
% clang --version
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: arm64-apple-darwin24.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
% make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
% brew -v
Homebrew 4.4.14
% docker version
Client:
Version: 28.0.1
API version: 1.48
Go version: go1.23.6
Git commit: 068a01e
Built: Wed Feb 26 10:38:16 2025
OS/Arch: darwin/arm64
Context: desktop-linux
Server: Docker Desktop 4.39.0 (184744)
Engine:
Version: 28.0.1
API version: 1.48 (minimum version 1.24)
Go version: go1.23.6
Git commit: bbd0a17
Built: Wed Feb 26 10:40:57 2025
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.7.25
GitCommit: bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
runc:
Version: 1.2.4
GitCommit: v1.2.4-0-g6c52b3f
docker-init:
Version: 0.19.0
GitCommit: de40ad0
%
docker network
% docker network ls
NETWORK ID NAME DRIVER SCOPE
c58f288835dd bknet bridge local
6456db5f094c bridge bridge local
17961720e0a5 dumynet bridge local
777b5a0c38b0 host host local
c92a78ea45f6 java_default bridge local
4671f838fd33 none null local
4fa724a5e3f3 sknet bridge local
a88795c525db supabase_network_supa-edgy bridge local
%
db.bkiban.com のネットワークなので bknet を使っていきます
docker-compose.yml
% pwd
/Users/m/Dev/db.bkiban/webapp
% ls
docker-compose.yml
% cat docker-compose.yml
version: '3'
services:
sk:
image: node:latest
container_name: 'dbuser'
hostname: 'dbuser'
ports:
- '3000:3000'
stdin_open: true
tty: true
working_dir: '/var/www/html'
volumes:
- ./src:/var/www/html
networks:
- bknet
networks:
bknet:
external: true
%
コンテナ起動
長らく docker-compose up で起動していましたが、docker compose の現バージョンでは docker composd up です
% docker compose up
WARN[0000] /Users/m/Dev/db.bkiban/webapp/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] Running 9/9
✔ sk Pulled 30.2s
✔ 545aa82ec479 Pull complete 8.2s
✔ 4378a6c11dea Pull complete 8.6s
✔ 140d15be2fea Pull complete 10.5s
✔ 1d9d474cce08 Pull complete 23.2s
✔ ca40eb2cc73f Pull complete 23.2s
✔ 151918725530 Pull complete 25.0s
✔ 88780de10938 Pull complete 25.0s
✔ a5366786ea25 Pull complete 25.0s
[+] Running 1/1
✔ Container dbuser Created 0.8s
Attaching to dbuser
dbuser | Welcome to Node.js v23.11.0.
dbuser | Type ".help" for more information.
v View in Docker Desktop o View Config w Enable Watch
コンテナ状態確認
コンテナが起動したようなので状態確認します
% docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce545654df58 node:latest "docker-entrypoint.s…" 27 seconds ago Up 26 seconds 0.0.0.0:3000->3000/tcp dbuser
%
React インストール
コンテナに接続して Next.js (App Router) をインストールしていきます
% docker container exec -it dbuser /bin/bash
root@dbuser:/var/www/html# pwd
/var/www/html
root@dbuser:/var/www/html# ls
root@dbuser:/var/www/html# npx create-next-app@latest
Need to install the following packages:
create-next-app@15.2.4
Ok to proceed? (y) y
✔ What is your project named? … my-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Turbopack for `next dev`? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
Creating a new Next.js app in /var/www/html/my-app.
Using npm.
Initializing project with template: app-tw
Installing dependencies:
- react
- react-dom
- next
Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- @tailwindcss/postcss
- tailwindcss
added 48 packages, and audited 49 packages in 14s
10 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Success! Created my-app at /var/www/html/my-app
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.2.0
npm notice To update run: npm install -g npm@11.2.0
npm notice
root@dbuser:/var/www/html#
React Router (v7)
root@dbuser:/var/www/html# npx create-react-router@latest
Need to install the following packages:
create-react-router@7.4.1
Ok to proceed? (y) y
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
create-react-router v7.4.1
dir Where should we create your new project?
/my-app
◼ Using default template See https://github.com/remix-run/react-router-templates for more
✔ Template copied
git Initialize a new git repository?
No
deps Install dependencies with npm?
Yes
✔ Dependencies installed
done That's it!
Enter your project directory using cd ./../../../my-app
Check out README.md for development and deploy instructions.
Join the community at https://rmx.as/discord
root@dbuser:/var/www/html#
ローカル (開発) サーバの起動
どうやって開発サーバを起動するのでしょうか。公式ページには記載がなく、昔の記憶を頼りに package.json のなかを見ながら起動してみます
root@dbuser:/var/www/html# ls
my-app
root@dbuser:/var/www/html# cd my-app/
root@dbuser:/var/www/html/my-app# ls
README.md app next-env.d.ts next.config.ts node_modules package-lock.json package.json postcss.config.mjs public tsconfig.json
root@dbuser:/var/www/html/my-app# cat package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.2.4"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4"
}
}
root@dbuser:/var/www/html/my-app# npm run dev
> my-app@0.1.0 dev
> next dev --turbopack
▲ Next.js 15.2.4 (Turbopack)
- Local: http://localhost:3000
- Network: http://172.19.0.2:3000
✓ Starting...
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry
✓ Ready in 1145ms
○ Compiling / ...
✓ Compiled / in 2.6s
GET / 200 in 2808ms
✓ Compiled /favicon.ico in 426ms
GET /favicon.ico?favicon.45db1c09.ico 200 in 486ms
ブラウザから localhost:3000 に接続してみます
デプロイ
Vercel にデプロイしてみます
- ここまでのコードを github に push
- Vercel にログイン
- [Add new Project]
- プロジェクト名: db-bkiban > [Build it]
- インポートする Git リポジトリの [import] をクリック
- Framework Preset に Next.js を選択
- Root Directory の [Edit] をクリック > V マークが表示されるフォルダを指定する > デプロイ
花びらというか紙吹雪が舞わなくなりましたね
プラウザから接続してみます
今日はここまでにして、また明日、がんばります
AWS 請求アラート
本題とは関係がないのですが、2025年3月の AWS の請求が思いのほか高額になりまして、サービスごとに確認してみました。結果は CloudWatch の東京リージョンでの利用料が多くなっておりましてメトリクスを確認したところ身に覚えのないメトリクスが大量に登録されていました。DynamoDB に関するものが多く、DynamoDB 自体はほぼ無料で使えたのにメトリクスで課金されるという、あるあるなのでしょうか? 気をつけたいと思います
db.bkiban でも AWS のサービス利用を予定していますので、今のうちに請求アラートを設定しておこうと思います
- AWS コンソールの検索で「Billing and Cost Management」
- 左側のハンバーガーメニューから「請求設定」
こんな感じに設定
- AWS コンソールの検索で「CloudWatch」
- リージョンが「米国東部 (バージニア北部)」であることを確認
- [アラーム] > [すべてのアラーム]
- [アラームの作成]
- [メトリクスの選択]
- [Billing]
- [概算合計請求額]
- 「USD」の左側のチェックを入れて > [メトリクスの選択]
- 「...よりも」にアラームをとばす閾値を入力 > [次へ]
- [新しいトピックの作成]
- トピック名 と メールアドレス を入力して [トピックの作成]
アラートがくるのが楽しみです
認証
では Web アプリケーション に認証機能を実装していこうと思います。認証は AWS Cognito を使ってみようと思っていまして、よくある メールアドレス + パスワード による認証を行います。ここで一つ工夫したいことがありまして、「お試しユーザ」は認証なしで使えるようしたくて、この機能を Firebase の「匿名認証」で実現しようと思っています
AWS Cognito 部分は以下のようにつくっていこうと思っています
CloudFront を間にいれるべき、とは思いますが、とりあえずは必要最低限で構成します
Firebase 側は、Web アプリケーションから Firebase API を直接呼び出します
ちょっと寄り道
Web アプリケーション に認証機能を組み込む際に使用する Web ページ をつくっていたら、だいぶ時間を使ってしまいました
Vercel社から訴えられそうなデザインですが、Powered by して公開すれば許してもらえそうな気がしています
今日 (2025/4/3) はここまでにして、また明日、頑張ります
Firebase
Authentication
Firebase アカウントは持っているので Firebase コンソールにログインし、プロジェクトを作成しました。匿名認証機能を有効にするには、作成したプロジェクトで
- [Authentication]
- [ログイン方法] タブをクリック
- [匿名]
- 「有効にする」のスイッチをオン > [保存]
アプリの登録
続いて「Firebase にアプリを追加する」ということをするようです。プロジェクトの最初の画面から
- [>] (マウスをホバーすると「ウェブ」と表示)
- アプリのニックネームを入力
- ホスティング設定のチェックを外す
- [アプリを登録]
ここまで進めると firebaseConfig の設定値が表示されますのでメモします
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "...",
authDomain: "bkiban.firebaseapp.com",
projectId: "bkiban",
storageBucket: "bkiban.firebasestorage.app",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
匿名ログイン機能の実装
以降は Firebase ドキュメント従って設定と実装を進めます
- Firebase を JavaScript プロジェクトに追加する
- JavaScript を使用して Firebase 匿名認証を行う
- Firebase apiKey ってさらしていいの? ほんとに?
- [Next.js]Event handlers cannot be passed to Client Component propsエラー
なんとか匿名ログインについては実装が完了しました。3年前に開発した react のコードを見ながら実装を進めていたのですが next.js はかなり違う実装が必要でして、いろんな方の技術解説やブロブに助けていただきました
匿名認証が終わると、Firebase コンソールではこんな感じで認証情報が確認できます
プログラム側では以下の情報が取得できていました
今日はここまでにして、また明日頑張ります
Firebase Auth のアップグレード
Firebase公式のドキュメントを眺めていたところ Firebase Auth のアップグレードが無料で行えることを知りました
そもそもですが Firebase には無料で使える Spark プランと従量課金の Blaze プランがあります。以前ですが DBアクセス回数が (プログラムバグで) 無料枠を超えてしまい、サービスが止まってしまったことがありました。Spark プランだと米国西海岸時間の 0 時からまた利用が可能になります。Blaze プランの場合はお金の力で動き続けますが、これはこれで怖い気もします
話を戻しますが Firebase Auth は Identity Platform と連携する Firebase Auth にアップグレードできます。このアップグレードは無料プランでも利用可能で、アップグレードすると以下の機能が利用できるようになります (私にとって有用なものの抜粋です)
- 匿名アカウントの自動クリーンアップ
- ユーザアクティビティのモニタリングとロギング
- 多要素認証
- マルチテナンシー
匿名アカウントの自動クリーンアップは、この機能を有効にすると 30 日以上経過した匿名アカウントは自動で削除されます。またこの機能を有効にした場合は匿名認証が使用量上限または請求の対象から除外されるため、イタズラされても安心、ということになります
マルチテナンシーはプールモデルの SaaS にとってはありがたい機能でして、先日 Firebase Auth のクライアント側のユーザデータを確認した際に tenantId なる項目があって、これはどうやって使うんだろうと思っていたのですが、マルチテナンシーで利用可能になるようです
アップグレードすることの懸念もありまして、プロバイダー認証 (Google認証などを使うアレですね) の1日の利用回数が、アップグレードしない場合は無制限に使えるのですが、アップグレード後は 3000回に制限されます。有料プランに移行すればまた無制限になるのですが、ちょっと気になります
まあ db.kiban はそこまで成功することはないでしょうから Firebase Auth のアップグレードを行なって、匿名アカウントの自動クリーンアップを行えるようにしました (この設定は元に戻せないという警告が最後に表示されます)
匿名アカウントを永久アカウントに変換する
匿名アカウントは 30 日で削除されますので利用を継続されるユーザ向けに永久アカウントへの移行機能を提供したいと思います
メールリンクによる認証ができそうです。メールアドレスとパスワードによる認証が通常だとは思いますが、自分がユーザの場合パスワードってやっかいですよね。使い回しはしたくないし、パスワードポリシーがサイトやアプリで異なるのも手間がかかる要因になります。私は Povo のユーザなのですが、ここの Web サイトはメールリンク認証のみとなっていて、これはこれで使いやすいです。ではさっそく実装してみます
と、ここまで書いていてなんですが、メールリンクは 2025/8/25 に仕様が変わる可能性があることがわかりました。実装はこれ以降で行うこととし、現時点ではおとなしくアイパス認証を実装することにしました
2025/4/3 から 4/8 にかけて Firebase の Authentication を用いて認証機能を実装していました。結果、以下の認証フローを実現できました
- Signed in (認証済み) か Signed out (承認済みでない) が判定する
- 匿名認証 (ID やプロバイダ認証が不要のお試しユーザ向け認証)
- ID (メールアドレス) + (パスワード) 認証
- Google (プロバイダ) 認証
- 匿名認証ユーザから ID または Google認証ユーザへの移行
Supabase
ここまで Firebase で認証機能をつくってしまったのですが、先ほど Supabase に匿名認証機能が追加されていることを知りました