# Cross Events Hub Joshua's central management app for every **Cross Events** install: customers, licences, install health and usage, and alerts. Customers never log in here. > **Naming:** Cross Events was called **Hope Events** until October 2026. Older commits, the > `hope-events` repo name and the `hel1.` licence-token prefix still use the old name. The > prefix is part of the protocol, so it stays. - `backend/` — Express + Prisma (Postgres) API, port 5200 - `frontend/` — Next.js dashboard, port 3200 - `docs/hub-protocol.md` — the contract with Cross Events installs (a copy lives in the `hope-events` repo; change both together) Installs only ever call the Hub (register, heartbeat); the Hub never reaches into an install and holds no church data — just versions, health and aggregate counts. ## Run it locally Needs Node 20+ and Postgres. ```bash cd backend cp .env.example .env # set DATABASE_URL, JWT_SECRET, HUB_ENCRYPTION_KEY npm install npx prisma migrate deploy && npx prisma generate npm run generate-keys # licence signing key → keys/hub-signing-key.pem npm run create-admin -- --email you@example.com --name "Your Name" npm run dev # http://localhost:5200 cd ../frontend cp .env.example .env.local # NEXT_PUBLIC_API_URL=http://localhost:5200 npm install npm run dev # http://localhost:3200 ``` The first login sets up two-factor with an authenticator app (required). To try it with Cross Events locally, point the install at the Hub with `HUB_URL=http://localhost:5200` and `HUB_PUBLIC_KEY` (the public key shown in Hub → Settings) in Cross Events' `backend/.env`. ## The licence signing key Licences are tokens signed with an Ed25519 key. **The private key exists only on the Hub server**; installs check licences with the public key, which is built into Cross Events (`backend/src/hub/publicKey.js`). - Create the production key once, on the Hub server: `npm run generate-keys`. Back up `keys/hub-signing-key.pem` somewhere safe and offline. - Put the public key it prints into Cross Events (`backend/src/hub/publicKey.js`) and release. - Losing or replacing the key means every install needs a Cross Events update with the new public key before it can trust new licences — so don't. - `HUB_ENCRYPTION_KEY` encrypts install secrets: it must never change after installs register. ## Deploying Same pattern as Cross Events: on the server (`events-hub.crosscode.co.za`), behind nginx with HTTPS, two PM2 processes (`backend`: `npm start`; `frontend`: `npm run build && npm start`), `TRUST_PROXY=1`, `FRONTEND_URL=https://events-hub.crosscode.co.za`, and the frontend's `NEXT_PUBLIC_API_URL` set to the public API address (e.g. `https://events-hub.crosscode.co.za` with nginx routing `/api` to port 5200). Back up the database daily, plus the signing key. ## Tests `cd backend && npm test` — encryption, licence tokens, request signatures, two-factor codes (RFC 6238 vector) and alert rules.