Skip to content

Repository files navigation

MedHistory

Personal and family medical-records app with patient and doctor experiences.

Patients organize folders and files (labs, imaging, prescriptions), track doctors, appointments, and medications, manage family members, and share a view-only health summary with a clinician via a short-lived code/QR. Doctors redeem that code and browse linked patients without write access.

Piece Location
Backend API Repo root (com.example.medhistroy)
Frontend SPA MedHistory/
Compose stack docker-compose.yml

Artifact / folder name is medhistroy (historical spelling). Product name is MedHistory.


Screenshots

Patient UI previews. Links open the full-size PNGs (faster than embedding huge blobs inline).

Screen Full size
Dashboard 1.png
Records 2.png
Profile & settings 3.png
Timeline 4.png

Dashboard

Dashboard — medical summary, stats, meds, uploads, pinned folders

Home overview: medical summary card, folder/file/doctor/visit counts, today’s medicines, recent uploads, and pinned folders.

Records

Records — folder grid with type filters

Folder grid with type filters (lab, prescription, dental, …), pin status, doctor, and file counts.

Profile & settings

Profile — health info, language, theme menu

Profile, health fields, push reminders, language (8 locales), and light/dark/system theme.

Timeline

Timeline — appointments by year with notes and follow-ups

Chronological visits with notes, prescriptions, linked folders, follow-ups, and specialty filters.


Tech stack

Layer Stack
Backend Java 21, Spring Boot 4.1, Web MVC, Security (stateless), Data JPA, Maven
Auth Custom HS256 JWT (JwtService), BCrypt passwords
Database MySQL 8.4 (runtime); H2 (tests)
Files Disk under uploads/ (DB stores relative path only)
Frontend Vue 3, Vite, Pinia, Vue Router, Vue I18n, Tailwind CSS 4
Infra Docker multi-stage builds; nginx serves SPA and proxies /api

Architecture

Browser
  ├─ Local: Vite → http://localhost:8081/api
  └─ Docker: :8090 nginx (SPA) + /api → backend:8081
                    │
                    ▼
             Spring Boot :8081
                    │
         JwtAuthFilter (Bearer or ?token=)
                    │
         Controllers + AccessService
                    │
         MySQL  ◄── JPA entities / seed JSON
         Disk   ◄── FileStorageService (/app/uploads)
  • JSON is snake_case end-to-end (spring.jackson.property-naming-strategy=SNAKE_CASE).
  • Frontend client: MedHistory/src/api/index.jsAuthorization: Bearer <jwt>.
  • <img> / <iframe> previews append ?token= because they cannot set headers.
  • On 401, the client clears session and routes to login.

Access model

Authorization is app-level (AccessService), not Spring roles:

Capability Who
Write Self + family members you own
Read Write set + patients with an ACTIVE doctor link
Doctor links View-only — never grant write

Two different “doctor” concepts:

  1. Doctor entity — patient’s care-provider contact (address book).
  2. User.role = doctor — clinician account that redeems share codes.

Features & implementation

Auth & accounts

Feature Backend Frontend
Login / register AuthController (/api/auth/*), BCrypt, roles patient | doctor LoginView, RegisterView, medStore.login/register
JWT session JwtService + JwtAuthFilter; secret JWT_SECRET / app.jwt.secret localStorage: med_token, med_user_id
Forgot password ForgotPasswordView (UI stub only)

Patient app

Feature Backend Frontend
Dashboard Aggregates via existing list APIs DashboardView
Member switcher Scope by userId / access checks MemberSwitcher; setActiveMember refreshes caches
Family members FamilyController — create managed User + FamilyRelation FamilyView, AddMemberSheet
Profile + photo UserController CRUD + photo upload/stream ProfileView, EditProfileSheet
Health summary User fields (blood, allergies, conditions, meds) SummaryView, SummaryCard
Share with doctor DoctorLinkController — 8-char code, ~15 min TTL, PENDING→ACTIVE/EXPIRED/REVOKED ShareWithDoctorSheet (QR), doctor redeems via RedeemCodeSheet
Doctor contacts DoctorController DoctorsView, DoctorDetailView, AddDoctorSheet
Record folders FolderController (type / doctor filters; cascade file delete) RecordsView, FolderDetailView, CreateFolderSheet
File upload / preview FileController multipart + /content stream; max 25MB file / 30MB request UploadSheet, FilePreviewSheet (XHR progress)
Appointments / timeline AppointmentController TimelineView, LogAppointmentSheet
Medications MedicationController; dose times in medication_times MedicinesView, AddMedicineSheet
Dose “taken” / notifications — (client-derived) NotificationsView; dismissals in localStorage
Search SearchController — LIKE over doctors / folders / files SearchViewmedStore.search
i18n + theme settings store; locales en, bn, ar, fr, es, hi, zh, pt; light/dark/system

Doctor app

Feature Backend Frontend
Doctor home GET /api/doctor-links/patients DoctorHomeView
Redeem share code POST /api/doctor-links/redeem RedeemCodeSheet
View patient records Same read APIs under viewable access Records / summary / etc. with active patient context

Seed / demo data

DataSeeder loads src/main/resources/seed/*.json when the users table is empty.

  • Demo password for all seeded users: demo1234
  • Example patient: atiqur.itc@gmail.com
  • Example doctor: see seed/users.json / seed/doctor_patient_links.json (pre-linked ACTIVE where configured)

Domain entities

Entity Table Role
User users Account + profile; role; blood/allergies; emergency contact; conditions/meds lists
FamilyRelation family_relations Owner ↔ managed member
Doctor doctors Contact doctor for a member
Folder folders Record folder (type, dates, pin, file count)
MedFile files File metadata; storagePath on disk
Appointment appointments Visits, notes, follow-up, optional linked folder
Medication medications Schedule + dosage
DoctorPatientLink doctor_patient_links Share codes / view grants

Most extend Auditable (created_at / updated_at).


API surface

Base URL: http://localhost:8081 (or same-origin /api behind nginx).

Public

  • POST /api/auth/login
  • POST /api/auth/register
  • GET /api/test
  • GET / — API status map

Authenticated (JWT)

Prefix Notes
/api/users List viewable users; CRUD; photo upload/get/delete
/api/family List / create relation / create member / delete
/api/doctors CRUD; list by userId
/api/folders CRUD; filter userId, type, doctorId
/api/files POST /upload, GET /{id}/content, list by folder/user, CRUD
/api/appointments CRUD; list by userId or doctorId
/api/medications CRUD; list by userId
/api/search q, userId, optional scope (all | doctors | folders | files)
/api/doctor-links Share code, redeem, list links/patients, revoke

CORS allows localhost / 127.0.0.1 with credentials for local Vite.


Project layout

medhistroy/
├── docker-compose.yml          # mysql + backend + frontend
├── Dockerfile                  # Spring Boot image
├── .env.example
├── pom.xml
├── src/main/java/...           # API, security, services, models
├── src/main/resources/
│   ├── application.properties
│   └── seed/                   # Demo JSON
├── uploads/                    # Local file storage (gitignored)
└── MedHistory/                 # Vue SPA
    ├── Dockerfile
    ├── nginx.conf              # SPA + /api reverse proxy
    ├── package.json
    └── src/
        ├── api/                # HTTP client
        ├── stores/             # Pinia (medStore, settings)
        ├── views/              # Pages
        ├── components/
        ├── router/
        └── i18n/

Run with Docker (recommended)

Prereqs: Docker Desktop (daemon running).

cd /path/to/medhistroy
cp .env.example .env          # optional; edit secrets
docker compose up --build
Service Host URL / port
Frontend (UI) http://localhost:8090
Backend API http://localhost:8081
MySQL localhost:3310 → container 3306

Stop:

docker compose down

Wipe DB + uploads volumes:

docker compose down -v

Compose wires:

  • Backend waits until MySQL is healthy.
  • Frontend build bakes VITE_API_URL=/api; nginx proxies /api/backend:8081.
  • Uploads persist in volume backend_uploads/app/uploads.

Run locally (without Docker)

Prerequisites

  • Java 21
  • MySQL 8.x with database medhistory (or rely on createDatabaseIfNotExist)
  • Node.js compatible with MedHistory/package.json (Vite 8 / Node 22+ recommended)

Backend

Default application.properties expects:

  • URL: jdbc:mysql://localhost:3306/medhistory?...
  • User: root
  • Password: empty
./mvnw spring-boot:run
# API → http://localhost:8081

Override as needed:

export SPRING_DATASOURCE_URL='jdbc:mysql://localhost:3310/medhistory?createDatabaseIfNotExist=true&serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false'
export SPRING_DATASOURCE_PASSWORD=medhistory
export JWT_SECRET='your-long-secret'
./mvnw spring-boot:run

Tests (H2, no MySQL):

./mvnw test

Frontend

cd MedHistory
npm install
npm run dev

API base defaults to http://localhost:8081/api. Override:

VITE_API_URL=http://localhost:8081/api npm run dev

Useful scripts: npm run build, npm run preview, npm run test:unit, npm run lint.


Environment variables

Variable Used by Purpose
MYSQL_ROOT_PASSWORD Compose MySQL + backend Root / datasource password (default medhistory)
JWT_SECRET Backend JWT HMAC secret (override in production)
SPRING_DATASOURCE_URL Backend JDBC URL
SPRING_DATASOURCE_USERNAME Backend DB user
SPRING_DATASOURCE_PASSWORD Backend DB password
VITE_API_URL Frontend build API base (/api in Docker; full URL in local Vite)

Also in application.properties:

  • server.port=8081
  • app.upload-dir=uploads
  • app.jwt.expiration-ms (default 24h)
  • Multipart limits 25MB / 30MB

Copy .env.example.env next to docker-compose.yml for Compose. Vite does not read that file for npm run dev.


Demo login

After first boot with an empty DB (seed runs automatically):

Role Email Password
Patient atiqur.itc@gmail.com demo1234
Doctor dr.farhana@example.com demo1234
Other seeded users src/main/resources/seed/users.json demo1234

Notes / known gaps

  • Forgot-password is frontend-only; no reset API yet.
  • Medication “taken today” and notification dismissals are client-side only.
  • Family members created via /api/family/members are managed profiles (may not be full login accounts).
  • Change JWT_SECRET and MySQL password before any shared/production deploy.

About

Save your personal or doctors patients all Medical Records in one place and managed their medicine times

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages