{"id":51824223,"url":"https://github.com/htlin222/mcq-bank","last_synced_at":"2026-07-22T07:33:40.039Z","repository":{"id":360275484,"uuid":"1247683496","full_name":"htlin222/mcq-bank","owner":"htlin222","description":"Collaborative MCQ study system — wiki-style explanations, threaded discussion, timed mock exams. Full-stack Cloudflare (Workers + D1 + R2 + Access), free tier.","archived":false,"fork":false,"pushed_at":"2026-07-17T12:54:26.000Z","size":1873,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-17T14:15:15.636Z","etag":null,"topics":["cloudflare","cloudflare-access","cloudflare-d1","cloudflare-pages","cloudflare-r2","cloudflare-workers","collaborative-learning","exam-preparation","hematology","hono","mcq","medical-education","question-bank","react","sqlite","study-group","study-tool","typescript","zero-trust","zero-trust-auth"],"latest_commit_sha":null,"homepage":"https://hema-2026.hsiehting.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/htlin222.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-23T16:32:43.000Z","updated_at":"2026-07-17T12:54:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/htlin222/mcq-bank","commit_stats":null,"previous_names":["htlin222/mcq-bank"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/htlin222/mcq-bank","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htlin222%2Fmcq-bank","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htlin222%2Fmcq-bank/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htlin222%2Fmcq-bank/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htlin222%2Fmcq-bank/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/htlin222","download_url":"https://codeload.github.com/htlin222/mcq-bank/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htlin222%2Fmcq-bank/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35753457,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-22T02:00:06.236Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare","cloudflare-access","cloudflare-d1","cloudflare-pages","cloudflare-r2","cloudflare-workers","collaborative-learning","exam-preparation","hematology","hono","mcq","medical-education","question-bank","react","sqlite","study-group","study-tool","typescript","zero-trust","zero-trust-auth"],"created_at":"2026-07-22T07:33:37.367Z","updated_at":"2026-07-22T07:33:40.033Z","avatar_url":"https://github.com/htlin222.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Q\u0026A bank — collaborative MCQ study system\n\nMultiple-choice question bank + collaborative wiki-style explanations,\n**full-stack on Cloudflare free tier**. Designed for small invite-only\nstudy groups (5–50 users). This repo is the 2026 Taiwan hematology\nsubspecialty exam (\"hema-2026\") instance, but every per-fork identifier\nlives in `config.toml` — read **[Forking this codebase](#forking-this-codebase)**\nto spin up your own deployment.\n\n- ~1000 questions, organised by year + category\n- Two study modes: review (single question, collaborative explanation, threads)\n  and full mock exam (timed, scored, error review)\n- 5–50 user small group (CF Access whitelist, email OTP, no passwords)\n- Free tier for development and production\n\n## 功能\n\n- **複習模式**:單題練習,即時看答案,協作 wiki 詳解 (TipTap rich text + 圖片)\n- **全真作答**:整年模擬考,計時、成績、錯題回顧\n- **討論串**:每題留言 thread,@提及成員,in-app 通知\n- **零信任認證**:Cloudflare Access,email allow-list + OTP,**無密碼**\n- **詳解共編**:Pessimistic lock + 版本歷史 (未來可升 Yjs CRDT)\n- **AI 輔助** (Workers AI 免費額度):詳解摘要、tag 建議、改寫\n- **RWD**:手機/平板/桌機\n\n## 技術棧\n\n| 層 | 技術 |\n|---|---|\n| Frontend | React 18 + Vite + TypeScript + TailwindCSS + TipTap |\n| Backend | Cloudflare Workers + Hono |\n| DB | Cloudflare D1 (SQLite) |\n| 物件儲存 | Cloudflare R2 (圖片) |\n| 認證 | Cloudflare Access (Zero Trust) |\n| AI | Cloudflare Workers AI |\n| 託管 | Cloudflare Pages |\n\n## Forking this codebase\n\nEverything fork-specific lives in three files; all three are gitignored\nand shipped as `.example` templates. Either run the interactive helper:\n\n```bash\n./scripts/setup.sh        # asks for slug / host / admin email / CF token\n```\n\n…or copy the templates by hand:\n\n```bash\ncp config.example.toml   config.toml\ncp wrangler.example.toml wrangler.toml\ncp .env.example          .env\n$EDITOR config.toml wrangler.toml .env\n```\n\nWhat goes where:\n\n| File              | Tracked? | Holds                                                   |\n|-------------------|----------|---------------------------------------------------------|\n| `config.toml`     | ❌       | slug, brand strings, public host, CF resource names     |\n| `wrangler.toml`   | ❌       | Worker bindings (must match `config.toml [project]`)   |\n| `.env`            | ❌       | CF API token, account ID, roster sheet URL, GH PAT      |\n\nAfter editing, `./scripts/deploy.sh` creates the D1 DB, R2 bucket, Worker,\nand Pages project from those values. Resource names everywhere in scripts\ncome from `config.toml [project]` (via `scripts/lib/cfg.mjs` /\n`scripts/lib/cfg.sh`), so changing the slug there propagates.\n\nReference deployment (this fork):\n\n| Resource | Value |\n|---|---|\n| URL | https://hema-2026.hsiehting.com |\n| Worker | `hema-2026-api` |\n| D1 | `hema-2026-db` |\n| R2 | `hema-2026-uploads` |\n| Access team | `htlin.cloudflareaccess.com` |\n\n## 本地開發\n\n```bash\n./scripts/setup.sh                        # (first time) writes config/wrangler/.env\npnpm install                              # worker deps\ncd frontend \u0026\u0026 pnpm install \u0026\u0026 cd ..      # frontend deps\npnpm db:migrate:local                     # local D1 schema + sample data\npnpm dev                                  # wrangler dev (:8787)\ncd frontend \u0026\u0026 pnpm dev                   # in another terminal — vite (:5173)\n```\n\n開瀏覽器到 http://localhost:5173 即可使用,Vite proxy 會把 `/api` 和 `/img` 轉到 :8787 並注入 `X-Dev-Email`。\n\n要改本機登入用的 email,改 `config.toml [dev] dev_email`。\n\n## 部署\n\n`.env` 需要 `CF_API_TOKEN`、`CF_ACCOUNT_ID`、`PAGES_DOMAIN`、`ADMIN_EMAILS`、`ROSTER_CSV_URL` (見 `.env.example`)。\n\n```bash\n./scripts/deploy.sh         # D1 / R2 / Worker / Pages,一鍵\nnode scripts/sync-access.ts # 建/同步 Access app + policy + Worker secrets\n```\n\n兩個都是 idempotent,可以重複跑。\n\n## 匯入真實題庫\n\n把 11 年 × 100 題整成 CSV (`year,number,group,stem,option_a..e,answer,tags,difficulty,source`),`year` 用民國 (104..114),`group` 用 `內科` 或 `共同`:\n\n```bash\nnode scripts/import-questions.ts ./questions.csv          # 上 prod\nnode scripts/import-questions.ts ./questions.csv --local  # 上本地測試\n```\n\n驗證規則 (任何一筆失敗就整批拒絕):\n- `year ∈ 104..114`\n- 1..70 必須 `group=內科`,71..100 必須 `group=共同`\n- 每年總計 70 內科 + 30 共同\n- (year, number) 全域唯一\n- `answer` 字母對應到實際存在的 option\n\n匯入前可選擇清除範例:\n\n```bash\nwrangler d1 execute hema-2026-db --remote --command 'DELETE FROM questions WHERE year = 100;'\n```\n\n## 資料結構\n\n見 `migrations/0001_initial_schema.sql` + `0003_year_and_groups.sql`。\n\n- `users` - 使用者 (email = identity from Access JWT)\n- `questions` - 題目 (id = `${year}-${number padded 3}`、`group` ∈ {內科,共同})\n- `question_tags` - 多對多自由標籤\n- `explanations` - 共筆詳解 (TipTap JSON + lock)\n- `explanation_history` - 版本歷史\n- `comments` - threaded 留言\n- `mentions` - @提及索引\n- `notifications` - 通知 inbox\n- `exam_sessions` / `exam_answers` - 模擬考\n- `review_progress` - 個人複習狀態 (含 bookmark)\n\n## 帳務估計\n\n20 人重度使用,預期 **$0/月** — 全部落在 free tier 內 (Workers/Pages/D1/R2/Access 50 seat/AI 10K neurons 日)。\n\n未來如果改 Durable Object 真共編,要 Workers Paid plan **$5/月**起。\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtlin222%2Fmcq-bank","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhtlin222%2Fmcq-bank","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtlin222%2Fmcq-bank/lists"}