544 lines
14 KiB
Markdown
544 lines
14 KiB
Markdown
# 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 <initData>` 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 <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
|
|
|
|
```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]
|
|
|
|
|