Lottery Backend
Spring Boot backend application for Lottery project.
Technology Stack
- Java 17
- Spring Boot 3.2.0
- MySQL 8.0 (using INT/BIGINT only, no floating point numbers)
- Flyway (database migrations)
- Docker (containerization)
- Maven (build tool)
Local Development
Prerequisites
- Java 17 JDK
- Maven 3.9+
- Docker and Docker Compose (for local MySQL)
Setup
-
Clone the repository
-
Start MySQL using Docker Compose:
docker-compose up -d db -
Create
.envfile (for local development):DB_NAME=lottery_db DB_USERNAME=root DB_PASSWORD=password DB_ROOT_PASSWORD=password TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here FRONTEND_URL=http://localhost:5173 -
Run the application:
mvn spring-boot:runOr build and run with Docker:
docker-compose up --build
Database Migrations
Flyway automatically runs migrations on startup. Migrations are located in src/main/resources/db/migration/.
Deployment Guides
Railway Deployment (Staging Environment)
Railway is the primary deployment platform for staging. It provides built-in logging and easy environment variable management.
Step 1: Create Railway Project
- Go to Railway and sign in
- Click "New Project"
- Select "Empty Project"
Step 2: Create MySQL Database Service
- In your Railway project, click "+ New" → "Database" → "Add MySQL"
- Railway will automatically create a MySQL database
- Note the connection details (you'll need them for the backend service)
Step 3: Create Backend Service
- In your Railway project, click "+ New" → "GitHub Repo" (or "Empty Service")
- If using GitHub:
- Connect your GitHub account
- Select the
honey-berepository - Railway will automatically detect it's a Java/Maven project
- If using Empty Service:
- Click "Empty Service"
- Connect to your repository or upload files
Step 4: Configure Environment Variables
In your backend service settings, go to "Variables" and add:
SPRING_DATASOURCE_URL=${MYSQL_URL}
SPRING_DATASOURCE_USERNAME=${MYSQLUSER}
SPRING_DATASOURCE_PASSWORD=${MYSQLPASSWORD}
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
FRONTEND_URL=https://your-frontend-url.railway.app
PORT=8080
Note: Railway automatically provides MYSQL_URL, MYSQLUSER, and MYSQLPASSWORD when you add a MySQL database. You can reference them using ${MYSQL_URL} syntax.
Step 5: Link Database to Backend
- In your backend service, go to "Settings" → "Connect"
- Find your MySQL database service
- Click "Connect" - Railway will automatically add the MySQL connection variables
Step 6: Configure Health Check
- In your backend service, go to "Settings" → "Healthcheck"
- Set Healthcheck Path to:
/actuator/health/readiness - Railway will poll this endpoint and wait for HTTP 200 before marking deployment as active
Step 7: Deploy
- Railway will automatically deploy when you push to the connected branch
- Or manually trigger deployment from the Railway dashboard
- Check the "Deployments" tab to monitor the deployment
Step 8: Get Backend URL
- In your backend service, go to "Settings" → "Networking"
- Click "Generate Domain" to get a public URL
- Or use the default Railway domain
- Copy the URL (e.g.,
https://lottery-be-production.up.railway.app)
Step 9: Create Frontend Service (Optional - if deploying frontend to Railway)
- In your Railway project, click "+ New" → "GitHub Repo"
- Select your
lottery-ferepository - Railway will detect it's a Node.js project
- Add environment variable:
VITE_API_BASE_URL=https://your-backend-url.railway.app - Railway will automatically build and deploy
Step 10: Create Volume (Optional - for persistent data)
If you need persistent storage:
- In your Railway project, click "+ New" → "Volume"
- Name it (e.g.,
lottery-data) - Mount it to your service if needed
Inferno Deployment (Production Environment)
Inferno Solution provides the production environment. It requires manual server setup and uses Docker Compose with nginx.
Prerequisites
- Access to Inferno Solution server (via SSH)
- Docker and Docker Compose installed on the server
- JDK 17 installed on the server (for building, though Docker handles runtime)
- Domain name configured (optional, for HTTPS)
Step 1: Prepare Server
-
SSH into your Inferno server:
ssh user@your-server-ip -
Install Docker (if not installed):
# For Ubuntu/Debian curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh sudo usermod -aG docker $USER -
Install Docker Compose (if not installed):
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose -
Install JDK 17 (for building):
# For Ubuntu/Debian sudo apt update sudo apt install openjdk-17-jdk -y -
Create project directory:
mkdir -p /opt/lottery cd /opt/lottery
Step 2: Clone Repository
cd /opt/lottery
git clone https://github.com/your-username/lottery-be.git
cd lottery-be
Step 3: Create Secret Configuration File
Create a tmpfs mount for secrets (more secure than .env files):
# Create tmpfs mount point
sudo mkdir -p /run/secrets
sudo chmod 700 /run/secrets
# Create secret file
sudo nano /run/secrets/lottery-config.properties
Add the following content (replace with your actual values):
SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/lottery_db
SPRING_DATASOURCE_USERNAME=lottery_user
SPRING_DATASOURCE_PASSWORD=your_secure_mysql_password
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
FRONTEND_URL=https://your-frontend-domain.com
MYSQL_PASSWORD=your_secure_mysql_password
MYSQL_ROOT_PASSWORD=your_secure_mysql_root_password
Important:
- Use strong, unique passwords
- Keep this file secure (it's in tmpfs, so it's in-memory only)
- The file will be lost on reboot - you'll need to recreate it or use a startup script
Step 4: Configure Docker Compose for Inferno
The docker-compose.inferno.yml file is already configured. Make sure it's present in your repository.
Step 5: Build and Start Services
cd /opt/lottery/lottery-be
# Build and start all services
docker-compose -f docker-compose.inferno.yml up -d --build
This will:
- Build the backend application
- Start MySQL database
- Start backend service
- Start nginx reverse proxy
Step 6: Configure Nginx (if using custom domain)
-
Edit nginx configuration:
nano nginx/conf.d/lottery.conf -
Update server_name (if using HTTPS):
server { listen 80; server_name your-domain.com; # ... rest of config } -
Reload nginx:
docker-compose -f docker-compose.inferno.yml restart nginx
Step 7: Set Up SSL (Optional - Recommended for Production)
-
Install Certbot (Let's Encrypt):
sudo apt install certbot python3-certbot-nginx -y -
Obtain SSL certificate:
sudo certbot --nginx -d your-domain.com -
Update nginx config to use HTTPS (uncomment HTTPS server block in
nginx/conf.d/lottery.conf) -
Reload nginx:
docker-compose -f docker-compose.inferno.yml restart nginx
Step 8: Configure Firewall
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow SSH (if not already allowed)
sudo ufw allow 22/tcp
# Enable firewall
sudo ufw enable
Step 9: Set Up Auto-Start on Boot
Create a systemd service to ensure services start on boot:
sudo nano /etc/systemd/system/lottery.service
Add:
[Unit]
Description=Lottery Application
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/lottery/lottery-be
ExecStart=/usr/local/bin/docker-compose -f docker-compose.inferno.yml up -d
ExecStop=/usr/local/bin/docker-compose -f docker-compose.inferno.yml down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
Enable the service:
sudo systemctl daemon-reload
sudo systemctl enable lottery.service
sudo systemctl start lottery.service
Step 10: Set Up Grafana Integration (Production Logging)
-
Install Grafana and Loki (on a separate server or same server):
# Follow Grafana/Loki installation guide # https://grafana.com/docs/loki/latest/installation/ -
Configure Promtail to collect logs from Docker containers:
# promtail-config.yml server: http_listen_port: 9080 grpc_listen_port: 0 positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: lottery-backend docker_sd_configs: - host: unix:///var/run/docker.sock refresh_interval: 5s relabel_configs: - source_labels: [__meta_docker_container_name] regex: lottery-backend action: keep -
Update docker-compose.inferno.yml to add logging driver:
app: # ... existing config logging: driver: "json-file" options: max-size: "10m" max-file: "3" -
Configure Grafana datasource to connect to Loki
Step 11: Monitor and Maintain
Check service status:
docker-compose -f docker-compose.inferno.yml ps
View logs:
# All services
docker-compose -f docker-compose.inferno.yml logs -f
# Specific service
docker-compose -f docker-compose.inferno.yml logs -f app
Update application:
cd /opt/lottery/lottery-be
git pull
docker-compose -f docker-compose.inferno.yml up -d --build
Backup database:
docker-compose -f docker-compose.inferno.yml exec db mysqldump -u lottery_user -p lottery_db > backup_$(date +%Y%m%d).sql
Configuration
Environment Variables
The application supports two configuration strategies:
- Environment Variables (Railway): Set variables in Railway dashboard
- Secret File (Inferno): Mount file at
/run/secrets/lottery-config.properties
Priority: Secret file → Environment variables
Required Variables
SPRING_DATASOURCE_URL- MySQL connection URLSPRING_DATASOURCE_USERNAME- MySQL usernameSPRING_DATASOURCE_PASSWORD- MySQL passwordTELEGRAM_BOT_TOKEN- Telegram bot token for authenticationFRONTEND_URL- Frontend URL for CORS configuration
Database Schema
The database uses INT and BIGINT only - no floating point numbers.
Current tables:
users- User information (id, telegram_id, username, created_at)
API Endpoints
Public Endpoints
GET /ping- Health check (no auth required)GET /actuator/health- Application healthGET /actuator/health/readiness- Readiness probe (checks database)GET /actuator/health/liveness- Liveness probe
Protected Endpoints (require Telegram auth)
GET /api/users/current- Get current user information
Authorization
The application uses Telegram Mini App authentication:
- Frontend sends
Authorization: tma <initData>header - Backend validates Telegram signature
- Backend creates/updates user in database
- User is stored in thread-local context for the request
Health Checks
- Readiness:
/actuator/health/readiness- Checks database connectivity - Liveness:
/actuator/health/liveness- Checks if application is running
Configure Railway to use /actuator/health/readiness as the health check path.
Logging
- Railway: Built-in logging available in Railway dashboard
- Inferno: Configure Grafana/Loki for log aggregation (see Grafana setup above)
Troubleshooting
Database Connection Issues
- Verify MySQL is running:
docker-compose ps - Check connection credentials in environment variables
- Review application logs for connection errors
Authorization Failures
- Verify
TELEGRAM_BOT_TOKENis correct - Check that frontend is sending
Authorization: tma <initData>header - Review backend logs for validation errors
Deployment Issues
- Check health check endpoint:
curl http://your-url/actuator/health/readiness - Review Railway deployment logs
- Verify all environment variables are set correctly
Development
Running Tests
mvn test
Building JAR
mvn clean package
Running Locally with Docker
docker-compose up --build
Project Structure
lottery-be/
├── src/
│ ├── main/
│ │ ├── java/com/lottery/lottery/
│ │ │ ├── config/ # Configuration classes
│ │ │ ├── controller/ # REST controllers
│ │ │ ├── dto/ # Data transfer objects
│ │ │ ├── exception/ # Exception handlers
│ │ │ ├── health/ # Health indicators
│ │ │ ├── logging/ # Grafana logging config
│ │ │ ├── model/ # JPA entities
│ │ │ ├── repository/ # JPA repositories
│ │ │ ├── security/ # Auth interceptor, UserContext
│ │ │ └── service/ # Business logic
│ │ └── resources/
│ │ ├── db/migration/ # Flyway migrations
│ │ └── application.yml # Application config
├── nginx/ # Nginx config (for Inferno)
├── Dockerfile # Dockerfile for Railway
├── Dockerfile.inferno # Dockerfile for Inferno
├── docker-compose.yml # Docker Compose for local/Railway
├── docker-compose.inferno.yml # Docker Compose for Inferno
└── pom.xml # Maven configuration
License
[Your License Here]