Imported from RSUD-ABDUL-AZIZ-UNOFFICIALLY/khanza-API (
AGENTS.md). Install upstream withnpx skills add RSUD-ABDUL-AZIZ-UNOFFICIALLY/khanza-API. Copyright stays with the author.
Khanza-API: Hospital Management System
Project Overview
Khanza is a comprehensive Hospital Information System (SIMRS) API built with Node.js/Express that manages all aspects of hospital operations. The system handles patient registration, outpatient/inpatient care, medical records, billing, insurance claims, and clinical documentation in compliance with Indonesian healthcare standards (BPJS, InaCBG).
Stack: Node.js 20 + Express.js + Sequelize ORM + MariaDB + Redis + JWT + PM2
Version: 1.4.8
Author: Fakhry
License: ISC
Architecture at a Glance
┌─────────────────────────────────────────┐
│ Express REST API (port 3000) │
│ (/api/ranap, /api/ralan, /api/icd ...) │
└──────────────┬──────────────────────────┘
│
┌───────┴────────────┬───────────────┐
│ │ │
┌───▼──┐ ┌───▼──┐ ┌───▼────┐
│Routes│ │ Auth │ │ Cache │
│ (9) │ │ (JWT)│ │(Redis) │
└───┬──┘ └──────┘ └────────┘
│
┌───▼────────────────┐
│ Controllers (11) │ ◄── Business Logic
└───┬────────────────┘
│
┌───▼────────────────────────┐
│ Models (45+ Sequelize) │ ◄── ORM Entities
│ + Associations │
└───┬────────────────────────┘
│
┌───▼──────────────┐
│ MariaDB │
│ (Hospital Data) │
└──────────────────┘
Domain Model (Hospital Entities)
The API organizes data around 9 hospital domains:
1. Patient Management (/api/registrasi, /api/ralan)
pasien- Patient master recordsreg_periksa- Medical visit registrationsbooking_periksa,booking_registrasi- Appointment bookingpengumuman_epasien- E-patient announcements
2. Outpatient Care (/api/ralan)
pemeriksaan_ralan- Outpatient examination recordsjns_perawatan- Treatment typesdiagnosa_pasien- Diagnosis linked to patients
3. Inpatient Care (/api/ranap)
kamar_inap- Inpatient roomsdpjp_ranap- Attending physician assignmentspemeriksaan_ranap- Inpatient examinationsbooking_operasi- Operating room booking
4. Facilities & Staff (/api/petugas)
bangsal- Wards/Departmentspoliklinik- Clinicskamar- Room masterspegawai- Employeespetugas- Staff assignmentsdokter- Physiciansspesialis- Medical specialistsjadwal- Doctor schedules
5. Billing & Insurance (/api/ranap, internal)
penjab- Insurance providers (Umum, BPJS, etc.)billing- Billing transactionsbridging_sep- BPJS SEP bridgingbridging_surat_kontrol_bpjs- BPJS control letters
6. Clinical Documentation
berkas_digital_perawatan- Digital care filesmaster_berkas_digital- Digital file templatessurat_pernyataan_pasien_umum*- Patient statementssurat_persetujuan_*- Medical consent forms
7. Medical Coding (/api/icd)
icd10,icd9- International disease classificationspenyakit- Disease masterkategori_penyakit- Disease categories
8. Supportive Services (/api/penunjang)
jns_perawatan_lab- Laboratory test typesjns_perawatan_radiologi- Radiology procedure typestemplate_laboratorium- Lab result templates
9. Dashboard & Analytics (/api/dashboard)
- Aggregated views for hospital metrics
- Performance indicators
API Endpoint Structure
URI Pattern
/api/{module}/{resource}
No version numbering in URLs. Breaking changes managed through backward compatibility or parallel endpoints.
Modules & Key Routes
| Module | Endpoints | Purpose |
|---|---|---|
/api/ranap |
belumpulang, listberkas, ruangan |
Inpatient management |
/api/ralan |
daftarperiksa, poli, kasir |
Outpatient management |
/api/registrasi |
bookingperiksa, bookingdokter |
Patient registration |
/api/icd |
ICD search & validation | Medical coding |
/api/petugas |
Staff CRUD, schedules | Workforce management |
/api/penunjang |
Lab/imaging procedures | Ancillary services |
/api/dashboard |
Metrics, reports | Hospital analytics |
/api/views |
Read-only queries | Reporting views |
/api/inacbg |
InaCBG claims | Insurance bridging |
Response Format (Unified)
{
status: true | false, // Success indicator
message: "String description", // Human-readable status
data: { /* payload */ }, // Main response body
record?: number, // Count of records (optional)
queryParam?: { /* echo */ } // Original query params (optional)
}
Authentication & Authorization
JWT-Based Auth
- Tokens: Bearer token in
Authorizationheader - Payload: Contains
kd_access[]array with role identifiers - Secret:
JWT_SECRET_KEYfrom environment - Middleware: All protected routes use
middleware.check
Role Levels (lvid)
| Level | Role | Usage |
|---|---|---|
1 |
Admin | Full system access |
3 |
Doctor (Dokter) | Medical records, prescriptions |
| Other | Staff | Department-specific access |
Middleware Application
app.get('/api/ranap/sensitive-data', middleware.check, controllerFunction);
// Token validated via middleware.check before reaching controller
Key Conventions & Patterns
1. Database: Sequelize ORM
- Auto-loading: Models in
/modelsdirectory auto-discover and associate - Associations: One-to-Many, Many-to-Many pre-configured
- Queries: Heavy use of Sequelize operators (
Op.between,Op.like,Op.in) - Include patterns: Nested associations for rich data fetches
- Example:
// models/pasien.js Pasien.hasMany(RegPeriksa, { foreignKey: 'no_rkm_medis' }); RegPeriksa.belongsTo(Pasien, { foreignKey: 'no_rkm_medis' });
2. Controllers: Direct Data Access
- Business logic embedded directly in controllers
- One controller per domain (e.g.,
ralan.js,ranap.js) - No dedicated service layer
- Pattern:
exports.getNamaFungsi = async (req, res) => { try { const data = await Model.findAll({ /* query */ }); return res.json({ status: true, message: 'OK', data }); } catch (e) { return res.status(500).json({ status: false, message: e.message }); } };
3. Encryption Patterns (Mixed)
- JWT: Authentication tokens
- MySQL AES-256-CBC: Password storage in database (via
user.jshelper) - Custom AES: E-Klaim/InaCBG API payloads signed for external integrations (via
encryption.jshelper) - No bcrypt: Raw MySQL encryption used for legacy compatibility
4. Caching with Redis
- Redis client connected at startup
- Attached to every request:
req.cache - Developers manually implement cache logic in controllers
- Pattern:
const cached = await req.cache.get('key'); if (cached) return res.json(JSON.parse(cached)); // Fetch from DB, cache result
5. Error Handling
- No global error handler middleware - each controller has try-catch
- Console logging - errors logged to stdout
- No structured logging - consider adding Winston/Pino for production
- Status codes: 200 (success), 400 (validation), 401 (auth), 404 (not found), 500 (server error)
6. Helpers Provide Domain Logic
| Helper | Domain |
|---|---|
encryption.js |
Encryption for external APIs (InaCBG, e-Klaim) |
user.js |
Password operations, user queries |
beds.js |
Bed occupancy calculations, date-range logic |
api.js |
External integrations (LPKP docs, claims) |
kalkulator.js |
Domain-specific calculations (rates, metrics) |
index.js |
Utilities like getCurrentTime() |
7. Cache Folder Structure
/cache/bangsal/- Ward cache/cache/dpjp/- Attending physician cache- Used for static/frequently-accessed data
Development Setup
Prerequisites
- Node.js: 20.x (Alpine-based in Docker)
- MariaDB: 10.x (or compatible MySQL)
- Redis: 4.x+
- PM2: Process manager (installed via npm)
Environment Variables (Required)
NODE_ENV=development|production
PORT=3000
# Database
DB_USERNAME=root
DB_PASSWORD=secret
DB_NAME=simrs_khanza
DB_HOST=localhost
DB_DIALECT=mariadb
# Security
JWT_SECRET_KEY=your-secret-key
JWT_SECRET_KEY_LPKP=your-lpkp-secret
# Redis
REDIS_URL=localhost
REDIS_URL_PORT=6379
REDIS_PASSWORD=redis-pass
# External APIs
URL_BPJS=https://bpjs.gov.id/api
HOST_API_LPKP=https://lpkp-api.gov.id
INACBG_UrlWS=https://inacbg.gov.id/ws
INACBG_keyRS=your-hospital-key
Running Locally
# Install dependencies
npm install
# Setup database (Sequelize migrations)
npx sequelize-cli db:migrate
# Development mode
node index.js
# or with auto-restart (install nodemon first)
npx nodemon index.js
# Production with PM2
pm2 start ecosystem.config.js
Docker Deployment
# Build image
docker build -t khanza-api:latest .
# Run with docker-compose
docker-compose up
Docker Setup (Dockerfile):
- Base:
node:20-alpine - Port:
3000 - Process Manager: PM2
- Volumes: Shared document storage (configured in
docker-compose.yml)
Common Development Tasks
Adding a New API Endpoint
- Create or extend a model in
models/(if needed) - Add controller method in
controllers/{domain}.js - Register route in
routes/{domain}.js:router.get('/endpoint-name', middleware.check, Controller.methodName); - Return unified response format (see Response Format above)
Adding a New Database Model
- Create file in
models/following Sequelize conventions - Import in
models/index.js(auto-discovery handles associations) - Run
npx sequelize-cli db:migrateto apply schema changes
Integrating with External API (BPJS, InaCBG)
- Add integration in
helpers/api.jsor new helper file - Use
encryption.jsfor payload signing/verification - Store credentials in environment variables
- Add error handling for timeout/validation failures
Adding Authentication to an Endpoint
// In routes/{domain}.js
router.get('/protected-route', middleware.check, Controller.method);
// middleware.check validates JWT in Authorization header
Implementing Caching
// In controller
const cacheKey = `entity-${id}`;
let data = await req.cache.get(cacheKey);
if (!data) {
data = await Model.findByPk(id);
await req.cache.setEx(cacheKey, 3600, JSON.stringify(data)); // 1 hour TTL
}
Important Files & Entry Points
| File | Purpose |
|---|---|
| index.js | Server startup, middleware setup, route registration |
| package.json | Dependencies, scripts, project metadata |
| config/config.js | Database connection config (Sequelize) |
| Dockerfile | Container image definition |
| ecosystem.config.js | PM2 process configuration |
| models/index.js | ORM initialization, auto-association |
| middleware/index.js | Auth & cross-cutting concerns |
| helpers/encryption.js | Encryption/decryption for external APIs |
| .env | Environment variable template |
External Integrations
BPJS (Indonesian Social Security Insurance)
- Purpose: Insurance claim submission and validation
- Models:
bridging_sep,bridging_surat_kontrol_bpjs - Helper: See
api.jsandencryption.js - Env Vars:
URL_BPJS,JWT_SECRET_KEY_LPKP
InaCBG (Indonesian Case-Based Grouping)
- Purpose: Hospital claims grouping by diagnosis & procedure
- Models:
maping_poli_bpjs,referensi_mobilejkn_bpjs* - Helper:
encryption.js(API payload signing) - Env Vars:
INACBG_UrlWS,INACBG_keyRS
ICD-10/ICD-9 Coding
- Purpose: Medical diagnosis/procedure standardization
- Models:
icd10,icd9,penyakit - Routes:
/api/icd
Best Practices for This Codebase
- Always use try-catch in controllers and return proper HTTP status codes
- Validate JWT before accessing sensitive data - use
middleware.check - Cache frequently-accessed data via
req.cachewith appropriate TTLs - Follow the unified response format - consistency is key for frontend integration
- Use Sequelize operators (
Op.*) for complex queries, not raw SQL - Store secrets in environment variables, never hardcode
- Log important operations (auth failures, API calls) to console (plan to upgrade to structured logging)
- Test encryption/decryption with BPJS/InaCBG before production deployment
- Document domain-specific logic - healthcare business rules can be subtle
- Run migrations before deploying schema changes
Troubleshooting Guide
| Issue | Cause | Solution |
|---|---|---|
Redis connection refused |
Redis service not running | Start Redis: redis-server |
Database connection failed |
Wrong credentials or host | Check .env and MariaDB running |
JWT validation failed |
Expired/invalid token | Request new token from /api/auth or equivalent |
Encryption error in InaCBG calls |
Wrong signature key | Verify INACBG_keyRS in .env |
Port 3000 already in use |
Another process on port | Change PORT env var or kill existing process |
Models not auto-loading |
Sequelize cache issue | Clear node_modules/.cache and restart |
Suggested Next Steps for AI Agents
When working with this codebase:
- Before adding features: Check if domain model already exists in
/models - For bug fixes: Verify JWT tokens are valid and Redis is connected
- For API additions: Mirror existing controller patterns for consistency
- For external API work: Review helpers to understand encryption requirements
- For deployment: Test environment variables match
Dockerfileexpectations
Questions or Customizations?
This document serves as a knowledge base for AI agents. Update it as:
- New integrations are added
- Architecture changes occur
- New conventions are established
- Troubleshooting patterns emerge