LinuxClub の毎日 Python コーディング練習サービス。
| レイヤー | 技術 |
|---|---|
| Frontend | Next.js 16 (App Router) / TypeScript / Tailwind CSS v4 |
| Backend | Go / Echo v5 |
| DB | PostgreSQL 17 |
| コード実行 | Docker (python:3.14-slim) |
| 認証 | OAuth2 Authorization Code Flow + HttpOnly Cookie (JWT) |
| バージョン管理 | mise |
- mise がインストールされていること
- Docker / Docker Compose が動作していること
mise installGo・Node.js・pnpm が mise.toml に記載のバージョンで揃います。
cd frontend && pnpm install && cd ..バックエンドは起動時に環境変数を読みます。backend/.env.example をコピーして backend/.env を作成し、値を設定してください。
cp backend/.env.example backend/.env
AUTH_BYPASSについてAUTH_BYPASS=trueにすると JWT 検証を完全スキップし、固定のテスト管理者として動作します。 デフォルトはfalseです。開発時も OIDC プロバイダーを使ってください。
Google Cloud Console でプロジェクトを作成し、OAuth 2.0 クライアント ID を発行します。
- 承認済みリダイレクト URI:
http://localhost:8080/api/auth/google/callback
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export GOOGLE_CALLBACK_URL="http://localhost:8080/api/auth/google/callback"
export JWT_SECRET="任意のランダム文字列(本番は強いシークレットを使うこと)"
export AUTH_BYPASS=falseexport KEYCLOAK_CLIENT_ID="daileycoding"
export KEYCLOAK_CLIENT_SECRET="your-secret"
export KEYCLOAK_ISSUER="http://keycloak:8080/realms/daileycoding"
export KEYCLOAK_CALLBACK_URL="http://localhost:8080/api/auth/keycloak/callback"
export JWT_SECRET="任意のランダム文字列"
export AUTH_BYPASS=falsemise run db # PostgreSQL コンテナを起動
mise run db:migrate # マイグレーションを実行(初回・変更時)マイグレーションは backend/internal/infrastructure/db/migrations/ 以下の SQL ファイルが順番に適用されます。
ログインすると role=student のユーザーが自動作成されます。
管理者への昇格には 2 つの方法 があります。
まず対象ユーザーが一度ログインしてアカウントを作成してから実行します。
docker compose exec postgres psql -U daileycoding -d daileycoding-- ログイン済みユーザーを管理者に昇格
UPDATE users SET role = 'admin' WHERE email = 'yourname@example.com';
-- 昇格後は再ログインすると admin ロールが反映されるauthentik を OIDC プロバイダーとして使う場合、グループ単位で管理者を自動付与できます。
authentik 側の設定:
- authentik 管理画面でグループ(例:
dailycoding-admins)を作成し、管理者にしたいユーザーを追加する - Provider の Advanced Protocol Settings → Scopes に
groupsProperty Mapping を追加する (これにより ID Token にgroupsクレームが含まれるようになる)
バックエンド側の設定:
# backend/.env.prod に追記
ADMIN_GROUPS=dailycoding-admins # カンマ区切りで複数指定可この設定を有効にすると、ログイン時にグループが照合されロールが自動で同期されます。
| 状態 | 結果 |
|---|---|
| グループに所属している | role = admin |
| グループから除外された | 次回ログイン時に role = student に戻る |
ADMIN_GROUPS 未設定 |
ロールを変更しない(方法 A の手動管理) |
管理者になると /admin/problems の問題管理ページにアクセスできます。
ALLOWED_DOMAINS に含まれないドメインのユーザー(外部協力者など)を個別に許可できます。
docker compose exec postgres psql -U daileycoding -d daileycoding-- 外部メールアドレスを許可リストに追加
INSERT INTO allowed_emails (email, note)
VALUES ('guest@gmail.com', '外部協力者 山田太郎');
-- 一覧確認
SELECT * FROM allowed_emails;
-- 削除(アクセス停止)
DELETE FROM allowed_emails WHERE email = 'guest@gmail.com';
ALLOWED_DOMAINSが未設定の場合はこのテーブルに関係なく全員許可になります。 本番環境では必ずALLOWED_DOMAINSを設定してください。
ターミナルを 3 つ用意して、それぞれ実行します。
# 1. DB(起動済みであればスキップ)
mise run db
# 2. バックエンド(port 8080)
mise run backend
# 3. フロントエンド(port 3000)
mise run frontendブラウザで http://localhost:3000 を開きます。
| コマンド | 内容 |
|---|---|
mise run db |
PostgreSQL コンテナを起動 |
mise run db:migrate |
未適用マイグレーションを実行 |
mise run db:reset |
データ全削除 → DB 再起動 → マイグレーション |
mise run backend |
Go API サーバー起動 (port 8080) |
mise run frontend |
Next.js 開発サーバー起動 (port 3000) |
ブラウザ
→ GET /api/auth/google # state Cookie を発行し Google 認可画面へリダイレクト
→ Google 同意画面
→ GET /api/auth/google/callback # コード交換 → ユーザー情報取得 → JIT プロビジョニング
→ HttpOnly Cookie (dc_session) に JWT を発行
→ フロントエンドへリダイレクト
- Cookie 名:
dc_session(HttpOnly / SameSite=Lax / 有効期限 24 時間) - JWT ペイロード:
uid/email/name/role - 複数プロバイダー対応: 同じメールアドレスで Google と Keycloak の両方からログインすると同一ユーザーに紐づく
.
├── mise.toml # ツールバージョン・タスク定義
├── docker-compose.yml # PostgreSQL
├── backend/
│ ├── cmd/server/ # エントリポイント
│ ├── internal/
│ │ ├── domain/ # エンティティ・型定義
│ │ ├── handler/ # HTTP ハンドラー
│ │ ├── middleware/ # JWT 認証ミドルウェア
│ │ ├── usecase/ # ビジネスロジック
│ │ └── infrastructure/
│ │ ├── db/ # PostgreSQL(migrations・repository)
│ │ └── docker/ # コード実行エンジン
└── frontend/
└── src/
├── app/ # Next.js App Router ページ
├── features/ # 機能ごとのコンポーネント・API
├── shared/ # 共通 Provider・型・設定
└── components/ # 汎用 UI コンポーネント