What to build
Add the specialization column to the doctors table and ship the read + partial-update endpoints for a doctor's own profile. The doctor dashboard gains a small read-only display of name + specialization so the slice is verifiable end-to-end. No edit form ships in this module — the PATCH endpoint exists for Module 03's API contract but the UI for editing is explicitly out of scope.
- Drizzle migration:
ALTER TABLE doctors ADD COLUMN specialization text (nullable). pnpm db:push applies cleanly to the existing local DB.
- Fill in
doctorContract with getProfile and updateProfile ts-rest entries.
GET /doctors/me/profile → 200 { userId, firstName, lastName, specialization } behind requireAuth() + requireRole(['doctor']).
PATCH /doctors/me/profile → 200 with the full updated profile; accepts any combination of firstName, lastName, specialization; empty body {} is a no-op returning the current profile; bumps updated_at.
- Use case + repository following the layered architecture; structured INFO log on every profile update (acting user id, fields changed).
- Doctor dashboard shows specialization beneath the welcome line (read-only text; "—" or similar when null). No form.
Acceptance criteria
User stories covered
Blocked by
- None — can start immediately
What to build
Add the
specializationcolumn to thedoctorstable and ship the read + partial-update endpoints for a doctor's own profile. The doctor dashboard gains a small read-only display of name + specialization so the slice is verifiable end-to-end. No edit form ships in this module — the PATCH endpoint exists for Module 03's API contract but the UI for editing is explicitly out of scope.ALTER TABLE doctors ADD COLUMN specialization text(nullable).pnpm db:pushapplies cleanly to the existing local DB.doctorContractwithgetProfileandupdateProfilets-rest entries.GET /doctors/me/profile→ 200{ userId, firstName, lastName, specialization }behindrequireAuth()+requireRole(['doctor']).PATCH /doctors/me/profile→ 200 with the full updated profile; accepts any combination offirstName,lastName,specialization; empty body{}is a no-op returning the current profile; bumpsupdated_at.Acceptance criteria
GET /doctors/me/profilereturns the authenticated doctor's profile; returns 401 without JWT and 403 with a patient JWT.PATCH /doctors/me/profilewith{ specialization: "Cardiology" }updates only that field and returns the new profile.PATCH /doctors/me/profilewith{}returns the current profile unchanged (no-op).PATCH /doctors/me/profilewith{ firstName, lastName, specialization }updates all three and bumpsupdated_at.pnpm verifyexits 0.User stories covered
Blocked by