Developer Onboarding
Welcome. This guide gets you from zero to “first PR merged” in about 60 minutes.
Audience: any incoming contributor — Vet 87 / 88 / 89 students taking over from Palm, or external open-source devs.
1. Pre-requisites
หัวข้อที่มีชื่อว่า “1. Pre-requisites”| Tool | Minimum | How to get it |
|---|---|---|
| Node.js | 18.x · 20.x · or 22.x LTS | https://nodejs.org/ (pick LTS) |
| npm | bundled with Node | — |
| git | 2.40+ | https://git-scm.com/ |
| Editor | VS Code or Cursor (recommended · MCP-aware) | https://code.visualstudio.com/ or https://cursor.com/ |
| Supabase account | free tier | https://supabase.com/ — ask Palm to invite you as a team member on the cuvetsmo project |
| GitHub access | read at minimum · write for PRs | ask Palm to add you as a collaborator on palmzamak2547/WebCUVETSMO |
Optional but useful:
- Supabase CLI — only needed if you want to deploy Edge Functions or pull schema diffs.
npx supabase ...works without a global install. - Playwright browsers —
npx playwright install chromiumif you plan to run smoke tests locally.
2. Clone and run
หัวข้อที่มีชื่อว่า “2. Clone and run”git clone https://github.com/palmzamak2547/WebCUVETSMO.gitcd WebCUVETSMOnpm installcp .env.example .env.local# Open .env.local in your editor and paste the two values from Palm.# (VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY · both are public-safe.)npm run devVisit http://localhost:5173. Vite picks the next free port if 5173 is busy — check the terminal output.
You should see the home page. If <ProtectedRoute> is asking you to “set Supabase env vars”, your .env.local was not loaded — restart npm run dev.
Sign in
หัวข้อที่มีชื่อว่า “Sign in”The site only accepts @chula.ac.th and @student.chula.ac.th emails (enforced at three layers: client, Supabase Auth, DB trigger). Use your real Chula email — sign-up will auto-create a member profile. To get a higher role for testing, ask Palm or an existing admin to promote you from /admin → Users.
3. Your first feature · “add yourself to the board history”
หัวข้อที่มีชื่อว่า “3. Your first feature · “add yourself to the board history””Goal: get one PR merged so you understand the full loop — clone → edit → build → push → review. Should take 30–60 minutes.
Step 1 · Pick a file
หัวข้อที่มีชื่อว่า “Step 1 · Pick a file”Open src/data/board-history.ts. This file holds the canonical roster for past SMO terms. Find the current term (SMO 69 at time of writing) and the chairs array.
Step 2 · Add an entry
หัวข้อที่มีชื่อว่า “Step 2 · Add an entry”Add one entry for yourself with the fields the BoardMember type requires:
{ position: 'ฝ่าย IT (ผู้ช่วย Palm)', cluster: 'operations', fullName: 'YOUR_FULL_NAME', nickname: 'YOUR_NICKNAME', vetCohort: 87,}Privacy contract (see the file header): we store position / full name / nickname / cohort only. Never add phone numbers, student IDs, or email addresses to this file. Contact info lives in the Drive contact list, not the repo.
Step 3 · Verify it renders
หัวข้อที่มีชื่อว่า “Step 3 · Verify it renders”npm run devVisit /about/board and confirm your entry is on the SMO 69 card.
Step 4 · Type-check + build
หัวข้อที่มีชื่อว่า “Step 4 · Type-check + build”npx tsc --noEmit # TypeScript check · must be cleannpm run build # production bundle in dist/Both should pass. If tsc complains about a missing field, you probably left out a non-optional property on BoardMember.
Step 5 · Commit and push
หัวข้อที่มีชื่อว่า “Step 5 · Commit and push”git checkout -b feat/add-myself-to-boardgit status -s# Stage SPECIFIC files (NEVER `git add -A`):git add src/data/board-history.tsgit commit -m "add YOUR_NICKNAME to SMO 69 board (IT)"git push -u origin feat/add-myself-to-boardOpen a PR on GitHub. Palm or another admin reviews, merges, and Vercel auto-deploys within ~60 seconds.
That’s it — you’re in.
4. Code style and conventions
หัวข้อที่มีชื่อว่า “4. Code style and conventions”4.1 Internationalization (i18n)
หัวข้อที่มีชื่อว่า “4.1 Internationalization (i18n)”Two locales currently live: src/locales/th.json (default) and src/locales/en.json. When you add user-facing text:
- Add a key to both files
- Use
useTranslation()fromreact-i18nextto consume it - Keys are nested by feature area (e.g.
submit.section3.budget.label) - Don’t hardcode Thai strings in JSX once the surrounding component is i18n-aware
4.2 Tailwind palette
หัวข้อที่มีชื่อว่า “4.2 Tailwind palette”Brand colors live in tailwind.config.js:
stone-*for neutrals (the site’s whole grey scale)smo-*for the brand accent (sky-blue derived from the SMO logo)
Don’t introduce new color tokens without asking — the palette is meant to be the single source of truth for a global rebrand.
4.3 Component patterns
หัวข้อที่มีชื่อว่า “4.3 Component patterns”- All pages are lazy-loaded · keep one page per file under
src/pages/ - Shared UI in
src/components/ - Auth-gated pages wrap with
<ProtectedRoute>(seesrc/components/ProtectedRoute.tsx) - Role-gated pages add
roles={[...]}or useBOARD_ROLES/APPROVAL_ROLESfrom the same module
4.4 Middle-dot (·) usage
หัวข้อที่มีชื่อว่า “4.4 Middle-dot (·) usage”The codebase uses · (middle dot, U+00B7) as a soft separator in copy. Keep it consistent — Login · Sign up rather than Login | Sign up or Login / Sign up. Search the locales for examples.
4.5 Git hygiene
หัวข้อที่มีชื่อว่า “4.5 Git hygiene”- Never
git add -Aorgit add .. Stage specific files by name. Untracked launch kits, scratch folders, and.env*files are common in worktrees. - Imperative commit subjects under 70 chars (
add export button,fix RLS for owner submit) - Body explains why not what — the diff already shows what
- Co-author tag is appreciated:
Co-Authored-By: Your Name <you@example.com>
4.6 Avoid burst-pushes
หัวข้อที่มีชื่อว่า “4.6 Avoid burst-pushes”Vercel Hobby tier has a 100 deploys/day quota across the whole team account (shared with VetMock, Hanong, miracle-investment). One feature = one deploy, not ten. Batch your commits before pushing if you’re iterating.
5. Pre-push checklist
หัวข้อที่มีชื่อว่า “5. Pre-push checklist”Before git push on any branch that will trigger CI:
-
npx tsc --noEmitpasses -
npm run buildpasses (Vite ES2018 target — older browsers will silently break if you use newer syntax) - If you touched a route, you tested both the logged-out and logged-in paths
- If you touched RLS or migrations, you
curl-smoked from an authenticated user (not the dashboard SQL editor — that bypasses RLS as superuser) - If you added a dependency, you justified the bundle delta (initial chunk target: < 1 MB gzip)
- (Optional but recommended)
npm run test:smoke— runs Playwright e2e
Smoke tests
หัวข้อที่มีชื่อว่า “Smoke tests”npm run test:smokeThis runs the Playwright suite in e2e/. It expects the dev server on localhost:5173 and a valid .env.local. If you don’t have Playwright browsers installed, run npx playwright install chromium once.
6. Where things live
หัวข้อที่มีชื่อว่า “6. Where things live”WebCUVETSMO/├── public/ static assets · forms/ holds official CUVET DOCX├── src/│ ├── App.tsx every route declared here│ ├── main.tsx React root + service worker register│ ├── pages/ one file per route│ ├── components/ shared UI (Header · Footer · ProtectedRoute · ErrorBoundary)│ ├── lib/ auth · supabase client · docx generators · form schema│ ├── locales/ th.json · en.json│ └── data/ static seed data (board-history · newsPosts · partners)├── supabase/│ ├── migrations/ numbered SQL files · run in order│ └── functions/ Edge Functions (Deno)├── docs/ you are here├── e2e/ Playwright smoke tests├── scripts/ one-off helpers (seo-ping · google-indexing)├── .mcp.json MCP server config (gitignored when it has tokens)├── tailwind.config.js brand palette├── vite.config.ts build + PWA config└── vercel.json SPA rewritesFor the deeper “why” behind each choice, see the Architecture reference.
7. Who to ask
หัวข้อที่มีชื่อว่า “7. Who to ask”| Topic | Who | How |
|---|---|---|
| General code questions | Palm (while transitioning) | GitHub issue or DM on IG |
| Council / non-code questions | IG @cuvetsmo | DM |
| Faculty contacts | ผู้ช่วยคณบดีฝ่ายกิจการนิสิต CUVET | email via Palm bridge |
| Production incident (site down) | Palm + current SMO IT lead | LINE group “CUVETSMO IT” (ask to be added) |
| Supabase or Vercel billing | Palm (until handover complete) | direct message |
Useful runbooks live in the source repo alongside this guide: docs/RUNBOOK.md and docs/COST_MONITORING.md.
8. Next steps
หัวข้อที่มีชื่อว่า “8. Next steps”Once your first PR is merged:
- Skim the Architecture doc end-to-end — at least the data model and the routes table
- Read
CONTRIBUTING.mdfor the more advanced workflows (DB migrations, Edge Function deploys, secret rotation) - Pick an issue tagged
good-first-issueon GitHub - If you’re being onboarded as the next maintainer, read the Successor Guide next