# 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 1. **Clone the repository** 2. **Start MySQL using Docker Compose**: ```bash docker-compose up -d db ``` 3. **Create `.env` file** (for local development): ```env 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 ``` 4. **Run the application**: ```bash mvn spring-boot:run ``` Or build and run with Docker: ```bash 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 1. Go to [Railway](https://railway.app) and sign in 2. Click **"New Project"** 3. Select **"Empty Project"** #### Step 2: Create MySQL Database Service 1. In your Railway project, click **"+ New"** → **"Database"** → **"Add MySQL"** 2. Railway will automatically create a MySQL database 3. Note the connection details (you'll need them for the backend service) #### Step 3: Create Backend Service 1. In your Railway project, click **"+ New"** → **"GitHub Repo"** (or **"Empty Service"**) 2. If using GitHub: - Connect your GitHub account - Select the `lottery-be` repository - Railway will automatically detect it's a Java/Maven project 3. 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: ```env 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 1. In your backend service, go to **"Settings"** → **"Connect"** 2. Find your MySQL database service 3. Click **"Connect"** - Railway will automatically add the MySQL connection variables #### Step 6: Configure Health Check 1. In your backend service, go to **"Settings"** → **"Healthcheck"** 2. Set **Healthcheck Path** to: ``` /actuator/health/readiness ``` 3. Railway will poll this endpoint and wait for HTTP 200 before marking deployment as active #### Step 7: Deploy 1. Railway will automatically deploy when you push to the connected branch 2. Or manually trigger deployment from the Railway dashboard 3. Check the **"Deployments"** tab to monitor the deployment #### Step 8: Get Backend URL 1. In your backend service, go to **"Settings"** → **"Networking"** 2. Click **"Generate Domain"** to get a public URL 3. Or use the default Railway domain 4. Copy the URL (e.g., `https://lottery-be-production.up.railway.app`) #### Step 9: Create Frontend Service (Optional - if deploying frontend to Railway) 1. In your Railway project, click **"+ New"** → **"GitHub Repo"** 2. Select your `lottery-fe` repository 3. Railway will detect it's a Node.js project 4. Add environment variable: ```env VITE_API_BASE_URL=https://your-backend-url.railway.app ``` 5. Railway will automatically build and deploy #### Step 10: Create Volume (Optional - for persistent data) If you need persistent storage: 1. In your Railway project, click **"+ New"** → **"Volume"** 2. Name it (e.g., `lottery-data`) 3. 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 1. **SSH into your Inferno server**: ```bash ssh user@your-server-ip ``` 2. **Install Docker** (if not installed): ```bash # For Ubuntu/Debian curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh sudo usermod -aG docker $USER ``` 3. **Install Docker Compose** (if not installed): ```bash 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 ``` 4. **Install JDK 17** (for building): ```bash # For Ubuntu/Debian sudo apt update sudo apt install openjdk-17-jdk -y ``` 5. **Create project directory**: ```bash mkdir -p /opt/lottery cd /opt/lottery ``` #### Step 2: Clone Repository ```bash 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): ```bash # 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): ```properties 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 ```bash 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) 1. **Edit nginx configuration**: ```bash nano nginx/conf.d/lottery.conf ``` 2. **Update server_name** (if using HTTPS): ```nginx server { listen 80; server_name your-domain.com; # ... rest of config } ``` 3. **Reload nginx**: ```bash docker-compose -f docker-compose.inferno.yml restart nginx ``` #### Step 7: Set Up SSL (Optional - Recommended for Production) 1. **Install Certbot** (Let's Encrypt): ```bash sudo apt install certbot python3-certbot-nginx -y ``` 2. **Obtain SSL certificate**: ```bash sudo certbot --nginx -d your-domain.com ``` 3. **Update nginx config** to use HTTPS (uncomment HTTPS server block in `nginx/conf.d/lottery.conf`) 4. **Reload nginx**: ```bash docker-compose -f docker-compose.inferno.yml restart nginx ``` #### Step 8: Configure Firewall ```bash # 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: ```bash sudo nano /etc/systemd/system/lottery.service ``` Add: ```ini [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: ```bash sudo systemctl daemon-reload sudo systemctl enable lottery.service sudo systemctl start lottery.service ``` #### Step 10: Set Up Grafana Integration (Production Logging) 1. **Install Grafana and Loki** (on a separate server or same server): ```bash # Follow Grafana/Loki installation guide # https://grafana.com/docs/loki/latest/installation/ ``` 2. **Configure Promtail** to collect logs from Docker containers: ```yaml # 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 ``` 3. **Update docker-compose.inferno.yml** to add logging driver: ```yaml app: # ... existing config logging: driver: "json-file" options: max-size: "10m" max-file: "3" ``` 4. **Configure Grafana datasource** to connect to Loki #### Step 11: Monitor and Maintain **Check service status**: ```bash docker-compose -f docker-compose.inferno.yml ps ``` **View logs**: ```bash # 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**: ```bash cd /opt/lottery/lottery-be git pull docker-compose -f docker-compose.inferno.yml up -d --build ``` **Backup database**: ```bash 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: 1. **Environment Variables** (Railway): Set variables in Railway dashboard 2. **Secret File** (Inferno): Mount file at `/run/secrets/lottery-config.properties` Priority: Secret file → Environment variables ### Required Variables - `SPRING_DATASOURCE_URL` - MySQL connection URL - `SPRING_DATASOURCE_USERNAME` - MySQL username - `SPRING_DATASOURCE_PASSWORD` - MySQL password - `TELEGRAM_BOT_TOKEN` - Telegram bot token for authentication - `FRONTEND_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 health - `GET /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: 1. Frontend sends `Authorization: tma ` header 2. Backend validates Telegram signature 3. Backend creates/updates user in database 4. 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_TOKEN` is correct - Check that frontend is sending `Authorization: tma ` 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 ```bash mvn test ``` ### Building JAR ```bash mvn clean package ``` ### Running Locally with Docker ```bash 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]