Development and Testing
Requirements
- Node.js 20+ (the Docker image uses Node 22).
- npm.
- Docker and Docker Compose for PostgreSQL, or SQLite for a quick local run.
python3,makeandg++only ifbetter-sqlite3needs to build from source.
Local setup
git clone https://git.emilyh.de/Emily/UniversalGamingApp-Backend.git
cd UniversalGamingApp-Backend
npm ci
cp .env.example .env
For a quick SQLite run, set a development secret and leave PostgreSQL variables empty:
NODE_ENV=development
JWT_SECRET=development-only-secret-at-least-32-characters
DATABASE_PATH=./data/accounts.db
CORS_ORIGINS=*
REQUEST_LOGGING=true
npm run dev
curl http://127.0.0.1:6767/healthz
For PostgreSQL, use Compose:
docker compose up -d db
# Point POSTGRES_* at 127.0.0.1:5432 for a host-run Node process.
npm run dev
Or run the full stack:
docker compose up -d --build
Scripts
| Command | Purpose |
|---|---|
npm start |
Run the server |
npm run dev |
Run with Node's watch mode |
npm test |
Run the full test suite |
node src/migrate.js |
Apply PostgreSQL migrations and exit |
Test suite
npm test
npm audit --omit=dev
At release 1.4.0:
- 45 tests pass.
npm audit --omit=devreports 0 vulnerabilities.
The tests use an in-memory SQLite database and do not need PostgreSQL, SMTP or network access. HTTP calls to the release feed are mocked.
Test files
| File | Focus |
|---|---|
test/accounts.test.js |
Registration, login, profile, leaderboard, chess, releases, CORS, management |
test/config.test.js |
Defaults, SMTP TLS inference, URL validation, proxy parsing, database URL encoding |
test/mailer.test.js |
Port 465 vs STARTTLS ports, auto-correction, transport options |
test/migrations.test.js |
Migration ordering, baseline schema, reset/session migration |
test/password_reset.test.js |
Confirmed-address requirement, anti-enumeration, reset flow, missing SMTP |
test/passwords.test.js |
Full-length passwords beyond 72 bytes, legacy hash upgrade |
test/request_logging.test.js |
Client IP logging and query-string stripping |
Run one file:
node --test test/password_reset.test.js
Adding an endpoint
- Add validation helpers near the top of
src/app.js. - Add the route inside
createApp(). - Use
authfor protected routes. - Use
asyncHandlerand throwHttpErrorfor expected failures. - Add database methods to both the PostgreSQL and SQLite implementations in
src/db.js. - Add a test to
test/accounts.test.jsor a focused file. - Document the endpoint in API Reference.
- Bump the version and update the changelog.
Adding a migration
- Append the next integer version to
POSTGRES_MIGRATIONSinsrc/migrations.js. - Keep statements idempotent.
- Never edit an already released migration.
- Add a test in
test/migrations.test.js. - Run against a disposable PostgreSQL database.
- Deploy with
./update.sh, which takes a pre-update backup.
Configuration changes
src/config.js merges defaults with the environment and validates:
JWT_SECRETlength.PUBLIC_BASE_URLandAPP_PUBLIC_URLschemes.TRUSTED_PROXIESentries.- SMTP TLS mode.
- Numeric ranges for TTLs, bcrypt rounds, ports and cache time.
Invalid configuration exits at startup with a clear message. Add a test in test/config.test.js for every new variable.
Versioning
Update the version in:
package.jsonsrc/config.js(version)src/app.js(User-Agent)docker-compose.ymldefault image tagREADME.mdupdate.shif it references a version.env.exampleif it references an image tag
Then commit and tag:
git tag v1.4.0
git push origin main --tags
Release process
npm testnpm audit --omit=dev- Build the image.
- Push
X.Y.Zandlatestto the Gitea registry. - Create a Gitea release with notes.
- Deploy with
./update.sh. - Verify
/healthz,/api/v1/meta, a login and a leaderboard read. - Confirm migrations and data are intact.
- Copy a post-update dump off-host.
docker build -t git.emilyh.de/emily/universal-gaming-backend:1.4.0 .
docker tag git.emilyh.de/emily/universal-gaming-backend:1.4.0 \
git.emilyh.de/emily/universal-gaming-backend:latest
docker push git.emilyh.de/emily/universal-gaming-backend:1.4.0
docker push git.emilyh.de/emily/universal-gaming-backend:latest
CI
The repository may include a Forgejo/Gitea workflow. Jobs remain queued if the instance has no registered Actions runner. Until a runner is available, run the test suite locally and publish images manually.
Code style
- ES modules, Node 20+.
- Async/await throughout.
- Throw
HttpError(status, message)for expected client errors. - Do not log secrets, bodies, tokens or e-mail addresses.
- Keep database access behind
src/db.js. - Keep chess validation in
src/chess.jsand leaderboard validation insrc/leaderboard.js.
Universal Gaming Accounts
- Home
- Deployment
- Configuration
- API Reference
- Database and Migrations
- Security
- Operations
- Development and Testing
- Troubleshooting
Repositories
The accounts backend is optional. Universal Gaming remains fully playable offline without it.