読後感で本を選ぶ、エンジニア・知的好奇心層向けの電子書籍ストア。
「泣ける」「知性が磨かれる」今の気分にぴったりの一冊を AI が提案する。
コアコンセプト
01 · 読後感ベクトル推薦
書籍のあらすじを OCI Generative AI(Cohere embed-multilingual-v3.0) で 1024 次元のベクトルに変換。「泣ける」「高揚感」「深い洞察」などの気分プリセットとの Cosine Similarity で上位 10 件をリアルタイム推薦する。プリセットは管理画面から追加・編集が可能。
02 · Kubernetes ゼロ運用
Container Instances + OCI Functions のサーバーレス構成でインフラ管理を最小化。PDF 抽出バッチは常駐 Worker(Container Instances)、Embedding 生成はイベント駆動の OCI Functions と用途別に使い分けることで、コスト効率と応答速度を両立する。
03 · PDF URL 完全隠蔽(BFF パターン)
Object Storage の Pre-signed URL(有効期限 5 分)は BFF 内部でのみ使用し、フロントエンドに一切露出しない。全 PDF はブラウザの PDF ビューア経由でストリーム配信し、ダウンロードを抑制する。
04 · Auth0 で認証をゼロ実装
Google / GitHub SSO・MFA・不審ログイン検知(Anomaly Detection)を Auth0 に完全委譲。JWKS 検証は MicahParks/keyfunc で RSA 公開鍵パースと自動更新を行う。アプリはコア機能の開発に集中できる設計判断。
アーキテクチャー全体図
技術スタック
| 層 | 技術 | 備考 |
|---|---|---|
| Database | OCI Autonomous DB 23ai | ECPU ベース・自動スケール・プライベートエンドポイント |
| AI / Embedding | OCI Generative AI | Cohere embed-multilingual-v3.0(日本語対応) |
| Vector Search | HNSW Index + COSINE |
VECTOR_DISTANCE() で上位 10 件を高速取得 |
| Backend API | Go + Gin | Instance Principal 認証・Graceful Shutdown |
| Frontend / BFF | Next.js 14 | App Router / Server Components / ISR(60s) |
| PDF Worker | Node.js + pdf-lib | 先頭 10 ページ抽出・ウォーターマーク付与 |
| Auth | Auth0 | SSO(Google / GitHub)/ MFA / Anomaly Detection |
| Payment | Stripe Checkout | Webhook 署名検証・冪等処理 |
| Storage | OCI Object Storage | PDF / プレビュー / 書影(3 バケット) |
| Gateway | OCI API Gateway | レートリミット・JWT 検証 |
| IaC | Terraform | Container Instances / Functions / API Gateway |
書籍登録から推薦までの流れ
1. 管理者が PDF をアップロード
POST /admin/books → Object Storage に保存 → DB に PENDING レコード作成
2. Worker が先頭 10 ページを自動抽出
Container Instances 内の常駐 Worker が FOR UPDATE SKIP LOCKED で検知
pdf-lib でプレビュー PDF を生成しウォーターマーク付与 → preview バケットへ保存
3. OCI Functions が Embedding を生成
あらすじを Cohere embed-multilingual-v3.0 で 1024 次元ベクトルに変換
Books.experience_vector に UPDATE
4. ユーザーが気分を選んで推薦を受け取る
MoodPresets のプリセットベクトルと VECTOR_DISTANCE(COSINE) で上位 10 件を返す
Next.js ISR でキャッシュ済みのため高速レスポンス
セキュリティ設計
| 対象 | 設計 |
|---|---|
| PDF 配信 | Pre-signed URL をフロントに露出しない。BFF が Object Storage からストリームして Content-Disposition: inline で返す |
| Stripe Webhook |
stripe-signature ヘッダを必ず検証。stripe_session_id の UNIQUE 制約で二重処理を防ぐ |
| JWT 検証 | API Gateway と Go API の二段階で検証。keyfunc が JWKS を自動更新し kid ローテーションに追従 |
| DB アクセス | Autonomous DB はプライベートエンドポイント + mTLS 接続のみ許可 |
| Object Storage | PDF / Preview バケットは NoPublicAccess。書影バケットのみ公開読み取り |
ディレクトリ構成
contextual-bookshelf-oci/
├── apps/
│ ├── api/ # Go + Gin バックエンド API
│ ├── bff/ # Next.js 14 BFF(App Router)
│ └── worker/ # Node.js PDF Worker(pdf-lib)
└── infra/
├── terraform/ # OCI インフラ定義(10 ファイル)
└── scripts/ # deploy.sh / init_db.sh / rotate_secrets.sh
クイックスタート
# 1. 変数ファイルの準備
cd infra/terraform
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars を編集(OCI 認証情報・Auth0・Stripe を設定)
# 2. 機密情報を環境変数で設定
export TF_VAR_adb_admin_password='your-strong-password'
export TF_VAR_stripe_webhook_secret='whsec_xxxxx'
export OCI_TENANCY_NAMESPACE='your-namespace'
export OCI_COMPARTMENT_OCID='ocid1.compartment.oc1..xxxxx'
export OCI_REGION='ap-tokyo-1'
# 3. インフラ構築
terraform init && terraform apply
# 4. DB スキーマ初期化
./infra/scripts/init_db.sh
# 5. 全サービスをビルド・デプロイ
./infra/scripts/deploy.sh
インフラ概要
| リソース | 仕様 |
|---|---|
| Region | ap-tokyo-1 |
| Container Instances | 2 OCPU / 4 GB RAM(BFF / API / Worker 各 1 台) |
| Autonomous DB | ECPU ベース・自動スケール / 1 TB |
| OCI Functions | Embedding バッチ(256 MB / 120 s タイムアウト) |
| API Gateway | Public エンドポイント / JWT 検証 / レートリミット |
このプロジェクトは OCI のサーバーレス・AI ネイティブ構成の実験を兼ねている。
認証(Auth0)・決済(Stripe)・AI(OCI GenAI)をすべて外部サービスに委譲し、
アプリケーション層はコア機能である「読後感推薦」の実装に集中する設計判断を行った。
