Dentify is a multi-tenant dental clinic management system. This repository contains the frontend (React + TypeScript + Vite), which consumes the Dentify backend API (Java Spring Boot).
Status: actively in development. APIs, folder structure, and conventions may still change. This is a portfolio/learning project also being built collaboratively.
- Overview
- Tech Stack
- Features
- Project Structure
- Getting Started
- Authentication & Roles
- Payments (Mercado Pago)
- Testing
- Deployment
- Contributing
- Roadmap
- License
Dentify helps dental clinics manage patients, appointments, medical histories, products/inventory, and payments from a single dashboard. The frontend is a single-page application built with React 19 and Vite, using role-based access (dentist vs. secretary) and a centralized HTTP client that talks to the Dentify backend.
This repo is the client only. All business logic, database access, and most configuration/secrets live in the backend repository.
| Layer | Choice |
|---|---|
| UI library | React 19 |
| Language | TypeScript + JavaScript (mixed, migrating toward TS) |
| Build tool | Vite 7 |
| Routing | React Router DOM v7 |
| Styling | Tailwind CSS v4 |
| HTTP client | Axios (centralized instance with JWT refresh) |
| Charts | Recharts |
| UI primitives | Radix UI, Lucide icons |
| Animation | Framer Motion |
| Linting | ESLint 9 |
- Role-based dashboards for dentists and secretaries
- Patient management and medical history (create/edit, complementary exams)
- Appointment scheduling (turnos) and admission flow
- Product/inventory management
- Payments module with Mercado Pago Checkout Pro integration
- JWT-based authentication with automatic token refresh (single-flight, no duplicate refresh calls on concurrent 401s)
dentify-frontend/
├─ src/
│ ├─ api/ # HTTP layer
│ │ ├─ apiClient.js # Central Axios instance (base URL, JWT refresh interceptor)
│ │ ├─ authError.js
│ │ ├─ authService.js
│ │ ├─ dashboardService.js
│ │ └─ login.js
│ │
│ ├─ pages/
│ │ ├─ agendas/ # Calendar / schedule views
│ │ ├─ auth/
│ │ │ ├─ invitation/ # Invite-based registration (dentist / secretary)
│ │ │ ├─ login/
│ │ │ ├─ AuthContext.jsx # Auth state + role (DENTIST / SECRETARY)
│ │ │ ├─ useAuth.js
│ │ │ ├─ ProtectedRoute.jsx
│ │ │ ├─ RoleProtectedRoute.jsx
│ │ │ └─ Unauthorized.jsx
│ │ ├─ dashboard/
│ │ ├─ dentist/ # Dentist-specific layout
│ │ ├─ medicalHistory/ # Medical history CRUD + complementary exams
│ │ ├─ patients/
│ │ ├─ payments/ # Mercado Pago flow, income chart, summaries
│ │ ├─ products/
│ │ ├─ sidebar/
│ │ └─ turnos/ # Appointments (create, detail, admission)
│ │
│ ├─ App.jsx # Route wrappers (WithUserProfile, CrearTurnoRouteWrapper, etc.)
│ ├─ App.css
│ ├─ home.jsx
│ └─ main.jsx
│
├─ index.html
├─ vite.config.js
├─ tailwind.config.js
├─ postcss.config.js
├─ eslint.config.js
├─ package.json
└─ README.md
Routing convention: each protected feature is wrapped in a dedicated route wrapper component in App.jsx (e.g. WithUserProfile, CrearTurnoRouteWrapper), which injects shared context/props before rendering the page.
Housekeeping: the top-level
js/folder (api/dashboardService.js,pages/login.js) is unused legacy — safe to delete..agentsis also unused.files-dentify-guideis kept intentionally as an internal reference guide. Also double checkdist/andnode_modules/are covered by.gitignoreand never committed.
- Node.js 20+ and npm
- The Dentify backend running locally (see below) — this frontend does not work standalone, it needs a live API to talk to.
git clone <this-repo-url>
cd dentify-frontend
npm installsrc/api/apiClient.js already reads the backend URL from import.meta.env.VITE_API_BASE_URL (falling back to http://localhost:8008 if unset) — it just needs a local .env file to exist, since .env is gitignored and not committed.
-
Create a
.envfile at the project root:VITE_API_BASE_URL=http://localhost:8008/api
-
Restart
npm run devafter creating/changing it — Vite only reads.envon startup. -
.env.example(committed, no real values needed here since there's nothing sensitive) documents the expected variable name for anyone cloning the repo — see the one included.
Important: all sensitive configuration (database credentials, JWT secret, Mercado Pago access token/public key, etc.) lives exclusively in the backend repository's
application.properties/ environment. This frontend never needs, stores, or ships secrets — it only needs to know the backend's URL, which can differ per developer (e.g. a different local port).
This frontend needs the Dentify backend running to do anything useful. Recommended local setup:
- Clone and run the backend separately (it has its own
Dockerfile; if usingdocker-compose, bring up the API + database there). - Point this frontend at it via
VITE_API_BASE_URLin your local.env. - Run the frontend natively with
npm run dev— don't Dockerize the frontend for local development, Vite's hot-module-reload is faster and simpler outside a container. Docker for the frontend only makes sense for a production build (multi-stage:npm run build→ serve the static output with nginx).
This keeps the two repos independently deployable and lets each contributor use their own backend instance/config without touching frontend code.
| Script | Description |
|---|---|
npm run dev |
Start the Vite dev server with hot reload |
npm run build |
Type-check and build for production |
npm run lint |
Run ESLint |
npm run preview |
Preview the production build locally |
Authentication is JWT-based, managed through AuthContext.jsx and useAuth.js. Two roles are supported:
- DENTIST
- SECRETARY
Routes are guarded with ProtectedRoute.jsx (must be logged in) and RoleProtectedRoute.jsx (must have a specific role); unauthorized access falls back to Unauthorized.jsx. apiClient.js centralizes an Axios instance with an interceptor that refreshes the JWT on 401 responses using a single-flight pattern, so concurrent requests don't trigger multiple refresh calls.
The payments module (src/pages/payments/) integrates Mercado Pago Checkout Pro to let clinics charge patients for appointments. The frontend triggers payment creation against the backend endpoint that generates the personalized Checkout Pro link; payment confirmation is handled via a webhook on the backend side.
No automated tests exist yet for the frontend. Planned:
- Component/unit tests (Vitest + React Testing Library, to match the Vite setup)
- Coverage for auth guards and the Axios refresh-token flow first, since they gate everything else
Not deployed yet — the project is still in active/experimental development with a second contributor onboarding. A live demo link will be added here once a first stable version is deployed (Vercel is a natural fit for a Vite + React static build).
See CONTRIBUTING.md for local setup notes if you're joining this project.
- Add automated tests (Vitest)
- Migrate remaining
.jsxfiles to.tsx - First deploy (Vercel) + live demo link
- Update backend Dockerfile and document a combined
docker-composefor full-stack local dev
TBD.