Skip to content

feat: CitrineOS production-grade Railway template (9 services)#2

Draft
cloudygetty-ai wants to merge 2 commits into
mainfrom
citrineos-railway-template
Draft

feat: CitrineOS production-grade Railway template (9 services)#2
cloudygetty-ai wants to merge 2 commits into
mainfrom
citrineos-railway-template

Conversation

@cloudygetty-ai

Copy link
Copy Markdown
Owner

Summary

  • Adds citrineos-railway/ — complete one-click Railway template for a production CitrineOS OCPP 2.0.1 EV charging stack
  • Deploys 9 services with all environment variables pre-wired via Railway ${{service.VAR}} cross-service references
  • Only the gateway service is publicly exposed; all databases and brokers are private-network only

Services

Service Image / Source Role
timescaledb timescale/timescaledb:latest-pg15 PostgreSQL + time-series meter data
rabbitmq rabbitmq:3.12-management-alpine OCPP event message bus
redis redis:7-alpine Cache for CitrineOS Core + Directus
citrineos-core ghcr.io/citrineos/citrineos-core:latest OCPP 2.0.1 CPMS
hasura hasura/graphql-engine:v2.40.0 GraphQL API over TimescaleDB
directus directus/directus:11 Headless CMS / admin UI
everest ghcr.io/everest/everest-demo:latest EV charging station simulator
extensions Custom Dockerfile (TypeScript/Node 20) Custom business logic service
gateway Custom Nginx 1.25 Dockerfile Public reverse proxy

Files

citrineos-railway/
├── railway.json          # Full template descriptor (all 9 services + vars)
├── docker-compose.yml    # Local dev (mirrors production topology)
├── .env.example
├── README.md
├── EXTENSIONS.md         # How to add new handlers and API routes
├── gateway/              # Nginx reverse proxy (public entry point)
└── extensions-service/   # TypeScript Node.js custom logic service

Test plan

  • docker compose up -d boots all services
  • curl http://localhost/health{"status":"ok"}
  • curl http://localhost/api/extensions/health → uptime JSON
  • Everest simulator connects to CitrineOS Core on startup
  • New handler file + registry entry routes OCPP events correctly

https://claude.ai/code/session_01FqEkDaad3jTipkfUGBCjpE


Generated by Claude Code

claude added 2 commits April 22, 2026 20:18
…eOS EV charging stack

Deploys 9 services simultaneously with private networking and pre-wired
environment variables:

Infrastructure (private):
  - TimescaleDB (PostgreSQL 15 + TimescaleDB) for meter time-series data
  - RabbitMQ 3.12 for OCPP event streaming
  - Redis 7 for caching

Application tier (private):
  - CitrineOS Core — OCPP 2.0.1 CPMS (HTTP :8080, WebSocket :8081)
  - Hasura GraphQL Engine v2.40 connected to TimescaleDB
  - Directus 11 CMS for CitrineOS data management
  - EVerest simulator for integration testing

Custom services (private):
  - Extensions Service — TypeScript/Node.js 20 app that consumes OCPP events
    from RabbitMQ and exposes a REST API for custom business logic
    (billing, loyalty, alerts). Handlers registered in src/handlers/index.ts.

Gateway (public — sole entry point):
  - Nginx 1.25 reverse proxy with envsubst-based runtime config
  - Routes: /api/graphql, /cms, /ocpp, /ocpp-ws, /api/extensions

Includes docker-compose.yml for local dev, .env.example, railway.json
template descriptor, railway.toml per service, and EXTENSIONS.md guide.

https://claude.ai/code/session_01FqEkDaad3jTipkfUGBCjpE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants