Skip to main content

Overview

The Extracurricular Management System uses environment-specific configuration for both backend and frontend. This guide covers all available configuration options, best practices, and security considerations.

Backend Configuration

The backend is configured via backend/src/main/resources/application.properties.

Server Configuration

# Development server runs on localhost
server.port=8080
server.port
integer
default:"8080"
The port on which the Spring Boot application listens for HTTP requests.

Database Configuration

Connection Settings

application.properties
# Database Connection
spring.datasource.url=jdbc:mysql://localhost:3306/ems_db?createDatabaseIfNotExist=true&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=app_user
spring.datasource.password=YOUR_SECURE_PASSWORD

# Schema Management
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url
string
required
JDBC connection URL for MySQL database. Key parameters:
  • createDatabaseIfNotExist=true: Auto-creates database on first run
  • useSSL=false: Disables SSL (set to true in production with certificates)
  • allowPublicKeyRetrieval=true: Required for MySQL 8.0+ authentication
spring.datasource.username
string
required
Database username. Use a dedicated application user, not root.
spring.datasource.password
string
required
Database password. Should be strong and unique per environment.
Never commit real passwords to version control. Use environment variables or secrets management in production.

Schema Management Strategy

spring.jpa.hibernate.ddl-auto
string
default:"update"
Controls how Hibernate manages database schema:
  • update: Automatically updates schema on entity changes (development)
  • validate: Only validates schema matches entities (production recommended)
  • create: Drops and recreates schema on startup (testing only)
  • create-drop: Creates schema on startup, drops on shutdown (testing only)
  • none: No schema management by Hibernate
spring.jpa.hibernate.ddl-auto=update
# Convenient for rapid development
The EMS entities use @Version for optimistic locking (see Event.java:83). This prevents lost updates during concurrent modifications, especially critical during high-traffic event registrations.

JWT Authentication

JWT (JSON Web Token) configuration for stateless authentication.
application.properties
# JWT Configuration (must match JwtUtils.java)
secretJwtString=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
expirationInt=86400000
secreteJwtString
string
required
Secret key for signing JWT tokens. Must be:
  • At least 256 bits (32+ characters)
  • Hex-encoded or securely random
  • Property name uses “secrete” (not “secret”) to match JwtUtils.java:26
The JWT utility class reads this value:
@Value("${secreteJwtString}")
private String secreteJwtString;
expirationInt
integer
default:"86400000"
JWT token expiration time in milliseconds.
  • 86400000 = 24 hours (default)
  • 3600000 = 1 hour
  • 604800000 = 7 days
Critical Security Requirements:
  1. Never use the example JWT secret in production
  2. Generate a cryptographically secure random key:
    openssl rand -hex 32
    
  3. Rotate secrets if compromised
  4. Store in environment variables or secrets manager
  5. Use different secrets per environment
The JWT implementation is in backend/src/main/java/com/ems/backend/security/JwtUtils.java. Tokens are validated on every authenticated request.

Email (SMTP) Configuration

EMS uses the Adapter Pattern for email notifications. The OutlookEmailAdapter supports both Outlook/Office365 and other SMTP providers.

Development (Mailtrap)

application.properties
# Mailtrap for development email testing
spring.mail.host=sandbox.smtp.mailtrap.io
spring.mail.port=2525
spring.mail.username=YOUR_MAILTRAP_USERNAME
spring.mail.password=YOUR_MAILTRAP_PASSWORD
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Production (Outlook/Office365)

application.properties
# Outlook/Office365 SMTP
spring.mail.host=smtp.office365.com
spring.mail.port=587
spring.mail.username[email protected]
spring.mail.password=YOUR_APP_PASSWORD
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Configuration Reference

spring.mail.host
string
required
SMTP server hostname:
  • Mailtrap: sandbox.smtp.mailtrap.io
  • Outlook: smtp.office365.com
  • Gmail: smtp.gmail.com
  • Amazon SES: email-smtp.{region}.amazonaws.com
spring.mail.port
integer
required
SMTP server port:
  • 587: STARTTLS (recommended)
  • 465: SSL/TLS
  • 2525: Mailtrap alternative port
spring.mail.username
string
required
SMTP authentication username (usually the email address).
spring.mail.password
string
required
SMTP authentication password or app-specific password.
spring.mail.properties.mail.smtp.auth
boolean
default:"true"
Enable SMTP authentication.
spring.mail.properties.mail.smtp.starttls.enable
boolean
default:"true"
Enable STARTTLS for encrypted connections.
Email Security Best Practices:
  1. Use app-specific passwords, not your main account password
  2. For Office365/Outlook, enable “App passwords” in security settings
  3. For Gmail, enable “Less secure app access” or use OAuth2
  4. Store credentials in environment variables:
    export SMTP_PASSWORD="your-secure-password"
    
    Then reference: spring.mail.password=${SMTP_PASSWORD}

Environment Variables

For production deployments, use environment variables instead of hardcoded values:
application.properties
# Database
spring.datasource.url=${DB_URL:jdbc:mysql://localhost:3306/ems_db}
spring.datasource.username=${DB_USERNAME:app_user}
spring.datasource.password=${DB_PASSWORD}

# JWT
secretJwtString=${JWT_SECRET}
expirationInt=${JWT_EXPIRATION:86400000}

# Email
spring.mail.host=${SMTP_HOST:smtp.office365.com}
spring.mail.port=${SMTP_PORT:587}
spring.mail.username=${SMTP_USERNAME}
spring.mail.password=${SMTP_PASSWORD}
The syntax ${VAR_NAME:default_value} uses the environment variable if set, otherwise falls back to the default.
export DB_PASSWORD="dev_password"
export JWT_SECRET="dev_secret_key_32_chars_min"
export SMTP_USERNAME="[email protected]"
export SMTP_PASSWORD="mailtrap_token"

Frontend Configuration

The React frontend uses Vite’s environment variable system.

Environment File

Create frontend/ems-frontend/.env:
.env
VITE_API_BASE_URL=http://localhost:8080/api
VITE_API_BASE_URL
string
required
Base URL for backend API requests. All API calls are prefixed with this value.Examples:
  • Development: http://localhost:8080/api
  • Staging: https://staging-api.example.com/api
  • Production: https://api.example.com/api
Vite requires environment variables to be prefixed with VITE_ to be exposed to the client code.

Environment-Specific Configuration

# Development environment
VITE_API_BASE_URL=http://localhost:8080/api
VITE_DEBUG_MODE=true
Vite automatically loads the appropriate file based on the mode:
  • npm run dev.env.development
  • npm run build.env.production
  • npm run build --mode staging.env.staging

Accessing Variables in Code

Access environment variables in your React components:
src/services/api.js
import axios from 'axios';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

export default api;
Frontend environment variables are embedded in the built JavaScript and visible to users. Never store secrets or sensitive data in frontend .env files.

Configuration Management

Development Setup

  1. Copy example files:
    cp backend/src/main/resources/application.properties.example application.properties
    cp frontend/ems-frontend/.env.example .env
    
  2. Edit with your values:
    • Database credentials
    • JWT secret (generate with openssl rand -hex 32)
    • SMTP settings (use Mailtrap for dev)
  3. Add to .gitignore:
    # Backend
    **/application.properties
    
    # Frontend
    .env
    .env.local
    .env.*.local
    

Production Deployment

1

Use Secrets Management

Never hardcode production secrets. Use:
  • AWS Secrets Manager
  • HashiCorp Vault
  • Kubernetes Secrets
  • Docker Swarm Secrets
  • Azure Key Vault
2

Environment Variables

Pass configuration via environment variables:
Docker Example
docker run -e DB_PASSWORD="$DB_PASSWORD" \
           -e JWT_SECRET="$JWT_SECRET" \
           -e SMTP_PASSWORD="$SMTP_PASSWORD" \
           ems-backend:latest
3

Validation

Set schema validation to validate mode:
spring.jpa.hibernate.ddl-auto=validate
This ensures the application fails to start if schema doesn’t match entities.
4

Rotate Secrets Regularly

Implement a secret rotation policy:
  • JWT secrets: Rotate quarterly or on suspected compromise
  • Database passwords: Rotate biannually
  • SMTP passwords: Rotate annually or per policy

Configuration Checklist

Database user created with appropriate permissions
Strong, unique JWT secret generated (32+ characters)
SMTP credentials tested and working
Environment variables configured for all secrets
Production uses ddl-auto=validate, not update
SSL/TLS enabled for database connections in production
Frontend API URL points to correct backend
All sensitive files added to .gitignore
Secrets stored in secure secrets manager (production)

Troubleshooting

Problem: Could not resolve placeholder 'secreteJwtString'Solution: Ensure the property name matches exactly in application.properties. Note the spelling “secrete” (not “secret”) to match the @Value annotation in JwtUtils.java:26.
Problem: Unable to connect to MySQLSolutions:
  • Verify MySQL is running
  • Check credentials are correct
  • Ensure database user has proper permissions
  • For remote databases, check firewall rules
  • Add &serverTimezone=UTC to connection URL if timezone errors occur
Problem: SMTP authentication failuresSolutions:
  • For Outlook: Use an app password, not your main password
  • Verify starttls.enable=true and port is 587
  • Check firewall isn’t blocking SMTP port
  • Test credentials with a mail client
Problem: API requests fail with CORS or connection errorsSolutions:
  • Verify VITE_API_BASE_URL is correct
  • Check backend is running and accessible
  • Ensure CORS is configured in Spring Security
  • Check browser console for specific error messages

Next Steps

Deployment

Deploy your configured application to production

Security

Learn about security architecture and best practices

API Reference

Explore available API endpoints

Architecture

Understand the system architecture

Build docs developers (and LLMs) love