# Contributing to OpenVPM Thank you for your interest in contributing to OpenVPM! ## Development Setup 1. **Prerequisites**: Node.js 24.22.1 or a newer Node.js 24 patch, pnpm 9+, Docker 2. **Clone and install**: ```bash git clone https://github.com/evangauer/openvpm.git cd openvpm nvm use # when using nvm; see .nvmrc cp .env.example .env # set NEXTAUTH_SECRET in .env to the output of: openssl rand -base64 32 pnpm install --frozen-lockfile ``` 3. **Start services**: ```bash docker compose --env-file .env -f docker/docker-compose.yml up -d postgres minio minio-bootstrap pnpm db:migrate pnpm db:seed pnpm dev ``` Keep `.env` at the repository root beside `.env.example`. `pnpm dev` loads it for the web server in `apps/web`; you do not need a second env file there. Existing shell exports and app env values take precedence. If `DATABASE_URL` is missing, the dev server stops with setup instructions. Restart `pnpm dev` after changing the root env file. Production continues to use its deployment environment. ## Project Structure - `apps/web/` — Next.js product + dashboard and REST/tRPC APIs - `apps/docs/` — Searchable Next.js staff-guide site - `packages/db/` — Drizzle ORM schema and migrations - `packages/api/` — Shared Zod validators and types - `packages/config/` — Shared TypeScript and Tailwind config - `packages/docs-content/` — Shared guide content and metadata ## Development Workflow 1. Create a feature branch from `main` 2. Make your changes 3. Run `pnpm test` (unit) and `pnpm build` (type-check + lint) to verify 4. Submit a pull request ## Testing - **Unit tests** (Vitest): `pnpm test`. Co-locate as `*.test.ts` next to the code (e.g. `lib/compat/openvpm/__tests__/`). Pure logic — mappers, helpers — should be unit-tested without a database. - **E2E tests** (Playwright): `pnpm test:e2e`. ## Code Style - TypeScript strict mode - Tailwind CSS for styling (follow existing design tokens) - tRPC for all internal API endpoints - Drizzle ORM for database queries ## Adding a compatibility endpoint or target The public REST API ([docs/api](docs/api/README.md)) is OpenVPM's integration moat: integrators (and AI agents) plug into a frozen, vendor-shaped contract. The layout makes adding endpoints — and entire vendor-compatible "targets" — repeatable: - **Route handlers**: `apps/web/app/api/v1//route.ts`. Keep them **thin** — authenticate → validate → tenant-scoped Drizzle query → map → respond. No business logic or shape knowledge in the handler. - **Auth**: call `authenticateApiKey(req, "")` from `lib/api-auth.ts`. **Every** query MUST be scoped by `ctx.practiceId` and filter `isNull(table.deletedAt)` — a cross-tenant read is a security bug. - **Mappers**: `lib/compat//mappers.ts` holds **pure** functions that translate internal rows ↔ the target's shapes (enum crosswalks, date formats). The target's request/response shapes live in `lib/compat//schema.ts`. - **A new target** (e.g. an existing PIMS's public API) is a new `lib/compat//` module plus an `app/api/compat//v1/` namespace — the auth, pagination, and error helpers are shared. Every endpoint ships with mapper unit tests **and** a contract test (`schema.parse(toApiX(row))`) so internal changes can't silently break the public contract. ## Good first issues New here? These are scoped, self-contained, and well-tested — great first PRs. Comment on the matching [issue](https://github.com/evangauer/openvpm/issues) (or open one) to claim it. - **Expand the drug dosing formulary** — add drugs with species-specific reference ranges to `apps/web/lib/dosing/formulary.ts`. Data-only, fully unit-tested (`apps/web/lib/dosing/__tests__/`). Keep ranges conservative and cite a source. - **Drag-to-reschedule on the calendar** — the `appointments.reschedule` API already exists with conflict checking; wire it into the schedule UI. - **Appointment waitlist UI** — build a staff-facing list on the existing tenant-scoped schema and tRPC router. - **CSV import review UX** — deepen the existing Settings → Data flow with clearer row-level validation and issue resolution for supported import types. - **Embeddable booking widget** — an iframe/script version of the client-portal booking flow (`apps/web/app/portal/[token]/book`). Want to help but unsure where to start? Open a [Discussion](https://github.com/evangauer/openvpm/discussions) and say hello. ## License By contributing, you agree that your contributions will be licensed under the GNU AGPLv3.