Checking API...

FlowCare API

Smart healthcare queue management and appointment booking. Built with Node.js, Express, PostgreSQL - fully Dockerized and production-ready.

26+
Endpoints
4
Auth Roles
7
DB Models
100%
Dockerized

How it's built

Four-layer stack with clean separation - HTTP routing, ORM, relational database, all containerized.

Runtime
Node.js
v18 LTS
Framework
Express
v4 + middleware
ORM
Sequelize
v6 + paranoid
Database
PostgreSQL
v15 + schemas
Containerized with Docker & Docker Compose - single command to run

Code Highlights

Key patterns from the implementation - auth middleware, audit logging, soft-delete hooks.

auth.middleware.js
audit.hook.js
appointment.model.js
rate-limit.js
// JWT authentication + role-based access control
const authenticate = async (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'Unauthorized' });

  const payload = jwt.verify(token, process.env.JWT_SECRET);
  const user = await User.findByPk(payload.id);
  if (!user || user.deletedAt) return res.status(401).json({ error: 'User not found' });

  req.user = user;
  next();
};

const authorize = (...roles) => (req, res, next) => {
  if (!roles.includes(req.user.role)) {
    return res.status(403).json({ error: 'Insufficient permissions' });
  }
  next();
};

// Usage: router.delete('/staff/:id', authenticate, authorize('admin', 'manager'), handler)
// Automatic audit logging via Sequelize hooks
const createAuditLog = async (instance, action, req) => {
  await AuditLog.create({
    userId:     req?.user?.id,
    action,
    entityType: instance.constructor.name,
    entityId:   instance.id,
    before:     instance._previousDataValues || null,
    after:      instance.dataValues,
    ipAddress:  req?.ip,
    userAgent:  req?.headers['user-agent'],
  });
};

// Attach to every model that needs auditing
[Appointment, Staff, Slot, Service].forEach(Model => {
  Model.afterCreate(async (inst) => await createAuditLog(inst, 'CREATE'));
  Model.afterUpdate(async (inst) => await createAuditLog(inst, 'UPDATE'));
  Model.afterDestroy(async (inst) => await createAuditLog(inst, 'DELETE'));
});
// Appointment model with queue management + soft deletes
const Appointment = sequelize.define('Appointment', {
  status: {
    type: DataTypes.ENUM('scheduled', 'checked_in', 'completed', 'cancelled', 'no_show'),
    defaultValue: 'scheduled'
  },
  queuePosition: DataTypes.INTEGER,
  notes:         DataTypes.TEXT,
  checkInTime:   DataTypes.DATE,
  completedTime: DataTypes.DATE,
}, {
  paranoid: true,  // soft deletes - sets deletedAt, never destroys rows
  hooks: {
    beforeCreate: async (appt) => {
      // Auto-assign queue position within the day
      const count = await Appointment.count({ where: { slotId: appt.slotId } });
      appt.queuePosition = count + 1;
    }
  }
});
// Rate limiting - 100 requests per 15 minutes per IP
import rateLimit from 'express-rate-limit';

export const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 100,
  standardHeaders: true,
  legacyHeaders: false,
  handler: (req, res) => res.status(429).json({
    error: 'Too many requests',
    retryAfter: Math.ceil(req.rateLimit.resetTime / 1000),
  }),
});

// Auth endpoints get stricter limits: 5 attempts / 15 min
export const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 });

26+ Endpoints

Full REST API covering auth, appointments, slots, staff, branches, services, and audit logs.

Live API Demo

Real requests to the live API - running on the production server. No mocks.

GETHealth Check

Verify the API is online and the database is connected

/health

GETList Branches

Fetch all clinic branches (Al Khuwair & Salalah seeded)

/api/branches

GETList Services

Browse available medical services with pricing

/api/services

GETAudit Logs

View the last 5 audit log entries with user/action tracking

/api/audit-logs?limit=5

Security & Features

Production-grade capabilities out of the box - not bolted on after.

🛡️
Rate Limiting
100 req / 15 min per IP
👥
4 Auth Roles
Admin · Manager · Staff · Customer
📚
Soft Deletes
30-day retention before purge
📋
Audit Logging
Every action tracked with CSV export
🏥️
2 Branches Seeded
Al Khuwair & Salalah ready to go
📥
File Uploads
Multer + type validation + size limits
📊
Queue Management
Auto-assigned position, check-in, no-show
⏱️
Slot Management
Bulk creation, conflict detection

Data Model

Seven models with clear relationships - Branch owns Staff, Slots, and Services. Customers book Appointments.

Branch name · address · phone Service name · duration · price Staff name · role · specialty Slot date · startTime · endTime Customer name · email · phone Appointment status · queuePosition · notes checkInTime · completedTime AuditLog action · userId · before/after has many has many has many books for service assigned in slot logs owns references