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