Skip to content

Backend Setup

Overview

The backend target is a REST API built with Node.js and Express, deployed on Railway with a MySQL database. It is publicly accessible over HTTPS — providing a realistic remote API target for the mobile application to communicate with.


Architecture

Layer Responsibility
Controller HTTP request handling and routing
Service Business logic and authorization
Repository Database queries
Middleware Authentication, validation, error handling

Deployment on Railway

Clone the project repository — this contains both the Flutter frontend and Node.js backend:

git clone https://github.com/irsyad521/todo-app

Screenshot 1


1. Create a Railway Account

Sign up at https://railway.com — Railway provides $5 free credit and handles SSL certificate provisioning automatically. The domain and its certificate are relevant later: the Flutter app implements SSL pinning against the deployed Railway domain, so the certificate fingerprint discovered during static analysis maps directly back to whatever Railway provisions here.

Screenshot 3


2. Install Railway CLI and Login

Follow the installation guide at https://docs.railway.com/cli, then authenticate:

railway login -b

This opens a browser prompt with a confirmation code.

Screenshot 4

Screenshot 5

Screenshot 6

Verify authentication:

railway whoami

Screenshot 7


railway init    # enter project name: todo-app-backend-deploy
railway link    # select the project just created

Screenshot 8


4. Add MySQL Database

railway add --database mysql    # provision MySQL service
railway status                  # verify services in project
railway variables               # inspect MySQL connection variables

Screenshot 9

Confirm the database is reachable:

railway connect mysql

Screenshot 10


5. Add and Configure API Service

From inside the todo-app-backend directory, create the API service:

railway add --service api

Set the required environment variables:

railway variables set \
  ADMIN_TOKEN=supersecret \
  APP_MODE=production \
  DB_HOST='${{MySQL.MYSQLHOST}}' \
  DB_NAME='${{MySQL.MYSQLDATABASE}}' \
  DB_PASSWORD='${{MySQL.MYSQLPASSWORD}}' \
  DB_PORT='${{MySQL.MYSQLPORT}}' \
  DB_USER='${{MySQL.MYSQLUSER}}' \
  JWT_EXPIRES_IN=1d \
  JWT_SECRET=b81ad2d4fb8486295dd500b0317e3d43c02b9627c6e947e63cf13081355b4d2f \
  NODE_ENV=production \
  PORT=3000

Screenshot 11

Verify the variables are applied:

railway variables

Screenshot 12


6. Deploy

railway up

Railway builds and deploys the Docker image. Once complete, the API is live on port 3000.

Screenshot 13

Screenshot 14

Both services — API and database — are now running and connected.

Screenshot 15


7. Generate Public Domain

The API is running but not yet publicly accessible. Generate a domain and provision the SSL certificate:

railway domain

Screenshot 16

The domain Railway generates here is what gets hardcoded into the Flutter app's SSL pinning configuration.

Access the domain in a browser to confirm the deployment is live.

Screenshot 17


8. Enable Serverless Mode

To minimize credit usage, both services can be set to auto-sleep mode.

Railway's serverless option is an auto-sleep mechanism — not serverless in the Lambda sense. Services sleep after ~10 minutes of inactivity and wake on the next incoming request. The first request after sleep will have a cold start delay. Services with active connections won't enter sleep.

Screenshot 18

The backend is now deployed and ready to serve as the API target for the Flutter application.