このプロジェクトは、ClojureScript と shadow-cljs を使用して作成されたフルスタックの3択クイズアプリケーションです。複数種類のクイズ、ユーザー認証、履歴管理、復習モード、統計表示などの機能を備えた本格的なWebアプリケーションです。
- フルスタックClojureScript: フロントエンドとバックエンドを全てClojureScriptで実装
- 複数クイズ対応: 3種類のクイズから選択可能(一般知識・世界の首都・都道府県庁所在地)
- TSVファイル管理: 問題データはTSVファイルで管理・編集可能
- ユーザー認証: セッションベースの認証システム
- データベース統合: Prisma ORM + SQLiteによるデータ永続化
- 履歴管理: クイズセッションの完全な履歴記録とクイズ別グループ表示
- 復習モード: 間違えた問題を再チャレンジ
- 練習モード: 過去に間違えた問題を選択して練習
- 統計情報: 平均スコア、最高スコア、総セッション数などの統計
- リアルタイム更新: shadow-cljsによるホットリロード対応
- キーボード操作: 数字キー・矢印キーによる操作サポート
- レスポンシブデザイン: モバイル対応UI
様々なジャンルの基本的な知識問題(8問)
世界各国の首都に関する問題(8問)
日本の都道府県庁所在地に関する問題(8問)
- ClojureScript: メイン開発言語
- Reagent: React の ClojureScript ラッパー
- shadow-cljs: 開発・ビルドツール
- Reitit: ルーティング(クライアントサイド)
- Accountant: HTML5 History API
- ClojureScript: サーバーサイド実装
- Express.js: Webサーバーフレームワーク
- Reitit: データドリブンルーティング(サーバーサイド)
- Prisma: データベースORM
- SQLite: データベース
- bcryptjs: パスワードハッシュ化
- express-session: セッション管理
- connect-sqlite3: セッション永続化
quizapp/
├── package.json # npm依存関係とスクリプト
├── shadow-cljs.edn # ClojureScript ビルド設定
├── prisma/
│ └── schema.prisma # データベーススキーマ
├── src/
│ └── cljs/
│ ├── client/ # フロントエンド
│ │ ├── components/ # Reactコンポーネント
│ │ │ ├── auth.cljs # 認証フォーム
│ │ │ ├── quiz.cljs # クイズ画面・選択画面
│ │ │ ├── history.cljs # 履歴・統計表示
│ │ │ └── layout.cljs # レイアウト
│ │ ├── core.cljs # メインアプリケーション
│ │ ├── state.cljs # 状態管理
│ │ ├── data.cljs # データ管理・API通信
│ │ └── events.cljs # イベントハンドリング
│ ├── server/ # バックエンド
│ │ ├── core.cljs # Express サーバー
│ │ ├── database.cljs # データベース操作
│ │ ├── data.cljs # クイズデータ管理
│ │ ├── reitit_router.cljs # 統合ルーティング
│ │ ├── middleware.cljs # 認証・CORS
│ │ └── util.cljc # 共通ユーティリティ
│ └── common/
│ └── data.cljc # 共通データ定義
├── resources/
│ └── public/
│ ├── index.html # メインHTML
│ ├── css/
│ │ └── site.css # スタイルシート
│ ├── data/ # クイズデータ(TSV)
│ │ ├── quiz-questions.tsv # 一般知識
│ │ ├── capitals_quiz.tsv # 世界の首都
│ │ └── prefectural_capitals_quiz.tsv # 都道府県庁所在地
│ └── js/ # コンパイル済みJavaScript
├── target/
│ └── server.js # コンパイル済みサーバー
└── README.md # このファイル
- id: String (主キー)
- username: String (ユニーク)
- password: String (ハッシュ化)
- createdAt: DateTime
- updatedAt: DateTime
- id: String (主キー)
- name: String
- description: String
- fileName: String
- category: String
- createdAt: DateTime
- updatedAt: DateTime
- id: String (主キー)
- userId: String (外部キー -> User)
- quizId: String (外部キー -> Quiz)
- startedAt: DateTime
- completedAt: DateTime?
- totalQuestions: Int
- correctAnswers: Int
- initialCorrect: Int (初回正解数)
- reviewCorrect: Int (復習正解数)
- finalScore: Int
- percentage: Float
- isCompleted: Boolean
- id: String (主キー)
- sessionId: String (外部キー -> QuizSession)
- questionIndex: Int
- questionText: String
- options: String (JSON)
- correctAnswer: Int
- initialAnswer: Int?
- initialCorrect: Boolean
- reviewAnswer: Int?
- reviewCorrect: Boolean
- finalCorrect: Boolean
- answeredAt: DateTime
- reviewedAt: DateTime?
POST /api/auth/login
- ユーザーログインPOST /api/auth/logout
- ユーザーログアウトGET /api/auth/me
- 現在のユーザー情報
GET /api/health
- ヘルスチェックGET /api/quiz
- 利用可能なクイズ一覧取得GET /api/quiz/:id
- 特定のクイズの問題取得POST /api/quiz/:id/validate
- 回答検証
POST /api/quiz/session/start
- 新しいセッション開始POST /api/quiz/session/:sessionId/answer
- 回答記録POST /api/quiz/session/:sessionId/review
- 復習回答記録POST /api/quiz/session/:sessionId/complete
- セッション完了
GET /api/user/history
- ユーザー履歴取得GET /api/user/stats
- 統計情報取得DELETE /api/user/history
- 全履歴削除DELETE /api/user/history/:sessionId
- 個別セッション削除DELETE /api/user/history/quiz/:quizId
- 特定クイズの履歴削除
# Node.js (LTS版推奨)
node --version
# Java (OpenJDK 11以上)
java -version
# リポジトリのクローン
git clone <リポジトリURL>
cd quizapp
# 依存関係のインストール
npm install
# データベースのセットアップ
npm run db-setup
# 開発サーバー起動(フロントエンド + バックエンド)
npm run start
- フロントエンド: http://localhost:3000
- バックエンド: http://localhost:3001
# フロントエンド開発サーバー
npm run dev
# バックエンド開発サーバー
npm run dev-server
# 両方同時に監視
npm run dev-all
# プロダクションビルド
npm run build-all
# サーバーのみ起動
npm run server
# データベース初期化
npm run db-setup
初回起動時は以下のテストユーザーでログイン:
- ユーザー名: user1
- パスワード: megafeps
- クイズ選択: ログイン後、3種類のクイズから選択
- 問題回答:
- マウス: 選択肢をクリック
- キーボード:
1
,2
,3
キーで選択肢を選択 - 次へ進む:
Enter
または→
,↓
キーで次の問題へ
- クイズを一通り完了
- 結果画面で「復習モード」ボタンをクリック
- 間違えた問題のみを再度解答
- 復習結果も履歴に記録される
- ヘッダーの「履歴」ボタンをクリック
- クイズ別にグループ化された履歴を表示
- 統計情報(平均スコア、最高スコア、総セッション数)を確認
- 「間違えた問題を練習」で過去の間違いを復習可能
クイズデータはresources/public/data/
内のTSVファイルで管理されています:
question option1 option2 option3 correct
日本の首都はどこですか? 東京 大阪 京都 0
1 + 1 = ? 1 2 3 1
地球は太陽の周りを何日で回りますか? 30日 100日 365日 2
- question: 問題文
- option1, option2, option3: 選択肢
- correct: 正解のインデックス(0-based)
-
対応するTSVファイルを編集:
quiz-questions.tsv
- 一般知識クイズcapitals_quiz.tsv
- 世界の首都クイズprefectural_capitals_quiz.tsv
- 都道府県庁所在地クイズ
-
サーバーを再起動すると新しい問題が反映されます
src/cljs/server/data.cljs
のquiz-definitions
に新しいクイズを追加:
{:id "new-quiz"
:name "新しいクイズ"
:description "新しいクイズの説明"
:fileName "new_quiz.tsv"
:category "new-category"}
# ブラウザREPL
npx shadow-cljs browser-repl
# Node.js REPL(サーバー用)
npx shadow-cljs node-repl
.cljs
ファイルを編集すると自動でコンパイル- ブラウザに即座に反映(状態保持)
;; ブラウザコンソールで
@app-state ; 現在の状態を表示
(swap! app-state assoc :current-question 0) ; 状態を直接変更
resources/public/css/site.css
を編集してUIをカスタマイズ
src/cljs/server/reitit_router.cljs
のroutes
に新しいエンドポイントを追加:
["/api/new-endpoint" {:get {:middleware [middleware/require-auth]
:handler new-endpoint-handler}}]
# Prismaクライアントを再生成
npx prisma generate
# データベースを再作成
npm run db-setup
# キャッシュをクリア
npx shadow-cljs clean
# 再ビルド
npm run build-all
src/cljs/server/core.cljs
の PORT
定数を変更
export JVM_OPTS="-Xmx2g"
npm run dev
# 本番用ビルド
npm run build-all
# サーバー起動
npm run server
export NODE_ENV=production
export PORT=3001
export DATABASE_URL="file:./production.db"
- リポジトリをフォーク
- 機能ブランチを作成 (
git checkout -b feature/new-feature
) - 変更をコミット (
git commit -am 'Add new feature'
) - ブランチにプッシュ (
git push origin feature/new-feature
) - プルリクエストを作成
MIT License