{"id":51502020,"url":"https://github.com/uunw/studymate-clone","last_synced_at":"2026-07-07T20:01:53.487Z","repository":{"id":363251808,"uuid":"1258044664","full_name":"uunw/studymate-clone","owner":"uunw","description":"Open-source rebuild of KMITL StudyMate (subject reviews \u0026 curriculum tracker) on TanStack Start + Drizzle + Better Auth, with KMITL SSO. A clone built for learning after the original cloud went down — not affiliated with KMITL.","archived":false,"fork":false,"pushed_at":"2026-06-08T05:57:13.000Z","size":158,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T06:11:47.802Z","etag":null,"topics":["better-auth","drizzle-orm","kmitl","kmitl-sso","postgresql","react","tailwindcss","tanstack-start","turborepo","typescript"],"latest_commit_sha":null,"homepage":null,"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/uunw.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-06-03T08:22:58.000Z","updated_at":"2026-06-08T05:57:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/uunw/studymate-clone","commit_stats":null,"previous_names":["uunw/studymate-clone"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/uunw/studymate-clone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uunw%2Fstudymate-clone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uunw%2Fstudymate-clone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uunw%2Fstudymate-clone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uunw%2Fstudymate-clone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uunw","download_url":"https://codeload.github.com/uunw/studymate-clone/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uunw%2Fstudymate-clone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35241029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"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":["better-auth","drizzle-orm","kmitl","kmitl-sso","postgresql","react","tailwindcss","tanstack-start","turborepo","typescript"],"created_at":"2026-07-07T20:01:52.757Z","updated_at":"2026-07-07T20:01:53.452Z","avatar_url":"https://github.com/uunw.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# StudyMate Clone\n\n\u003e An open-source rebuild of **StudyMate** — a KMITL subject-review \u0026 curriculum-tracking\n\u003e web app — on a modern, fully type-safe TanStack stack.\n\u003e\n\u003e ⚠️ **This is a clone, built for learning.** It was inspired by the original\n\u003e [kmitl-savvy-students/studymate](https://github.com/kmitl-savvy-students) project\n\u003e (Angular + ASP.NET). I rebuilt it from scratch after the original hosting went down,\n\u003e to keep the idea alive and to explore a different architecture. **Not affiliated with,\n\u003e or endorsed by, KMITL.**\n\n[![CI](https://github.com/uunw/studymate-clone/actions/workflows/ci.yml/badge.svg)](https://github.com/uunw/studymate-clone/actions/workflows/ci.yml)\n\n---\n\n## ✨ Features\n\n- 🔐 **Auth** — sign in with your real **KMITL account** via SSO (OpenID Connect,\n  configured as a generic OIDC provider through **Better Auth**'s `genericOAuth`\n  plugin). Accounts are auto-provisioned on first login; the 8-digit student id is\n  read from the OIDC claims.\n- 📚 **Subjects** — browse, search, and paginate the course catalog; per-subject\n  average rating + review count.\n- ⭐ **Reviews** — write/replace a review per (subject, year, term), rate 0.5–5 stars,\n  like/unlike reviews.\n- 🎓 **Curriculum hierarchy** — Faculty → Department → Program → Curriculum, with admin CRUD.\n- 📄 **Transcript** — upload a PDF transcript, parse grades, compute GPA and\n  curriculum progress.\n- 👤 **Profile** — edit name/nickname, pick a curriculum, change password.\n\n## 🧱 Stack\n\n| Layer | Choice |\n| --- | --- |\n| Framework | **TanStack Start** (v1) + **TanStack Router** — SSR, file-based routing, server functions |\n| Data | **TanStack Query** v5 (loader-prefetch + `useSuspenseQuery`) |\n| Forms | **TanStack Form** v1 + **Zod** (Standard Schema) |\n| ORM / DB | **Drizzle ORM** + **PostgreSQL** (local) / **Neon** (prod) |\n| Auth | **Better Auth** (`genericOAuth` → KMITL OIDC SSO) |\n| UI | **React 19** + **Tailwind CSS v4** (CSS-first `@theme`) |\n| Utils | **Remeda**, **date-fns** v4, **Jotai** |\n| Tooling | **Turborepo** + **pnpm** workspaces, **Biome**, **Vitest** |\n\n## 🗂️ Monorepo layout\n\n```\nstudymate-clone/\n├── apps/\n│   └── web/                  # TanStack Start app (routes, SSR, server functions)\n├── packages/\n│   ├── db/                   # Drizzle schema + client + migrations  (@repo/db)\n│   ├── auth/                 # Better Auth server + client config     (@repo/auth)\n│   ├── core/                 # Zod schemas, domain logic, transcript parser (@repo/core)\n│   ├── ui/                   # Shared React 19 components             (@repo/ui)\n│   └── tailwind-config/      # Shared Tailwind v4 theme tokens\n└── turbo.json\n```\n\nServer-only code (Drizzle, Better Auth) is isolated behind `createServerFn` handlers and\n`*.server.ts` modules, so it is stripped from the client bundle. Heavy deps are kept\nexternal to the SSR bundle (see `apps/web/vite.config.ts`).\n\n## 🚀 Quick start\n\n**Prerequisites:** Node ≥ 22, [pnpm](https://pnpm.io) 10, Docker (for local Postgres).\n\n```bash\n# 1. install\npnpm install\n\n# 2. env\ncp .env.example .env          # defaults work for local docker Postgres\n\n# 3. start Postgres\ndocker compose up -d\n\n# 4. create schema + seed reference data\npnpm db:migrate\npnpm db:seed                  # faculties, subjects, teachtables…\n\n# 5. run\npnpm dev                      # http://localhost:3000\n```\n\n### Logging in\n\nLogin uses **KMITL SSO** (issuer `https://sso.kmitl.ac.th/realms/master`). Set\n`KMITL_SSO_CLIENT_ID` / `KMITL_SSO_CLIENT_SECRET` / `KMITL_SSO_ISSUER` in `.env`\n(register an SSO client at [developer.kmitl.ac.th](https://developer.kmitl.ac.th) and\nadd the redirect URI `http://localhost:3000/api/auth/oauth2/callback/kmitl`). Until\nthose are set, public pages work but sign-in is disabled. First login auto-provisions\nthe account; sign-out performs **Single Logout** (ends the KMITL session too).\n\n\u003e **Student id claim:** KMITL's default scopes (`openid profile email`) don't include\n\u003e the 8-digit student id — it's a special claim you request from KDMC. Once granted,\n\u003e set `KMITL_SSO_STUDENT_ID_CLAIM` to that claim name; otherwise the user handle falls\n\u003e back to `preferred_username` / `sub`.\n\nTo grant admin, flip the flag on your user row:\n\n```sql\nUPDATE \"user\" SET is_admin = true WHERE username = '\u003cyour-handle\u003e';\n```\n\n## 📜 Scripts\n\n| Command | What |\n| --- | --- |\n| `pnpm dev` | Run the web app (SSR) on :3000 |\n| `pnpm build` | Build all packages |\n| `pnpm lint` | Biome lint + format check |\n| `pnpm typecheck` | `tsc --noEmit` across the workspace |\n| `pnpm test` | Vitest unit tests |\n| `pnpm db:generate` | Generate a Drizzle migration from schema changes |\n| `pnpm db:migrate` | Apply migrations |\n| `pnpm db:seed` | Seed academic reference data |\n| `pnpm db:studio` | Open Drizzle Studio |\n\n## ☁️ Deployment (Vercel + Neon)\n\nThe app is **deploy-ready** but intentionally not deployed here.\n\n1. **Database** — create a **[Neon](https://neon.com)** Postgres project. Use the\n   **pooled** connection string (`-pooler` endpoint) as `DATABASE_URL`. Run\n   `pnpm db:migrate` against it once.\n2. **Host** — import the repo into **Vercel** (it auto-detects TanStack Start). Set the\n   project **Root Directory** to `apps/web`.\n3. **Env vars** (Vercel project settings):\n\n   | Var | Notes |\n   | --- | --- |\n   | `DATABASE_URL` | Neon pooled connection string |\n   | `BETTER_AUTH_SECRET` | `openssl rand -base64 32` |\n   | `BETTER_AUTH_URL` | your production URL |\n   | `KMITL_SSO_CLIENT_ID` / `KMITL_SSO_CLIENT_SECRET` | from the KMITL SSO client |\n   | `KMITL_SSO_ISSUER` | OIDC issuer (discovery is derived from it) |\n\nThe stack is portable — Drizzle + Postgres, Better Auth, and TanStack Start (via Nitro)\nall run on Cloudflare/Netlify/Fly with config changes only, so you are not locked in.\n\n## ⚖️ Disclaimer \u0026 License\n\nThis is an independent, educational reimplementation inspired by StudyMate. It is **not\naffiliated with KMITL** and ships no data from the original service. All trademarks belong\nto their respective owners.\n\nLicensed under the [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuunw%2Fstudymate-clone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuunw%2Fstudymate-clone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuunw%2Fstudymate-clone/lists"}