Skip to main content

Deployment

This guide covers deploying True Life to a production FiveM server.

Build for Production

# Full production build
pnpm build

This runs:

  1. pnpm gen - Generate asset references
  2. pnpm typecheck:build - Type check all code
  3. pnpm build:client - Build client bundle
  4. pnpm build:server - Build server bundle
  5. pnpm build:ui - Build UI with Vite

Output Structure

dist/
├── client.js      # Client bundle
├── server.js      # Server bundle
└── ui/            # UI build output
    ├── index.html
    └── assets/
        ├── index-[hash].js
        ├── index-[hash].css
        └── [feature]-[hash].js

FiveM Resource Setup

fxmanifest.lua

fx_version 'cerulean'
game 'gta5'
 
name 'true_life'
description 'True Life FiveM Framework'
version '1.0.0'
 
-- Server script
server_script 'dist/server.js'
 
-- Client script
client_script 'dist/client.js'
 
-- UI files
ui_page 'dist/ui/index.html'
 
files {
    'dist/ui/**/*'
}
 
-- Dependencies
dependency 'yarn'
dependency 'oxmysql' -- If using MySQL alongside MongoDB

Server Configuration

# server.cfg (FiveM server.cfg format)
 
# Resource
ensure true_life
 
# MongoDB
set mongodb_uri "mongodb://user:password@host:27017"
set mongodb_database "true_life_prod"
 
# Disable dev mode
set dev_mode "false"
set dev_features ""
 
# OpenTelemetry (optional)
set otel_enabled "true"
set otel_endpoint "http://otel-collector:4318"
set otel_service_name "true_life_prod"

Docker Deployment

MongoDB

# docker-compose.prod.yml
services:
    mongo:
        image: mongo:7
        restart: always
        environment:
            MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
            MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
        volumes:
            - mongo-data:/data/db
        networks:
            - fivem-network

Full Stack

services:
    mongo:
        image: mongo:7
        restart: always
        environment:
            MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
            MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
        volumes:
            - mongo-data:/data/db
        networks:
            - internal
 
    otel-collector:
        image: otel/opentelemetry-collector-contrib:0.141.0
        restart: always
        volumes:
            - ./infra/otel/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
        networks:
            - internal
 
    tempo:
        image: grafana/tempo:2.9.0
        restart: always
        volumes:
            - ./infra/tempo/tempo.yaml:/etc/tempo.yaml:ro
            - tempo-data:/var/tempo
        networks:
            - internal
 
    loki:
        image: grafana/loki:3.6.2
        restart: always
        volumes:
            - ./infra/loki/loki.yaml:/etc/loki/loki.yaml:ro
            - loki-data:/loki
        networks:
            - internal
 
    grafana:
        image: grafana/grafana:12.3.0
        restart: always
        environment:
            - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
            - GF_AUTH_ANONYMOUS_ENABLED=false
        volumes:
            - ./infra/grafana/provisioning:/etc/grafana/provisioning:ro
            - grafana-data:/var/lib/grafana
        ports:
            - "3001:3000"
        networks:
            - internal
 
    docs:
        image: node:22-alpine
        working_dir: /app
        command: sh -c "npm install && npm run build && npm run serve"
        volumes:
            - ./docs:/app
        ports:
            - "3003:3003"
        networks:
            - internal
 
volumes:
    mongo-data:
    tempo-data:
    loki-data:
    grafana-data:
 
networks:
    internal:

Environment Variables

Create .env.production:

# MongoDB
MONGO_USER=true_life
MONGO_PASSWORD=secure_password_here
 
# Grafana
GRAFANA_PASSWORD=secure_admin_password
 
# OpenTelemetry
OTEL_ENDPOINT=http://otel-collector:4318

CI/CD Pipeline

GitHub Actions Example

# .github/workflows/deploy.yml
name: Deploy
 
on:
    push:
        branches: [main]
 
jobs:
    build:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4
 
            - uses: pnpm/action-setup@v2
              with:
                  version: 10
 
            - uses: actions/setup-node@v4
              with:
                  node-version: 22
                  cache: "pnpm"
 
            - run: pnpm install
            - run: pnpm lint
            - run: pnpm test
            - run: pnpm build
 
            - uses: actions/upload-artifact@v4
              with:
                  name: dist
                  path: dist/
 
    deploy:
        needs: build
        runs-on: ubuntu-latest
        steps:
            - uses: actions/download-artifact@v4
              with:
                  name: dist
                  path: dist/
 
            # Deploy to your server
            - name: Deploy
              run: |
                  rsync -avz dist/ user@server:/path/to/resources/true_life/dist/

Security Checklist

  • Use strong MongoDB credentials
  • Disable dev mode in production
  • Set strong Grafana admin password
  • Use HTTPS for external endpoints
  • Configure firewall rules
  • Enable MongoDB authentication
  • Rotate secrets regularly
  • Monitor for suspicious activity

Performance Optimization

MongoDB Indexes

Ensure indexes are created on startup:

// src/modules/init/repository.ts
export async function ensureIndexes(): Promise<void> {
	const db = await getMongoDb();
 
	await db.collection("characters").createIndexes([{ key: { id: 1 }, unique: true }, { key: { playerId: 1 } }]);
 
	await db.collection("accounts").createIndexes([{ key: { id: 1 }, unique: true }, { key: { characterId: 1 } }]);
}

UI Bundle Optimization

Vite automatically optimizes the bundle:

  • Code splitting by feature
  • Tree shaking
  • Minification
  • Asset hashing

Telemetry Sampling

For high-traffic servers, configure sampling:

# otel-collector-config.yaml
processors:
    probabilistic_sampler:
        sampling_percentage: 10 # Sample 10% of traces

Monitoring

Key Metrics to Watch

  • Player count
  • Error rates
  • Response times
  • Database query performance
  • Memory usage

Alerting

Configure Grafana alerts for:

  • Error rate spikes
  • High latency
  • Database connection failures
  • Resource exhaustion

Backup Strategy

MongoDB Backup

# Manual backup
mongodump --uri="mongodb://user:pass@host:27017" --out=/backup/$(date +%Y%m%d)
 
# Scheduled backup (cron)
0 2 * * * mongodump --uri="..." --out=/backup/$(date +\%Y\%m\%d) --gzip

Restore

mongorestore --uri="mongodb://user:pass@host:27017" /backup/20240101