# Dyolink — Agent guide This file orients Cursor agents at the start of a **new chat**. Project conventions live in **`.cursor/rules/`** (auto-loaded). Workflow playbooks live in **`.cursor/skills/`**. ## What Dyolink is Dental clinic ↔ lab platform (monorepo): | Path | Stack | |------|--------| | `backend/` | NestJS, Prisma, PostgreSQL | | `frontend/` | Next.js 16, React 19, next-intl, Tailwind | | `infrastructure/` | Docker, nginx, deploy scripts | **Organization types:** `CLINIC` (patients, appointments, treatment) and `LAB` (cases, tasks). Many features are org-type-specific. Permissions use `TAB_*_READ` / `TAB_*_EDIT` codes — see `backend/src/common/permissions.ts`. ## Before you code 1. **Read applicable rules** in `.cursor/rules/` (especially `dyolink-overview` and the file-scoped rule for the area you touch). 2. **Match existing patterns** in the nearest feature folder — do not invent parallel structures. 3. **Keep diffs small** — one concern per change unless the user asks for a refactor. 4. **Verify:** `npm run build` (backend) and `npx tsc --noEmit` (frontend) when you change types or cross-cutting code. ## Frontend layout (critical) ``` frontend/src/ app/ → thin page.tsx only; compose from ui/ components/ ui/shared/ → cross-feature UI (Button, Sidebar, …) ui/{feature}/ → feature UI (+ {Feature}Page.tsx for route logic) shared/ → cross-feature non-UI (formatApiError, permissions, …) {feature}/ → feature non-UI (helpers, config, pure functions) lib/ → api clients, hooks types/ → shared TS types messages/{en,fa,nl}.json → all user-facing strings ``` **Example thin page:** `app/.../treatment/page.tsx` → imports `TreatmentWorkspace` from `components/ui/treatment/`. **Treatment tab:** Preview and editable form are **separate** until the user clicks **Load into workspace** on a history item. See `.cursor/skills/treatment-workspace/SKILL.md` before changing that flow. **Treatment lab rules (quick ref):** - Lab-dependent details (e.g. prosthesis) **without teeth** can save but **cannot ship** — show `LabShipmentBlockedNotice` + inline banner; toast on dispatch add. - **History filters** are client-side only (`treatmentHistoryFilters.ts`): “Not shipped to lab” + single date on already-fetched patient history; includes live current draft when filtering. - **Lab shipments rail**: unified list with scope toggle **This patient** vs **All updates** (unread across org, includes patient name). - **Unread semantics**: Treatment tab badge = count of unread cases (per-case read cursor) and clears when a case is opened/marked read (not on tab visit). - **Lab shipment progress + comments**: shown in **Lab dispatch panel** for the active shipment; expanding activity / opening comments marks that case read. **Lab Tasks tab:** Newest case first; steps ordered 1→N; case grouping when sorted by date; `stepCompleted` filter; prosthesis colors from `PROSTHESIS_TYPE_COLORS` via catalog; task assignment in **Cases** (compact row: status + assignee + last update); on **Tasks**, all staff see every task but only assignee (or unassigned pool) can change status — others see “Assigned to {name}” instead of the status dropdown; **case due dates** set/edited in clinic Treatment lab dispatch, shown on lab Cases/Tasks with overdue filter + sort; **mobile:** larger task status controls, sticky case header when grouped; **tab badges:** `LabCaseActivity` + `GET /notifications/tab-counts` (lab Cases/Tasks split, clinic Treatment) — see `.cursor/skills/lab-tasks/SKILL.md` and `.cursor/skills/lab-notifications/SKILL.md`. ## Backend layout ``` backend/src/ modules/{feature}/ → controller, service, dto, module common/ → guards, permissions, errors, utils prisma/ → schema, migrations, seed ``` Errors: `AppException` + `ErrorCode` → frontend `getUserFacingError()`. Never throw raw strings for user-facing failures. ## Git & commits - **Do not commit or push** unless the user explicitly asks. - **Do not** amend commits, force-push, or skip hooks unless explicitly requested. ## Skills (workflows) | Skill | When to use | |-------|-------------| | `.cursor/skills/add-feature/` | New tab, API module, or end-to-end feature | | `.cursor/skills/treatment-workspace/` | Treatment tab: preview vs form, history, load flow, drafts | | `.cursor/skills/lab-tasks/` | Lab Tasks tab: sort, case grouping, step-completed filter, prosthesis colors | | `.cursor/skills/lab-notifications/` | Tab badges: LabCaseActivity, tab-counts API, read cursors | | `.cursor/skills/frontend-structure/` | Moving components, auditing folder layout | | `.cursor/skills/api-errors/` | New backend errors + frontend translations | ## Subagents (Task tool) Use subagents to **save context**, not to avoid work: | Type | Use for | |------|---------| | `explore` | Broad codebase search, unfamiliar areas | | `shell` | Git, npm, long command sequences | | `generalPurpose` | Multi-step research when parent context is large | Do **not** delegate the user's main task to a subagent and return its summary — implement in the parent unless the user asked for exploration only. ## Improving this setup When you and the user agree on a new convention, **add or update a rule** in `.cursor/rules/` (keep each rule under ~50 lines, one topic). For multi-step workflows, extend `.cursor/skills/`. **To save a convention mid-task**, say: *"Remember this"* or *"Add to project rules"* — the agent uses the `capture-convention` skill and updates the repo (commit with your code). | You say | Agent does | |---------|------------| | "Remember this: …" | Updates the right `.mdc` rule or skill | | "Add a skill for …" | Creates `.cursor/skills/{name}/SKILL.md` | | "This rule is wrong" | Edits the rule file; you commit | Rules/skills **load automatically** in new chats; they do **not** update themselves unless you ask.