docs: add comprehensive project documentation
Some checks failed
Deploy / deploy (push) Has been cancelled

- README.md: project overview, server status, quick start guide,
  architecture diagram, tech stack, and content inventory
- docs/architecture.md: technical architecture, service diagram,
  component details, and design decisions
- docs/game-servers.md: setup and operation guide for OpenFusion,
  MapleStory 2, and Minecraft FTB Infinity Evolved
- docs/cms-content.md: Strapi content model, i18n strategy,
  documentary structure, and API endpoints
- docs/deployment.md: local dev, production deploy, CI/CD,
  SSL setup, backup procedures, and monitoring

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
consultoria-as
2026-02-23 12:23:53 +00:00
parent aea2283d8f
commit e4404b209d
5 changed files with 931 additions and 0 deletions

161
docs/architecture.md Normal file
View File

@@ -0,0 +1,161 @@
# Arquitectura Tecnica
## Vision General
Project Afterlife es un monorepo que combina una plataforma web de preservacion de videojuegos con los servidores de los juegos preservados. La infraestructura se gestiona completamente con Docker Compose.
## Diagrama de Servicios
```
┌─────────────────────────────────────┐
│ USUARIO / CLIENTE │
└───────────┬───────────┬─────────────┘
│ │
┌───────────▼───┐ ┌─────▼─────────────┐
│ Next.js :3000│ │ Clientes de juegos │
└───────┬───────┘ └──┬──────┬─────┬───┘
│ │ │ │
┌───────▼───────┐ │ │ │
│ Strapi :1337 │ │ │ │
└───┬───────┬───┘ │ │ │
│ │ │ │ │
┌───────▼──┐ ┌──▼────┐ │ │ │
│ PG :5432 │ │ MinIO │ │ │ │
│ │ │ :9000 │ │ │ │
└──────────┘ └───────┘ │ │ │
│ │ │
┌──────────────────────────────┘ │ │
│ │ │
┌───────▼──────────┐ ┌──────────────────┐ │ │
│ OpenFusion │ │ MapleStory 2 │ │ │
│ :23000-23001 │ │ Login :20001 │ │ │
└──────────────────┘ │ World :21001 │ │ │
│ Game :20002 │ │ │
│ Web :4000 │ │ │
│ MySQL :3307 │ │ │
└──────────────────┘ │ │
│ │
┌──────────────────────▼─┐ │
│ Minecraft FTB :25565 │ │
└────────────────────────┘ │
(Juegos futuros...) ◄──┘
```
## Componentes
### Frontend (Next.js 15)
**Ubicacion**: `apps/web/`
- **Framework**: Next.js 15 con App Router
- **React**: 19 (forzado via `overrides` en root `package.json`)
- **Estilos**: Tailwind CSS v4 con `@tailwindcss/postcss`
- **i18n**: next-intl con prefijo de ruta (`/es/`, `/en/`)
- **Audio**: Howler.js para reproductor de documentales
- **Animaciones**: Framer Motion
**Estructura de rutas**:
```
src/app/
├── layout.tsx # Pass-through (return children)
├── globals.css # Tailwind v4 imports
├── not-found.tsx # 404 page
└── [locale]/
├── layout.tsx # <html>, <body>, providers
├── page.tsx # Home
├── about/page.tsx # About
├── catalog/page.tsx # Game catalog
├── donate/page.tsx # Donations
└── games/
└── [slug]/
├── page.tsx # Game detail
└── documentary/page.tsx # Interactive documentary
```
**Patron de layout**: El root `layout.tsx` es un pass-through que solo retorna `children`. El layout real con `<html>`, `<body>`, y `NextIntlClientProvider` esta en `[locale]/layout.tsx`. Esto es necesario para que next-intl funcione correctamente con el App Router.
### CMS (Strapi 5)
**Ubicacion**: `apps/cms/`
- **Version**: Strapi 5.36.0
- **Base de datos**: PostgreSQL 16
- **Almacenamiento**: MinIO (compatible con S3)
- **React**: 18 (admin panel, separado del frontend)
- **i18n**: Plugin nativo con locales ES/EN
**Content Types**:
- `Game` — Entrada de juego con metadata, screenshots, estado del servidor
- `Documentary` — Documental con titulo, descripcion, relacion 1:1 con Game
- `Chapter` — Capitulo con contenido rich text, audio opcional, orden
**Nota sobre schemas**: Los archivos `schema.json` de Strapi 5 deben copiarse manualmente al directorio `dist/` durante el build. El Dockerfile del CMS incluye este fix.
### Tipos Compartidos
**Ubicacion**: `packages/shared/`
Paquete TypeScript puro (`@afterlife/shared`) con las interfaces compartidas entre web y CMS:
```typescript
// Game, Documentary, Chapter, StrapiMedia, StrapiResponse, etc.
```
### Base de Datos
**PostgreSQL 16** para el CMS:
- 44 tablas (contenido + sistema Strapi)
- Modelo i18n: cada contenido tiene filas separadas por locale (en/es) y estado (draft/published)
- Relaciones via tablas `_lnk` (e.g., `games_documentary_lnk`)
**MySQL 8.0** para MapleStory 2:
- Dos databases: `maple-data` (datos del juego, read-only) y `game-server` (datos de jugadores)
- Puerto 3307 para evitar conflicto con PostgreSQL 5432
### Almacenamiento (MinIO)
MinIO corre como servicio S3-compatible para almacenar:
- Imagenes de portada de juegos
- Screenshots
- Archivos de audio para documentales
- Cualquier otro media subido al CMS
**Puertos**: 9000 (API), 9001 (consola web)
## Docker Compose: Tres Archivos
| Archivo | Proposito | Servicios |
|---------|----------|-----------|
| `docker-compose.dev.yml` | Desarrollo local | PG, MinIO, CMS, Web, OpenFusion, Minecraft FTB |
| `docker-compose.maple2.yml` | MapleStory 2 | MySQL, World, Login, Game, Web, File-Ingest |
| `docker-compose.yml` | Produccion | PG, MinIO, CMS, Web, Nginx, Certbot |
MapleStory 2 tiene su propio compose porque son 6 servicios (demasiados para mezclar con el stack principal) y requiere su propia base de datos MySQL.
## Red Docker
Todos los servicios del mismo archivo compose comparten una red Docker implicita. Los servicios se referencian entre si por nombre de servicio (e.g., `cms` desde `web`, `maple2-mysql` desde `maple2-world`).
Las variables de entorno como `DB_IP`, `GRPC_WORLD_IP` se configuran en cada servicio para apuntar al nombre de contenedor correcto dentro de la red Docker.
## CI/CD
**GitHub Actions** (`.github/workflows/deploy.yml`):
1. Push a `main` dispara el deploy
2. SSH al VPS
3. Pull, build, restart de servicios Docker
## Decisiones Arquitectonicas
### React 19 vs 18
El monorepo tiene dos versiones de React: 19 para Next.js (web) y 18 para Strapi (admin). Resuelto con `overrides` en el root `package.json` que solo afecta al workspace de web. El CMS corre en su propio contenedor Docker con sus propias dependencias.
### Tailwind v4
Usa la nueva sintaxis `@import "tailwindcss"` en `globals.css` con el plugin `@tailwindcss/postcss`. No hay `tailwind.config.js`.
### i18n con Strapi 5
Strapi 5 maneja i18n con filas separadas por locale y un `document_id` compartido. Cada documento tiene 4 filas: draft EN, draft ES, published EN, published ES. Las relaciones (`_lnk`) conectan las filas del mismo estado/locale.
### Servidores de juegos separados
Los servidores de juegos no son parte del build del monorepo. Son proyectos externos (OpenFusion en C++, Maple2 en C#) que se clonan en `servers/` y se ejecutan via Docker. El `.gitignore` excluye `servers/maple2/` (14 GB de datos de cliente) y los binarios de OpenFusion.

145
docs/cms-content.md Normal file
View File

@@ -0,0 +1,145 @@
# Modelo de Contenido CMS
## Strapi 5 — Content Types
### Game
Entrada principal de cada juego preservado.
| Campo | Tipo | Requerido | Localizado | Descripcion |
|-------|------|-----------|------------|-------------|
| title | string | si | si | Nombre del juego |
| slug | uid | si | no | URL-friendly, auto-generado desde title |
| description | richtext | no | si | Descripcion larga del juego |
| genre | enum | si | no | MMORPG, FPS, Casual, Strategy, Sports, Other |
| releaseYear | integer | si | no | Ano de lanzamiento original |
| shutdownYear | integer | si | no | Ano de cierre de servidores |
| developer | string | si | no | Estudio desarrollador |
| publisher | string | no | no | Publisher/distribuidor |
| screenshots | media[] | no | no | Capturas de pantalla (solo imagenes) |
| coverImage | media | si | no | Imagen de portada principal |
| serverStatus | enum | no | no | online, maintenance, coming_soon (default) |
| serverLink | string | no | no | IP:puerto para conectarse |
| documentary | relation | no | no | oneToOne con Documentary |
### Documentary
Documental interactivo asociado a un juego.
| Campo | Tipo | Requerido | Localizado | Descripcion |
|-------|------|-----------|------------|-------------|
| title | string | si | si | Titulo del documental |
| description | text | no | si | Descripcion/subtitulo |
| game | relation | no | no | oneToOne con Game |
| chapters | relation | no | no | oneToMany con Chapter (ordenados) |
### Chapter
Capitulo individual de un documental.
| Campo | Tipo | Requerido | Localizado | Descripcion |
|-------|------|-----------|------------|-------------|
| title | string | si | si | Titulo del capitulo |
| content | richtext | si | si | Contenido narrativo completo |
| audioFile | media | no | no | Archivo de audio (narracion) |
| audioDuration | integer | no | no | Duracion en segundos |
| order | integer | si | no | Orden de aparicion (1, 2, 3...) |
| coverImage | media | no | no | Imagen de portada del capitulo |
| documentary | relation | no | no | manyToOne con Documentary |
## Modelo i18n de Strapi 5
Strapi 5 maneja la internacionalizacion con **filas separadas por locale**. Cada documento tiene un `document_id` compartido y multiples filas:
```
document_id: "abc123"
├── id: 1 (locale: en, draft)
├── id: 2 (locale: en, published)
├── id: 3 (locale: es, draft)
└── id: 4 (locale: es, published)
```
Las **relaciones** (`_lnk` tables) conectan las filas del mismo estado. Un juego publicado en ES se conecta al documental publicado en ES, no al draft ni al EN.
### Tablas de enlace
- `games_documentary_lnk` — game_id ↔ documentary_id
- `chapters_documentary_lnk` — chapter_id ↔ documentary_id + chapter_ord
## Contenido Actual
### Juegos (3)
| Slug | document_id | Titulo | Genre | Release | Shutdown | Server |
|------|-------------|--------|-------|---------|----------|--------|
| fusionfall | sx17hshy2d... | FusionFall | MMORPG | 2009 | 2013 | online |
| maplestory2 | ms2maple2d... | MapleStory 2 | MMORPG | 2015 | 2020 | online |
| minecraft-ftb-infinity | mcftbinfd... | Minecraft: FTB Infinity Evolved | Sandbox | 2011 | - | online |
### Documentales (2)
#### FusionFall: "El Mundo Que No Queriamos Perder"
| # | Titulo | Contenido |
|---|--------|-----------|
| 1 | El Sueno Imposible | Origenes, Cartoon Network, Grigon Entertainment |
| 2 | Cuando los Mundos Colisionaron | Desarrollo, motor Unity, estilo anime de Midori Foo |
| 3 | Bienvenido al Futuro | Lanzamiento, viajes en el tiempo, sistema de Nanos |
| 4 | La Caida de Grigon | Quiebra del estudio, CN asume el desarrollo |
| 5 | La Academia | Free-to-play, The Academy, Adventure Time |
| 6 | Seis Dias | Cierre con 6 dias de aviso, agosto 2013 |
| 7 | Afterlife | Comunidad, FusionFall Retro/Legacy, OpenFusion |
#### MapleStory 2: "El Mundo Que Construimos Juntos"
| # | Titulo | Contenido |
|---|--------|-----------|
| 1 | El Siguiente Nivel | De MapleStory 1 a la vision 3D de NSquare |
| 2 | Un Mundo de Cubos y Color | Arte voxel, UGC, musica, housing |
| 3 | El Amanecer Coreano | Lanzamiento Korea julio 2015, primeros problemas |
| 4 | La Conquista Global | Lanzamiento global octubre 2018, hype de Twitch |
| 5 | La Tormenta Perfecta | Declive: RNG, limites semanales, exodo |
| 6 | El Ultimo Despertar | Expansion Awakening, demasiado tarde |
| 7 | Afterlife | Cierre mayo 2020, emulador MS2Community |
## Crear Contenido Nuevo
### Via Strapi Admin (recomendado)
1. Ir a http://localhost:1337/admin
2. Content Manager > Game / Documentary / Chapter
3. Crear en un idioma, luego usar "Localization" para traducir
### Via PostgreSQL (insercion directa)
Cuando la API de Strapi tiene restricciones de permisos, se puede insertar directamente en PostgreSQL. Cada contenido necesita 4 filas:
```sql
-- Draft EN
INSERT INTO games (document_id, title, slug, ..., locale)
VALUES ('unique_doc_id', 'Title', 'slug', ..., 'en');
-- Draft ES
INSERT INTO games (document_id, title, slug, ..., locale)
VALUES ('unique_doc_id', 'Titulo', 'slug', ..., 'es');
-- Published EN (con published_at)
INSERT INTO games (document_id, title, slug, ..., published_at, locale)
VALUES ('unique_doc_id', 'Title', 'slug', ..., NOW(), 'en');
-- Published ES (con published_at)
INSERT INTO games (document_id, title, slug, ..., published_at, locale)
VALUES ('unique_doc_id', 'Titulo', 'slug', ..., NOW(), 'es');
```
Para documentales, ademas de los inserts hay que crear las relaciones en las tablas `_lnk`:
```sql
INSERT INTO games_documentary_lnk (game_id, documentary_id) VALUES (game_id, doc_id);
INSERT INTO chapters_documentary_lnk (chapter_id, documentary_id, chapter_ord) VALUES (ch_id, doc_id, 1);
```
## API Endpoints
La API de Strapi se consume desde Next.js via funciones en `apps/web/src/lib/api.ts`:
| Funcion | Descripcion |
|---------|------------|
| `getGames(locale)` | Lista todos los juegos con portada |
| `getGameBySlug(slug, locale)` | Juego con documental y capitulos |
| `getDocumentaryByGameSlug(slug, locale)` | Documental completo de un juego |
Todas las llamadas requieren el header `Authorization: Bearer <STRAPI_API_TOKEN>`.

194
docs/deployment.md Normal file
View File

@@ -0,0 +1,194 @@
# Guia de Despliegue
## Entornos
| Entorno | Compose File | Servicios |
|---------|-------------|-----------|
| **Desarrollo local** | `docker-compose.dev.yml` + `docker-compose.maple2.yml` | Todos |
| **Produccion** | `docker-compose.yml` | Web + CMS + DB + Nginx + SSL |
## Desarrollo Local
### Requisitos
- Docker Engine 24+
- Docker Compose v2+
- 8 GB RAM minimo (16 GB con todos los servidores de juegos)
- 50 GB disco libre
### Levantar todo
```bash
cd docker/
# 1. Stack principal
docker compose -f docker-compose.dev.yml up -d
# 2. MapleStory 2 (requiere setup previo, ver game-servers.md)
docker compose -f docker-compose.maple2.yml up -d
# 3. Verificar
docker ps
```
### Puertos en uso
| Puerto | Servicio |
|--------|---------|
| 3000 | Next.js (frontend) |
| 1337 | Strapi (CMS admin) |
| 5432 | PostgreSQL |
| 9000 | MinIO API |
| 9001 | MinIO Console |
| 23000-23001 | OpenFusion |
| 20001 | MapleStory 2 Login |
| 21001 | MapleStory 2 World |
| 20002 | MapleStory 2 Game |
| 21002 | MapleStory 2 Game gRPC |
| 3307 | MySQL (MapleStory 2) |
| 4000 | MapleStory 2 Web |
| 25565 | Minecraft FTB |
### Detener servicios
```bash
docker compose -f docker-compose.dev.yml down
docker compose -f docker-compose.maple2.yml down
```
### Reconstruir imagenes
```bash
docker compose -f docker-compose.dev.yml build --no-cache
docker compose -f docker-compose.maple2.yml build --no-cache
```
## Produccion
### Archivo: docker-compose.yml
El compose de produccion incluye:
- **Nginx** como reverse proxy (puertos 80/443)
- **Certbot** para certificados SSL Let's Encrypt
- Sin servidores de juegos (se configuran aparte segun el VPS)
### Variables de entorno requeridas
```env
# Base de datos
DATABASE_NAME=afterlife
DATABASE_USERNAME=afterlife
DATABASE_PASSWORD=<password-seguro>
# MinIO
MINIO_ROOT_USER=afterlife
MINIO_ROOT_PASSWORD=<password-seguro>
# Strapi keys (generar con: openssl rand -base64 32)
APP_KEYS=<key1>,<key2>,<key3>,<key4>
API_TOKEN_SALT=<salt>
ADMIN_JWT_SECRET=<secret>
TRANSFER_TOKEN_SALT=<salt>
JWT_SECRET=<secret>
# API
STRAPI_API_TOKEN=<token-generado-en-admin>
PUBLIC_STRAPI_URL=https://tu-dominio.com
# Domain
DOMAIN=tu-dominio.com
```
### Deploy manual al VPS
```bash
# En el VPS
cd /opt/project-afterlife
git pull origin main
docker compose build
docker compose up -d
```
### CI/CD Automatico
El archivo `.github/workflows/deploy.yml` automatiza el deploy:
1. **Trigger**: Push a `main`
2. **Accion**: SSH al VPS, pull, build, restart
**Secrets de GitHub requeridos**:
- `VPS_HOST` — Hostname o IP del VPS
- `VPS_USER` — Usuario SSH
- `VPS_SSH_KEY` — Llave privada SSH
### SSL con Certbot
```bash
# Primera vez: obtener certificado
docker compose run --rm certbot certonly \
--webroot --webroot-path=/var/www/certbot \
-d tu-dominio.com
# Renovacion automatica (cron)
0 0 * * * docker compose run --rm certbot renew
```
## Backups
### Base de datos CMS (PostgreSQL)
```bash
# Exportar
docker exec docker-postgres-1 pg_dump -U afterlife afterlife > backup_$(date +%Y%m%d).sql
# Importar
cat backup.sql | docker exec -i docker-postgres-1 psql -U afterlife afterlife
```
### Base de datos MapleStory 2 (MySQL)
```bash
# Exportar
docker exec maple2-db mysqldump -u root -pmaplestory --databases maple-data game-server > backup_ms2_$(date +%Y%m%d).sql
# Importar
cat backup_ms2.sql | docker exec -i maple2-db mysql -u root -pmaplestory
```
### Mundo de Minecraft
```bash
# Exportar
docker cp minecraft-ftb:/data/world ./backup_mc_world_$(date +%Y%m%d)/
# Importar
docker cp ./backup_mc_world/ minecraft-ftb:/data/world
docker restart minecraft-ftb
```
### Volumenes Docker (completo)
```bash
# Listar volumenes
docker volume ls | grep afterlife
# Backup de un volumen
docker run --rm -v docker_postgres_data:/data -v $(pwd):/backup \
alpine tar czf /backup/postgres_data.tar.gz -C /data .
```
## Monitoreo
### Estado de contenedores
```bash
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
```
### Uso de recursos
```bash
docker stats --no-stream
```
### Logs en tiempo real
```bash
docker logs -f --tail 50 <container-name>
```
### Health checks
PostgreSQL y MySQL tienen healthchecks configurados en los compose files. Verificar con:
```bash
docker inspect --format='{{.State.Health.Status}}' docker-postgres-1
docker inspect --format='{{.State.Health.Status}}' maple2-db
```

233
docs/game-servers.md Normal file
View File

@@ -0,0 +1,233 @@
# Servidores de Juegos
Guia de setup, operacion y troubleshooting de cada servidor de juegos.
## OpenFusion (FusionFall)
### Resumen
| Dato | Valor |
|------|-------|
| Emulador | [OpenFusion](https://github.com/OpenFusionProject/OpenFusion) |
| Lenguaje | C++ |
| Puerto | 23000 (login), 23001 (shard) |
| Base de datos | SQLite (embebida) |
| RAM | ~254 MB |
### Archivos
```
servers/openfusion/
├── Dockerfile # Ubuntu 24.04, copia binario + config
├── docker-entrypoint.sh # Genera config.ini desde env vars
├── config.ini # Configuracion del servidor
├── fusion # Binario compilado (no en git)
├── sql/ # Migraciones SQLite
└── tdata/ # Datos del juego (NPCs, mobs, drops)
```
### Configuracion
Variables de entorno en `docker-compose.dev.yml`:
- `OPENFUSION_SHARD_IP`: IP publica del servidor (default: 192.168.10.234)
- `OPENFUSION_MOTD`: Mensaje del dia
### Conexion de cliente
1. Descargar el cliente FusionFall
2. Usar el launcher de OpenFusion apuntando a `192.168.10.234:23000`
### Troubleshooting
- **"Connection refused"**: Verificar que el contenedor esta corriendo y los puertos estan mapeados
- **Datos de juego**: Los archivos `tdata/` contienen los NPCs, mobs y drops. Si faltan, el mundo estara vacio
---
## MapleStory 2
### Resumen
| Dato | Valor |
|------|-------|
| Emulador | [Maple2](https://github.com/MS2Community/Maple2) |
| Lenguaje | C# / .NET 8 |
| Puertos | 20001 (login), 21001 (world), 20002/21002 (game), 4000 (web) |
| Base de datos | MySQL 8.0 (puerto 3307) |
| RAM total | ~1.4 GB (5 contenedores) |
### Arquitectura Multi-Servicio
```
maple2-mysql (3307)
├── maple2-world (21001) ← Coordinador central, gRPC
│ │
│ ├── maple2-login (20001) ← Autenticacion, seleccion de personaje
│ │
│ └── maple2-game-ch0 (20002/21002) ← Canal de juego
└── maple2-web (4000) ← API web auxiliar
```
Los servidores se comunican entre si via **gRPC** (HTTP/2). El World server actua como coordinador central. Los Game servers se conectan al World al iniciar.
### Setup Inicial (Primera Vez)
#### 1. Clonar el repositorio
```bash
cd servers/
git clone --recurse-submodules https://github.com/MS2Community/Maple2.git maple2
```
#### 2. Descargar datos del cliente
Se necesita el cliente de MapleStory 2 (~14 GB). Los archivos se colocan en `servers/maple2/client-data/Data/`.
Fuentes del cliente:
- [adventure-island-online-2 releases](https://github.com/shuabritze/adventure-island-online-2/releases) (6 partes ZIP)
- Extraer todo a `servers/maple2/client-data/`
#### 3. Aplicar XML Patches
Descargar [MapleStory2-XML v1.2.1](https://github.com/MS2Community/MapleStory2-XML/releases/tag/v1.2.1) y copiar los archivos `Server.m2d`, `Server.m2h`, `Xml.m2d`, `Xml.m2h` a `servers/maple2/client-data/Data/` (reemplazar los originales).
#### 4. Configurar .env
```bash
cp servers/maple2/.env.example servers/maple2/.env
# Editar con las IPs correctas:
# GAME_IP=192.168.10.234
# LOGIN_IP=192.168.10.234
```
#### 5. Verificar .dockerignore
El archivo `servers/maple2/.dockerignore` DEBE incluir:
```
client-data
client-download
xml-patches
```
Sin esto, el build de Docker intentara copiar 14 GB de datos al contexto.
#### 6. Ingestar datos del juego
```bash
cd docker/
docker compose -f docker-compose.maple2.yml up -d maple2-mysql
# Esperar a que MySQL este healthy
docker compose -f docker-compose.maple2.yml run --rm maple2-file-ingest \
bash -c "cd /app && dotnet restore && cd Maple2.File.Ingest && dotnet run"
```
Este proceso importa todos los datos del cliente a MySQL. Toma ~10 minutos.
#### 7. Construir y levantar servidores
```bash
docker compose -f docker-compose.maple2.yml build
docker compose -f docker-compose.maple2.yml up -d
```
### Conexion de cliente
1. Tener el cliente de MapleStory 2 instalado
2. El cliente debe apuntar a `192.168.10.234:20001` (Login Server)
3. Las IPs se configuran en `servers/maple2/.env` (`GAME_IP`, `LOGIN_IP`)
### Troubleshooting
- **"No space left on device" al buildear**: Verificar `.dockerignore` incluye `client-data`
- **"Scripting/Scripts not found"**: Ya corregido — se removio la linea COPY del Dockerfile del Game server
- **"project.assets.json not found" en file-ingest**: Ejecutar `dotnet restore` antes de `dotnet run`
- **Servidores no se conectan entre si**: Verificar que `GRPC_WORLD_IP=maple2-world` y `GRPC_GAME_IP=maple2-game-ch0` estan configurados en el compose
### Agregar mas canales de juego
Para agregar un segundo canal, duplicar el servicio `maple2-game-ch0` en el compose cambiando:
- Nombre: `maple2-game-ch1`
- Puertos: `20003:20003` y `21003:21003`
- `GRPC_GAME_IP: maple2-game-ch1`
---
## Minecraft: FTB Infinity Evolved
### Resumen
| Dato | Valor |
|------|-------|
| Imagen Docker | itzg/minecraft-server:java8 |
| Modpack | FTB Infinity Evolved v3.1.0 |
| Minecraft | 1.7.10 |
| Forge | 10.13.4.1614 |
| Puerto | 25565 |
| RAM | ~3.5 GB (6 GB JVM heap, 8 GB limite contenedor) |
| Mods | ~175 |
### Configuracion
El servidor se configura via variables de entorno en `docker-compose.dev.yml`:
```yaml
environment:
EULA: "TRUE"
TYPE: FTBA
FTB_MODPACK_ID: 23
FTB_MODPACK_VERSION_ID: 99
MEMORY: 6G
MAX_MEMORY: 6G
MOTD: "Project Afterlife - FTB Infinity Evolved"
DIFFICULTY: normal
MAX_PLAYERS: 20
VIEW_DISTANCE: 10
JVM_DD_OPTS: "fml.queryResult=confirm"
PRE_LAUNCH_CMD: "cp -n /data/minecraft_server.jar /data/minecraft_server.1.7.10.jar 2>/dev/null; true"
```
### Fix Conocido: Classpath de Forge 1.7.10
El MANIFEST.MF del jar de Forge 1.7.10 referencia `minecraft_server.1.7.10.jar` en su Class-Path, pero la imagen itzg renombra el archivo a `minecraft_server.jar`. Sin el fix, Forge no encuentra log4j2 y crashea con `NoClassDefFoundError`.
**Solucion**: El `PRE_LAUNCH_CMD` copia el archivo con el nombre correcto antes de cada inicio. Si recreas el volumen, este fix se aplica automaticamente.
### Primer inicio
El primer inicio toma 5-10 minutos porque:
1. Descarga el FTB App installer
2. Descarga los ~175 mods del modpack
3. Instala Forge 10.13.4.1614
4. Genera el mundo
### Conexion de cliente
1. Instalar [FTB App](https://www.feed-the-beast.com/app), MultiMC, ATLauncher, o Prism Launcher
2. Instalar modpack **FTB Infinity Evolved** version 3.1.0
3. Multiplayer > Add Server: `192.168.10.234:25565`
### Modo Experto
Para activar el modo experto (recetas mas complejas):
```
/ftb_mode set expert
```
Ejecutar desde la consola del servidor o como operador in-game.
### Troubleshooting
- **"NoClassDefFoundError: org/apache/logging/log4j/Level"**: El fix de classpath no se aplico. Ejecutar manualmente: `docker exec minecraft-ftb cp /data/minecraft_server.jar /data/minecraft_server.1.7.10.jar` y reiniciar
- **Server lag**: Reducir `VIEW_DISTANCE` de 10 a 8, o aumentar `MEMORY` si hay RAM disponible
- **Pastebin 403**: Error inocuo — Pastebin bloquea requests automaticos. Solo afecta a los badges de FTB Utilities, no a la funcionalidad del juego
---
## Operaciones Comunes
### Ver logs de un servidor
```bash
docker logs -f minecraft-ftb # Minecraft
docker logs -f maple2-world # MapleStory 2 World
docker logs -f docker-openfusion-1 # OpenFusion
```
### Reiniciar un servidor
```bash
docker restart minecraft-ftb
docker restart maple2-world maple2-login docker-maple2-game-ch0-1
docker restart docker-openfusion-1
```
### Ver uso de recursos
```bash
docker stats --no-stream
```
### Backup de datos
```bash
# PostgreSQL (CMS)
docker exec docker-postgres-1 pg_dump -U afterlife afterlife > backup_cms.sql
# MySQL (MapleStory 2)
docker exec maple2-db mysqldump -u root -pmaplestory --databases maple-data game-server > backup_ms2.sql
# Minecraft (mundo completo)
docker cp minecraft-ftb:/data/world ./backup_minecraft_world/
```