はじめに
個人開発で育てている Chainlit 製チャットアプリ「AgentApp」を、ポートフォリオとして外部公開できるレベルまで仕上げるために作業したログをまとめます。
今回は ユーザー登録〜認証/DB永続化/Herokuデプロイ/CI設定 までを一気に整備しました。
✅ ゴール
- ログイン・チャット・履歴がクラウドでも正常動作
- 誰でも新規登録可能(メール+パスワード)
- Heroku に一発デプロイ、GitHub Actions で CI が走る
プロジェクト構成と主なファイル
AgentApp/ ├── app.py # Chainlit アプリの本体 ├── auth/ # 認証関連モジュール ├── data_layer.py # DB永続化の拡張 ├── public/ # 静的ファイル(CSS/JS/登録ページなど) ├── schema_chainlit.sql # PostgreSQL用スキーマ ├── Procfile # Heroku Dyno 起動コマンド ├── runtime.txt # Heroku の Python バージョン指定 ├── requirements.txt # 依存ライブラリ └── .github/workflows/ci.yml# GitHub Actions (CI)
Chainlit の標準 UI をベースに、ログイン画面や履歴表示を調整しています。
ローカル環境での準備
1. 認証コールバックの改修
auth/email.py にメール+パスワード認証の処理を実装。未登録の場合はその場でユーザー作成まで完了するようにし、Clainlit の User テーブルと AppUser テーブルを同期します。
ポイント:
- normalize_email() でメールを正規化
- bcrypt でパスワードハッシュ化(最低8文字)
- create_app_user() で新規作成→Chainlit 側のユーザーも永続化
python
async def authenticate_email_password(username: str, password: str, data_layer: AppDataLayer) -> Optional[User]: email = normalize_email(username) if not email or not password: return None await data_layer.connect() async with data_layer.pool.acquire() as connection: row = await connection.fetchrow('SELECT ... FROM "AppUser" WHERE email = $1', email) if not row: if not is_password_valid(password): return None row = await create_app_user(connection, email=email, password=password) if not bcrypt.checkpw(password.encode(), row["password_hash"].encode()): return None user = User(identifier=row["email"], display_name=row["display_name"], metadata={"app_user_id": str(row["id"])}) await data_layer.create_user(user) return user
2. DB 永続化レイヤー
チャット履歴を PostgreSQL に保存するため、Chainlit のデータレイヤーを拡張 (data_layer.py)。JSONB カラムへの保存時に変換・復元を挟むことで、UI でも違和感なく表示できます。
3. ユーザー登録用のシンプルなページ
public/register.html と public/custom.js を追加し、ログインフォームから「新規登録はこちら」→/public/register.html への導線を表示。Chainlit 本体は認証必須 (requireLogin = true) のままですが、公開ディレクトリの静的ページで登録フォームを提供する形にしました。
Heroku デプロイ準備
1. 依存ライブラリの整理
requirements.txt に xai-sdk を漏れなく追加。Heroku で起動後に ModuleNotFoundError が発生し、慌てて修正しました。
Version:
chainlit>=2.6.0,<3.0.0 openai>=1.40.0 ... asyncpg>=0.29.0 xai-sdk>=0.1.20
2. Procfile と runtime.txt
Heroku dyno で Chainlit を起動するため、リポジトリ直下にファイルを追加。
# Procfile web: chainlit run app.py --host 0.0.0.0 --port $PORT # runtime.txt python-3.12.4
3. Config Vars の整理
Heroku ダッシュボードの Settings > Reveal Config Vars で以下を登録:
- CHAINLIT_AUTH_SECRET (chainlit create-secret で生成)
- OPENAI_API_KEY, GOOGLE_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY
- PostgreSQL アドオン追加後、自動生成された DATABASE_URL
.env に引用符付きで書いていた値は Heroku ではそのまま(引用符なし)で設定すれば OK。
Heroku デプロイ手順(GitHub 連携例)
- heroku login で CLI 認証
- heroku git:remote -a <app-name>
- Git 管理:bash
git checkout -b feature/heroku-setup # 変更をステージしてコミット git add Procfile runtime.txt requirements.txt ... git commit -m "Add Heroku deployment setup and CI workflow" git push origin feature/heroku-setup
- GitHub のリポジトリを Heroku Deploy タブで Connect → 対象ブランチを手動 Deploy
(自動デプロイをオンにすることも可能)
PostgreSQL スキーマの適用
bash
heroku pg:psql -a <app-name> < schema_chainlit.sql
これで AppUser, Thread, Step など Chainlit で使うテーブルが Heroku DB に作成されます。
CI(GitHub Actions)の導入
.github/workflows/ci.yml を追加し、push / PR 時に最低限の構文チェックが走るようにしました。
yaml
name: CI on: push: branches: ["main", "feature/**"] pull_request: branches: ["main"] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: { python-version: "3.12" } - run: pip install -r requirements.txt - run: python -m py_compile app.py data_layer.py auth/email.py
後で pytest や e2e テストを追加しやすいように、まずは構文エラー検出に絞っています。
デプロイ後のトラブルシューティング
- ModuleNotFoundError: No module named ‘xai_sdk’
→ requirements.txt に漏れがあり、Heroku で失敗。追加して再デプロイ。 - ログイン画面のロゴを消したい
試行錯誤したものの、Chainlit のバージョン差異でクラス名が変わるため一旦ロールバック。今後は CSS の適用範囲をもう少し調査して削除予定。 - DATABASE_URL の形式
Heroku Postgres は postgres:// で配布されるので、アプリ内で postgresql:// に置換するヘルパー関数を実装。ローカルでも DATABASE_URL を .env に入れておくと後でテストしやすい。
現在の状態と今後
- ローカル/本番ともにログイン → チャット履歴 → 複数ユーザー管理が動作。履歴は PostgreSQL に永続化され、Chainlit の UI で閲覧できます。
- Heroku デプロイもワンクリックで可能。Config Vars を整えれば別環境にも比較的簡単に展開できる。
- CI が入ったことで、今後の機能追加やバグ修正も安全に進めやすくなりました。
今後強化したいこと:
- ログイン画面のブランド調整(ロゴ削除や独自UI)
- テスト(pytest)や Lint(ruff/mypy)の導入
- 監視・アラート体制(Heroku メトリクス、Sentryなど)
参考リンク
- Chainlit Docs
- Chainlit Cookbook – custom-frontend サンプル
- Heroku CLI デプロイ公式ドキュメント
- asyncpg – PostgreSQL driver
- bcrypt for Python パッケージ
以上、Chainlit アプリを Heroku で公開するまでの道のりでした。どなたかの参考になれば幸いです。