Deployed application system
MartialXPro
A tournament management platform for martial arts organisations, documented here through its data model, application workflows and current deployment path.
martialxpro.com ↗
The problem
The product is designed around a tournament workflow that was split across spreadsheets, message groups and paper: registration; classification by age, weight and belt; fixture generation; result tracking; certificates; and ID cards.
The platform separates responsibilities across three access roles: admin, organiser and player.
System architecture
The current deployment uses one Ubuntu host: Nginx accepts requests and proxies them to a PM2-supervised Node.js and Express API, which reads and writes PostgreSQL through Prisma. This keeps the operational surface small; host-level redundancy and horizontal scaling remain future work.
Runtime configuration comes from environment variables, allowing the same code to be deployed without environment-specific edits.
Data model
The core model is relational: an organisation owns tournaments; tournaments contain categories; and registrations connect players to the categories they enter. Fixture generation, reports and analytics all depend on those same relationships.
Schema changes are managed as Prisma migrations, versioned alongside the code, so the database state is reproducible rather than hand-edited.
Authentication and access control
Sessions are JWT-based, and authorisation is role-based access control across three roles:
- AdminPlatform-level control across organisations.
- OrganiserRuns tournaments for their own organisation.
- PlayerRegisters and competes.
Route middleware resolves role and ownership context before a handler runs. Centralising that logic keeps route declarations consistent and avoids duplicating checks inside individual handlers.
What the platform does
Implemented in the current product:
Designed; implementation in progress:
Deployment and operations
I use PM2 process logs and Nginx access and error logs to diagnose application, proxy and routing failures on the host. PM2 is configured to restart the API after process failure and host reboot.
The scale-out plan covers EC2 in a custom VPC, IAM-scoped access, S3 for generated documents and CloudWatch for visibility. The AWS case study documents the labs behind that plan.
What broke, and what it taught me
These failures changed how I sequence migrations, centralise access checks, set file ownership and diagnose the deployed service.
Prisma migrations drifting from production
Schema changes that applied cleanly in development did not always land cleanly against a database holding real tournament data. Resolving migration state without dropping and reseeding the production database changed how I sequence schema changes and was the single most instructive part of the project.
Authentication and role resolution edge cases
With three role types and organisations owning their own tournaments, 'is this user allowed to do this' is not a single check. Token handling, role resolution and ownership checks all had to agree, and the failures were the quiet kind that return the wrong data rather than an error.
PostgreSQL behaviour underneath the ORM
The ORM hides the database until it doesn't. Connection handling and query behaviour on relational reads had to be understood at the SQL level, not just the Prisma level, before some issues made sense.
Linux permissions between deploy user and process user
The account that deploys the code and the account that runs it are not the same, and file ownership, log directories and environment file access all have to reflect that. Classic Linux administration, and it only surfaces in production.
Nginx reverse proxy configuration
Getting upstream routing, forwarded headers and the split between proxied API traffic and static content correct, so the application sees the request it expects rather than the one Nginx rewrote.
Debugging against a live server
Some failures appeared only on the deployed host. PM2 and Nginx logs, process state, file ownership and proxy behaviour became the primary evidence for isolating them.