OMP Server is the Node.js/TypeScript REST API powering the OMP admin panel — an internal tool for the MOONZ video streaming service. It orchestrates offer and plan management across Recurly, GhostLocker, PlayAuth, Contentful, and more while persisting state in MySQL.
- Tech Stack
- Prerequisites
- Getting Started
- Available Scripts
- Project Structure
- API Reference
- Environment Variables
- Testing
- Deployment
| Layer | Technology |
|---|---|
| Runtime | Node.js 12.18+ · TypeScript (CommonJS) |
| Framework | Express 4 · express-async-handler |
| Database | MySQL 2 · Sequelize 6 · sequelize-typescript |
| Auth | External JWT endpoint · bcrypt |
| Real-time | Socket.IO 3 (health-status-update events) |
| HTTP Client | Axios · p-retry |
| AWS | S3 · CloudFront · Secrets Manager · STS |
| Integrations | Recurly · Contentful · GhostLocker · PlayAuth · Bamboo · Slack |
| Logging | Winston · winston-daily-rotate-file · Splunk |
| Validation | express-validator 6 |
| Migrations | Umzug 2 |
| Testing | Jest · ts-jest |
| Package Manager | Yarn |
| Config | @dotenvx/dotenvx (.env file or process.env) |
| API Docs | Swagger UI at /api-docs |
- Node.js 12.18.0+ — Download
- Yarn — Install
- MySQL —
brew install mysql(macOS) or install via your OS package manager - Global dev tools:
yarn global add typescript nodemon ts-nodeVerify TypeScript is available: tsc -v
cp .env.development .env
# Then open .env and fill in your local valuesSee Environment Variables for a full reference.
yarn installRun the SQL init scripts against your local MySQL instance:
mysql -u <user> -p <db_name> < db/db_init.sql
mysql -u <user> -p <db_name> < db/db_android_init.sql
mysql -u <user> -p <db_name> < db/db_roku_init.sql# Development (ts-node, with --inspect for debugger on port 5858)
yarn start
# Development with file watching (auto-restart)
yarn start:watch
# Production (compiled JS)
yarn build && yarn serveThe API will be available at http://localhost:1337 by default. Interactive API docs are at http://localhost:1337/api-docs.
| Script | Description |
|---|---|
yarn start |
Start via ts-node (dev, inspector on :5858) |
yarn start:watch |
Start with nodemon file watching |
yarn build |
Compile TypeScript to dist/ |
yarn serve |
Run compiled output from dist/ |
yarn test |
Run all Jest tests |
yarn test:int |
Run integration tests only |
yarn lint |
Type-check + ESLint auto-fix |
yarn clean |
Remove compiled output |
yarn download-logs:aws-dev |
Download logs from the dev AWS environment |
yarn download-logs:aws-prod |
Download logs from the prod AWS environment |
src/
├── app.ts # Express app factory — registers routers, middleware, Swagger
├── server.ts # HTTP + Socket.IO bootstrap
├── start.ts # Entry point
├── controllers/ # Route handler logic (thin, delegates to services/utils)
│ ├── offers/ # Offer CRUD, publish, validate, draft, sync, history
│ ├── plans/ # Plan CRUD
│ ├── android/ # Android module controllers
│ ├── roku/ # Roku module controllers
│ └── dpe/ # Dynamic Pricing Engine controllers
├── routers/ # Express Router definitions (HTTP method → controller)
├── services/ # External system integrations (Recurly, Contentful, S3, …)
├── models/ # Sequelize model factories
│ ├── android/ # Android-specific models
│ ├── roku/ # Roku-specific models
│ └── web/ # Web-platform models
├── middleware/ # Express middleware (errors, validation, logging, auth)
├── types/ # TypeScript interfaces and domain enums
├── util/ # Shared utilities (config, logger, error classes, helpers)
└── validators/ # express-validator chains for each domain
http://localhost:1337
| Method | Path | Description |
|---|---|---|
| GET | /health |
Liveness probe |
| GET | /ping |
Readiness probe |
| GET | /db/wipe |
(dev only) Drop all tables |
| GET | /db/init |
(dev only) Re-initialize DB from db_init.sql |
| Method | Path | Description |
|---|---|---|
| POST | /users/login |
Login — returns a JWT |
| GET | /users/logout |
Invalidate current session |
Login payload:
{
"email": "admin@example.com",
"password": "yourpassword"
}| Method | Path | Description |
|---|---|---|
| GET | /api/offers?brand=moonz®ion=us&store=web |
List all offers |
| GET | /api/offers/:offerCode |
Get a single offer |
| POST | /api/offers/save |
Save offer as draft |
| POST | /api/offers/create |
Save and publish offer |
| PUT | /api/offers/:offerCode |
Update an offer |
| DELETE | /api/offers/:offerCode |
Delete an offer |
| GET | /api/offers/:offerCode/validate |
Validate offer against external systems |
| GET | /api/offers/:offerCode/publish |
Publish offer to all systems |
Save/create payload example:
{
"offerCode": "ompsinglefixedsave",
"offerTypeId": 2,
"offerCodeType": "single",
"planCode": "qamonthlynft",
"offerHeader": "OMP-SINGLE-FIXED-SAVE",
"offerBodyText": "Single Fixed Body",
"offer": "price",
"offerPrice": 5.99,
"offerDurationType": "customize",
"offerDurationValue": 3,
"offerDurationUnit": "day",
"publishDateTime": "2020-07-20T01:00:00Z",
"noEndDate": false,
"endDateTime": "2020-10-30T13:00:00Z"
}| Method | Path | Description |
|---|---|---|
| GET | /api/plans?brand=moonz®ion=us&store=web |
List all plans |
| GET | /api/plans/:planCode |
Get a single plan |
| POST | /api/plans/save?brand=moonz®ion=us&store=web |
Save plan as draft |
| POST | /api/plans/create?brand=moonz®ion=us&store=web |
Save and publish plan |
| PUT | /api/plans/:planCode |
Update a plan |
| DELETE | /api/plans/:planCode |
Delete a plan |
| GET | /api/plans/:planCode/publish |
Publish plan to all systems |
Save/create payload example:
{
"planCode": "ompmonthlynft",
"planName": "OMP Test Plan",
"price": 8.99,
"billingCycle": "month",
"trialOffer": "none"
}| Mount Path | Description |
|---|---|
/api/android |
Android module CRUD + publish (SKUs, App Copy, Store Copy, Campaigns, Images) |
/api/roku |
Roku module CRUD + publish |
/api/offertypes |
Offer type lookup |
/api/stores |
Store list and hierarchy |
/api/status |
Status lookup table |
/api/states |
US state data |
/api/roles |
User roles lookup |
/api/uploadImage |
Image upload to S3 |
/api/validator |
Offer/plan uniqueness validation |
/api/translations |
Store translations |
/api/slack |
Slack bot config |
/api/dezmund |
Dezmund content metadata proxy |
/api/dpe |
Dynamic Pricing Engine config |
/api/tardis |
Tardis connection check |
/api/filters |
CancelFlow 2 retention filters |
/api/tokens |
External service token management |
/api-docs |
Swagger UI (interactive API documentation) |
Copy .env.development to .env and fill in values for your environment.
| Variable | Description |
|---|---|
EXPRESS_PORT |
HTTP server port (default: 1337) |
NODE_ENV |
Environment: local, dev, qa, or prod |
DB_NAME / DB_USER / DB_PASSWORD / DB_HOST |
MySQL connection |
AUTHENTICATION_ENDPOINT |
External JWT auth service base URL |
RECURLY_* |
Recurly API keys per store/environment |
CONTENTFUL_* |
Contentful space/env/API key per store |
GHOSTLOCKER_* / CONFIGLOCKER_* |
GhostLocker host and credentials |
PLAYAUTH_STG / PLAYAUTH_PROD |
PlayAuth base URLs |
BAMBOO_REST_ENDPOINT / BAMBOO_SVC_USER_ID / BAMBOO_SVC_USER_PWD |
Bamboo CI/CD credentials |
ANDROID_BUCKET_NAME / ROKU_BUCKET_NAME |
S3 bucket names for image storage |
TARDIS_BASE_URL / TARDIS_API_VERSION |
Tardis resource API |
SLACK_* |
Slack API tokens |
LOG_LEVEL / LOG_FOLDER / LOG_FILE |
Winston logging config |
SPLUNK_ADMIN_PASSWORD |
Splunk forwarder admin password (used by run.sh entrypoint) |
CONSTELLATION_API_ENDPOINT |
Constellation CMS API endpoint template (token-formatted URL) |
CONSTELLATION_PROD_ID / CONSTELLATION_DEV_ID |
Route identifiers substituted into CONSTELLATION_API_ENDPOINT |
DISABLE_ROLLBACK |
Set true to disable rollback on publish failure |
FUZZ_ERROR_PROBABILITY |
Dev-only: random error injection probability (0–100) |
# Run all tests
yarn test
# Run integration tests only
yarn test:intTests are located in test/. The main test files are:
test/app.test.ts— Integration tests against the servertest/cmsapi.test.ts— CMS API service tests
Tests can occasionally fail due to external service latency. If a test fails, try running that file individually. Common causes:
- Slow API response — Jest global timeout is 60 000 ms. Override per test:
}, 100000) - Sequelize auth switch — Usually transient; re-run the file alone
- 504 from AWS cache clear — Re-run the file alone
- GhostLocker busy — Re-run the file alone
The service is containerized with Docker and deployed to AWS ECS (Fargate). The run.sh entrypoint configures the Splunk forwarder before starting the Node process.
# Build Docker image
docker build -t omp-server .
# Run with Docker Compose (local)
docker-compose up