Skip to content

Abdi-github/rhne-node-api

Repository files navigation

RHNe API — Réseau Hospitalier Neuchâtelois

REST API for the RHNe (Réseau hospitalier neuchâtelois) hospital network platform, built with Node.js, Express 5, TypeScript, MongoDB, and Redis.

Features

  • 7 hospital sites, 93 medical services, 138 doctors, events, jobs, newborns, patient info
  • Multi-language content (FR, EN, DE, IT) with TranslatedField pattern
  • JWT authentication with access + refresh tokens
  • Role-Based Access Control — 5 roles, 39 granular permissions
  • Full-text search across all resources
  • Redis caching on all public endpoints
  • Image upload via Multer + Cloudinary
  • Email via Nodemailer (Mailpit in dev)
  • Zod validation on all endpoints
  • Soft delete pattern with is_active flag
  • Standardized API response envelope

Tech Stack

Area Technology
Runtime Node.js 20+
Language TypeScript 5 (strict)
Framework Express.js 5
Database MongoDB 7 (Mongoose 8)
Cache Redis 7
Auth JWT (access + refresh)
Validation Zod
File Uploads Multer + Cloudinary
Email Nodemailer
Testing Jest + Supertest
Containers Docker + Docker Compose

Quick Start

Prerequisites

  • Node.js 20+ and npm
  • Docker and Docker Compose

1. Clone & Install

git clone <repo-url>
cd rhne-node-api
npm install

2. Environment Configuration

cp .env.example .env

Edit .env with your settings. Key variables:

NODE_ENV=development
PORT=5000
MONGODB_URI=mongodb://admin:password@localhost:27017/rhne?authSource=admin
REDIS_HOST=localhost
REDIS_PORT=6379
JWT_ACCESS_SECRET=your-access-secret
JWT_REFRESH_SECRET=your-refresh-secret

3. Start Infrastructure

# Start MongoDB, Redis, Mailpit, Mongo-Express
docker compose up -d
Service URL
MongoDB localhost:27017
Redis localhost:6379
Mailpit (email UI) http://localhost:8025
Mongo-Express http://localhost:8081

4. Seed the Database

npm run seed         # Insert seed data (skip duplicates)
npm run seed:fresh   # Drop all collections, then seed

Seeds 1,493 records across 15 collections.

5. Start the API

npm run dev          # Development with hot-reload

API available at: http://localhost:5000/api/v1


NPM Scripts

Script Description
npm run dev Start dev server (ts-node-dev, hot-reload)
npm run build Compile TypeScript → dist/
npm start Run compiled JS from dist/
npm run seed Seed database
npm run seed:fresh Drop & re-seed database
npm test Run Jest test suite
npm run test:watch Run tests in watch mode
npm run lint Lint with ESLint
npm run lint:fix Auto-fix lint issues
npm run docker:dev Start Docker containers
npm run docker:down Stop Docker containers
npm run docker:logs Tail API container logs

API Endpoints

Public (No Auth)

GET    /api/v1/sites                    # List active sites
GET    /api/v1/sites/:slug              # Get site by slug
GET    /api/v1/services                 # List services (?category=, ?search=)
GET    /api/v1/services/:slug           # Get service with contacts, links, doctors
GET    /api/v1/doctors                  # List doctors (?service=, ?search=)
GET    /api/v1/doctors/:id              # Get doctor detail
GET    /api/v1/events                   # List upcoming events
GET    /api/v1/events/:slug             # Get event detail
GET    /api/v1/jobs                     # List active jobs (?category=, ?site=)
GET    /api/v1/jobs/:id                 # Get job detail
GET    /api/v1/newborns                 # List newborns (paginated)
GET    /api/v1/patient-info             # List patient info pages (?section=)
GET    /api/v1/patient-info/:slug       # Get page with sections
GET    /api/v1/search?q=...            # Full-text search

Auth

POST   /api/v1/auth/login              # Login → access + refresh tokens
POST   /api/v1/auth/refresh            # Refresh access token
POST   /api/v1/auth/logout             # Revoke refresh token
POST   /api/v1/auth/forgot-password    # Request password reset email
POST   /api/v1/auth/reset-password     # Reset password with token

Admin (Auth + RBAC required)

GET    /api/v1/admin/dashboard/stats    # Dashboard statistics
GET    /api/v1/admin/profile            # My profile
PUT    /api/v1/admin/profile            # Update my profile
PUT    /api/v1/admin/profile/password   # Change password

# Full CRUD on all resources:
# /admin/sites, /admin/services, /admin/doctors,
# /admin/events, /admin/jobs, /admin/newborns,
# /admin/patient-info, /admin/users
# + /admin/services/:id/contacts, /admin/services/:id/links

POST   /api/v1/admin/uploads/images    # Upload image

Query Parameters

Param Type Description
page number Page number (default: 1)
limit number Items per page (default: 20, max: 100)
sort string Sort field (prefix - for desc)
search string Full-text search
lang string Language: fr, en, de, it
is_active boolean Filter by status (admin only)

Response Format

// Success
{
  "success": true,
  "message": "Sites retrieved successfully",
  "data": [ ... ],
  "pagination": { "page": 1, "limit": 20, "total": 7, "totalPages": 1 }
}

// Error
{
  "success": false,
  "message": "Site not found",
  "error": { "code": "NOT_FOUND", "details": [] }
}

Authentication

  1. Login → POST /api/v1/auth/login with { email, password }
  2. Returns access_token (15min) and refresh_token (7 days)
  3. Use access token: Authorization: Bearer <token>
  4. Refresh when expired: POST /api/v1/auth/refresh with { refresh_token }

Roles & Permissions

Role Description
super_admin Full platform access
admin Platform administration
content_editor Manage services, events, patient info
hr_manager Manage job postings
site_manager Manage a specific hospital site

Permissions follow resource.action format (e.g., sites.read, services.create).


Test Accounts

Email Password Role
superadmin@rhne-clone.ch SuperAdmin123! super_admin
admin@rhne-clone.ch Admin123! admin
editor@rhne-clone.ch Editor123! content_editor
hr@rhne-clone.ch HrManager123! hr_manager
pourtales.manager@rhne-clone.ch Manager123! site_manager
chauxdefonds.manager@rhne-clone.ch Manager123! site_manager

Testing

npm test              # Run all tests (77 integration tests)
npm run test:watch    # Watch mode

Tests use a separate rhne_test database. Requires MongoDB and Redis running.

Test coverage:

  • Auth: login, refresh, logout, forgot/reset password (16 tests)
  • Public API: sites, services, doctors, events, jobs, newborns, patient info, search, health, language (34 tests)
  • Admin API: auth protection, RBAC, dashboard, CRUD, profile (27 tests)

Project Structure

src/
├── config/                 # DB, Redis, env, CORS, i18n, Cloudinary, mail
├── api/v1/
│   ├── public/             # Public routes (no auth)
│   │   ├── auth/           # Login, refresh, logout, password reset
│   │   ├── sites/          # Hospital sites
│   │   ├── services/       # Medical services
│   │   ├── doctors/        # Medical professionals
│   │   ├── events/         # Public events
│   │   ├── jobs/           # Job postings
│   │   ├── newborns/       # Birth announcements
│   │   ├── patient-info/   # Patient information pages
│   │   └── search/         # Full-text search
│   └── admin/              # Admin routes (auth + RBAC)
│       ├── dashboard/      # Statistics
│       ├── profile/        # Current user profile
│       ├── sites/          # Sites CRUD
│       ├── services/       # Services CRUD + contacts/links
│       ├── doctors/        # Doctors CRUD
│       ├── events/         # Events CRUD
│       ├── jobs/           # Jobs CRUD
│       ├── newborns/       # Newborns CRUD
│       ├── patient-info/   # Patient info CRUD
│       ├── users/          # Users CRUD + role assignment
│       └── uploads/        # Image upload
├── models/                 # 16 Mongoose models
├── middleware/             # Auth, RBAC, validation, error, cache, rate-limit
├── shared/                 # Utils, types, constants
├── scripts/                # Database seeder
├── __tests__/              # Integration tests
├── app.ts                  # Express app
└── server.ts               # Server entry point

Each feature module follows the pattern:

feature/
├── feature.routes.ts       # Route definitions
├── feature.controller.ts   # Request handling (thin)
├── feature.service.ts      # Business logic
└── feature.validation.ts   # Zod schemas

Multi-Language Support

All user-facing text uses the TranslatedField pattern:

{ fr: "Cardiologie", en: "Cardiology", de: "Kardiologie", it: "Cardiologia" }

Language is determined by:

  1. ?lang=fr query parameter
  2. Accept-Language: fr header
  3. Default: fr (French)

API Documentation (Postman)

Import the collection and environment into Postman:

File Description
postman/RHNe-API.postman_collection.json Full collection — all public + admin endpoints
postman/RHNe-API.postman_environment.json Development environment variables

Usage:

  1. Import both files into Postman
  2. Select the RHNe — Development environment
  3. Run Auth → Login (Super Admin) — tokens are saved automatically
  4. All admin requests inherit the Bearer token from the collection

Docker

docker compose up -d          # Start all services
docker compose down           # Stop all services
docker compose logs -f api    # Tail API logs

Services: MongoDB, Redis, Mailpit (email testing), Mongo-Express (DB admin).


License

Private — All rights reserved.

About

HR management platform API — Express + TypeScript + MongoDB

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages