Induty is an incident management and on-call scheduling platform built on a microservices architecture.
Each service is independent, has its own database, and can be deployed separately.
| Service | Port | Description | README |
|---|---|---|---|
| auth | 8001 |
Registration, login, JWT issuance | → |
| teams | 8002 |
Team and member management | → |
| incidents | 8003 |
Incident creation, statuses, comments | → |
| schedules | 8004 |
On-call schedules, shifts, on-call lookup | → |
| gateway | 8000 |
Reverse proxy to other microservices | → |
Authentication service. Handles user registration, issues access_token (JWT) and refresh_token.
All other services verify the JWT signature using a shared JWT_SECRET.
Team management. Allows creating teams, adding members, and assigning roles (owner / member).
The team creator automatically becomes the owner. Only the owner or a global admin can manage the team.
Regular users receive the viewer role and can be added to a team by an admin or team owner.
Incident lifecycle management with states: open → acknowledged → resolved.
Any team member, regardless of role, can manage incidents — assign them, add comments, etc.
Only the team owner or a global admin can delete an incident.
On-call scheduling. Supports one or more named-shift schedules per team.
Provides an endpoint to query the current on-call person by schedule or by team.
Reverse proxy that routes public API requests to the appropriate microservices.
The backend is built with Go + Gin framework. All logs are emitted as structured JSON.
The frontend is React + Vite, served by nginx.
The incidents and schedules services communicate with the teams service over mTLS (HTTP) via internal /internal paths that are not exposed to the frontend or gateway.
- Docker 24+
- Docker Compose v2+
Use the install.sh script in the repository root.
It generates mTLS certificates and starts docker-compose.yml.
Before running, you can create a .env file from the provided example:
cp .env.example .envOr just run the installer — it will copy .env.example → .env automatically if .env is missing:
bash install.sh
# or
make installAfter a successful installation you will see:
─────────────────────────────────────────
Induty is running 🚀
─────────────────────────────────────────
Frontend : http://localhost
Gateway : http://localhost:8000
Admin credentials
Email : admin@example.com
Password : <pass>
─────────────────────────────────────────
make # show help
make install # first-time setup
make up # start services (no rebuild)
make down # stop services
make restart # down + up
make re # full reset: down -v + rm certs + install
make build # rebuild all images
make build-svc SERVICE=auth # rebuild a single service
make test # run all Go tests
make test-svc SERVICE=teams # test a single service
make logs # follow all logs
make logs-svc SERVICE=gateway
make certs # generate certs (skips if already exist)
make certs-regen # force regenerate certs
make clean # down -v + rm certs
make ps # container statusAfter the first launch, the admin creates teams via the UI or API (see each service's README for API docs).
Users are then created with a temporary password. Future team owners receive the owner role at the team level.
When creating a user, the "Require password change on first login" checkbox can be enabled — the user will be prompted to set a new password before accessing the dashboard.
Team owners manage their own teams: adding members, creating on-call schedules, etc.
Each service reads its own config.yaml. Any field can be overridden by an environment variable.
JWT_SECRET=change-me-in-production
# auth
INDUTY_AUTH_PORT=8001
INDUTY_AUTH_DATABASE_DSN=host=postgres user=induty password=secret dbname=induty_auth port=5432 sslmode=disable
INDUTY_AUTH_JWT_SECRET=${JWT_SECRET}
# teams
INDUTY_TEAMS_PORT=8002
INDUTY_TEAMS_DATABASE_DSN=host=postgres user=induty password=secret dbname=induty_teams port=5432 sslmode=disable
INDUTY_TEAMS_JWT_SECRET=${JWT_SECRET}
INDUTY_TEAMS_INTERNAL_ADDR=:8443
INDUTY_TEAMS_SERVER_CERT_FILE=/certs/server.crt
INDUTY_TEAMS_SERVER_KEY_FILE=/certs/server.key
INDUTY_TEAMS_CACERT_FILE=/certs/ca.crt
# incidents
INDUTY_INCIDENTS_PORT=8003
INDUTY_INCIDENTS_DATABASE_DSN=host=postgres user=induty password=secret dbname=induty_incidents port=5432 sslmode=disable
INDUTY_INCIDENTS_JWT_SECRET=${JWT_SECRET}
INDUTY_INCIDENTS_TEAMS_SERVICE_URL=https://teams:8443
INDUTY_INCIDENTS_CLIENT_CERT_FILE=/certs/client.crt
INDUTY_INCIDENTS_CLIENT_KEY_FILE=/certs/client.key
INDUTY_INCIDENTS_CA_CERT_FILE=/certs/ca.crt
# schedules
INDUTY_SCHEDULES_PORT=8004
INDUTY_SCHEDULES_DATABASE_DSN=host=postgres user=induty password=secret dbname=induty_schedules port=5432 sslmode=disable
INDUTY_SCHEDULES_JWT_SECRET=${JWT_SECRET}
INDUTY_SCHEDULES_TEAMS_SERVICE_URL=https://teams:8443
INDUTY_SCHEDULES_CLIENT_CERT_FILE=/certs/client.crt
INDUTY_SCHEDULES_CLIENT_KEY_FILE=/certs/client.key
INDUTY_SCHEDULES_CA_CERT_FILE=/certs/ca.crt
# gateway
INDUTY_GATEWAY_PORT=8000
INDUTY_GATEWAY_JWT_SECRET=${JWT_SECRET}
INDUTY_GATEWAY_READ_TIMEOUT=30s
INDUTY_GATEWAY_WRITE_TIMEOUT=30s
INDUTY_GATEWAY_AUTH_URL=http://auth:8001
INDUTY_GATEWAY_TEAMS_URL=http://teams:8002
INDUTY_GATEWAY_INCIDENTS_URL=http://incidents:8003
INDUTY_GATEWAY_SCHEDULES_URL=http://schedules:8004