Skip to content

Repository files navigation

Ignixio

Plataforma de crowdfunding para startups — monorepo con pnpm + Turborepo. GitHub Actions valida cada PR, Dokploy clona y construye las imágenes directamente en el servidor OVH.

Frontend architecture reference: apps/web/ARCHITECTURE.md — routes, data flow, component map, Strapi conventions.

Arquitectura

┌─────────────────────────────────────────────────────┐
│               GitHub (gratis)                       │
│  Pull Request → GitHub Actions (ci.yml)             │
│    • lint + type-check + build (sin Docker)         │
│    • Required check para mergear a main             │
│  Merge a main → push                                │
└───────────────────────┬─────────────────────────────┘
                        │ webhook nativo (GitHub App)
┌───────────────────────▼─────────────────────────────┐
│               OVH (servidor propio)                 │
│  Dokploy                                            │
│    • Detecta el push y filtra por Watch Paths       │
│    • git clone del repo en el servidor              │
│    • docker build con cache local (rápido)          │
│    • ignixio-web  :3000  (contenedor web)           │
│    • ignixio-api  :1337  (contenedor api)           │
│    • PostgreSQL   :5432  (servicio Dokploy)         │
└─────────────────────────────────────────────────────┘

Estructura del monorepo

ignixio/
├── apps/
│   ├── api/                  # Strapi v5 (backend / CMS)
│   │   ├── src/
│   │   │   ├── api/          # Content types: project, pledge, category, saved-project, global, auth-provider
│   │   │   ├── middlewares/  # rate-limit, security
│   │   │   └── utils/        # populate-sanitizer
│   │   ├── .dockerignore
│   │   ├── Dockerfile        # Multi-stage con turbo prune
│   │   ├── package.json
│   │   └── README.md
│   └── web/                  # Next.js 16 (frontend)
│       ├── app/              # App Router (auth, account, dashboard, studio, projects, landing…)
│       ├── actions/          # Server Actions
│       ├── components/       # Componentes por dominio
│       ├── hooks/            # Custom hooks
│       ├── lib/              # Strapi client, analytics, utils
│       ├── store/            # Estado global (Zustand)
│       ├── .dockerignore
│       ├── Dockerfile        # Multi-stage con turbo prune + standalone
│       ├── package.json
│       └── README.md
├── packages/
│   ├── eslint-config/        # @ignixio/eslint-config
│   └── typescript-config/    # @ignixio/typescript-config
├── .github/
│   └── workflows/
│       └── ci.yml            # CI: lint + type-check + build de validación
├── .dockerignore
├── .editorconfig
├── .env.example              # Plantilla de todas las variables de entorno
├── .gitignore
├── .npmrc
├── .nvmrc                    # Node 20 LTS
├── .prettierrc
├── docker-compose.dev.yml    # PostgreSQL local para desarrollo
├── package.json
├── pnpm-workspace.yaml
└── turbo.json

Requisitos previos

Configuración inicial

1. Instalar dependencias

pnpm install

2. Configurar variables de entorno

cp .env.example .env
# Edita .env con tus valores
# Para el frontend también necesitas apps/web/.env.local (ver apps/web/README.md)

Entorno de desarrollo

Arrancar el entorno

pnpm dev

El script dev levanta PostgreSQL con Docker Compose y arrancan Strapi y Next.js en paralelo. No hace falta ejecutar Docker por separado.

O en terminales separadas:

docker compose -f docker-compose.dev.yml up -d   # PostgreSQL
pnpm --filter @ignixio/api dev                   # → http://localhost:1337/admin
pnpm --filter @ignixio/web dev                   # → http://localhost:3000

La primera vez que arranques Strapi te pedirá crear un usuario administrador desde el panel.

Detener el entorno

docker compose -f docker-compose.dev.yml down
# Strapi y Next.js se detienen con Ctrl+C en cada terminal

URLs del entorno de desarrollo

Servicio URL
Frontend (Next.js) http://localhost:3000
Backend (Strapi) http://localhost:1337
Panel admin Strapi http://localhost:1337/admin
PostgreSQL localhost:5432 (strapi_dev)

Pledges y pagos (MVP)

El flujo de aporte usa siempre documentId (proyecto y pledge). Tras POST /api/pledges, el frontend confirma el pago simulado con POST /api/pledges/:documentId/confirm, lo que marca el pledge como pagado y suma el importe a project.raised_amount. Los endpoints GET /api/users/me/pledges y GET /api/users/me/projects/:documentId/pledges alimentan Activity y la pestaña Funding del Creator Studio. La integración con Stripe queda fuera de este MVP.


Entorno de producción

El despliegue es automático y se reparte entre GitHub Actions (validación) y Dokploy (build + deploy):

Pull Request → main
      │
      ▼
GitHub Actions (.github/workflows/ci.yml)
  ├── Detecta qué cambió (apps/web, apps/api o ambas)
  ├── lint + type-check + build (sin Docker)
  └── Required check: bloquea el merge si falla
            │
            ▼ (merge a main)
git push origin main
      │
      ▼
Dokploy (OVH) — GitHub App connection
  ├── Recibe el webhook y filtra por Watch Paths
  ├── git clone del repo en el servidor
  ├── docker build con cache local (rápido)
  └── Reinicia el contenedor afectado (web, api o ambos)

Tres mecanismos garantizan que solo se despliega lo correcto:

  1. Branch protection en GitHub sobre main: el merge requiere CI verde, así main siempre es desplegable.
  2. Auto-deploy on push en Dokploy: cualquier commit en main dispara el ciclo.
  3. Watch Paths por aplicación en Dokploy: filtran qué contenedor se reconstruye. Un cambio solo en apps/api/** no toca el contenedor web, y viceversa.

Requisitos previos en producción

Antes del primer despliegue debes tener configurado en Dokploy:

  • PostgreSQL 16 corriendo como servicio
  • Aplicación ignixio-api conectada a GitHub (Source = GitHub, branch main, Dockerfile apps/api/Dockerfile) con dominio ignixio-api.silvak.dev + HTTPS y Watch Paths configurados
  • Aplicación ignixio-web conectada a GitHub (Source = GitHub, branch main, Dockerfile apps/web/Dockerfile) con dominio ignixio.silvak.dev + HTTPS y Watch Paths configurados

Y en GitHub:

Variable / Setting Tipo Valor
NEXT_PUBLIC_STRAPI_URL Variable https://ignixio-api.silvak.dev (usada por CI)
Branch protection main Setting Require status checks: Validate web, Validate api

Ya no se usan los secrets DOKPLOY_WEBHOOK_WEB ni DOKPLOY_WEBHOOK_API. Si vienen de la configuración anterior, bórralos.

Consulta la sección Despliegue en Dokploy para la configuración completa paso a paso.

Desplegar manualmente

  • Re-ejecutar validación: GitHub → Actions → CI → Run workflow (opción web, api o both).
  • Forzar despliegue sin commit: Dokploy → la app que quieras → botón Redeploy.

Probar las imágenes Docker en local antes de producción

Aunque ya no se construyen en CI, puedes reproducir lo que Dokploy hace en OVH:

# Imagen del frontend
docker build -f apps/web/Dockerfile -t ignixio-web:local \
  --build-arg NEXT_PUBLIC_STRAPI_URL=http://localhost:1337 .
docker run -p 3000:3000 ignixio-web:local

# Imagen del backend
docker build -f apps/api/Dockerfile -t ignixio-api:local .
docker run -p 1337:1337 --env-file apps/api/.env ignixio-api:local

Comandos disponibles

Comando Descripción
pnpm dev Levanta Postgres + todas las apps en modo desarrollo
pnpm build Compila todas las apps (con cache de Turborepo)
pnpm lint Ejecuta ESLint en todas las apps
pnpm type-check Comprobación de tipos TypeScript
pnpm clean Elimina artifacts de build y node_modules
pnpm prune:web Genera out/ con el subgrafo de web (para Docker)
pnpm prune:api Genera out/ con el subgrafo de api (para Docker)
pnpm format Formatea el código con Prettier

CI/CD — GitHub Actions

El archivo .github/workflows/ci.yml se encarga solo de validar. No construye imágenes Docker ni publica nada en registros — eso lo hace Dokploy directamente en el servidor OVH.

Jobs del pipeline:

  1. detect-changes: usa dorny/paths-filter para decidir si los cambios afectan a apps/web/** (más packages/**, pnpm-lock.yaml, package.json, turbo.json, .npmrc) y/o a apps/api/**.
  2. validate-web (condicional): instala dependencias con cache de pnpm, ejecuta lint, type-check y build (sin Docker) del paquete @ignixio/web.
  3. validate-api (condicional): mismo flujo para @ignixio/api. Inyecta variables dummy (APP_KEYS, JWT_SECRET, etc.) que Strapi exige en build time.

Branch protection en GitHub

Para que el CI actúe como puerta antes del despliegue, configúralo como required check en main:

  1. Ve a Settings → Branches → Branch protection rules → Add rule.
  2. Branch name pattern: main.
  3. Marca Require a pull request before merging.
  4. Marca Require status checks to pass before merging y selecciona:
    • Validate web
    • Validate api
  5. Guarda.

Variables requeridas en GitHub

Ve a Settings → Secrets and variables → Actions:

Nombre Tipo Descripción
NEXT_PUBLIC_STRAPI_URL Variable URL pública de Strapi (https://ignixio-api.silvak.dev). El job validate-web la usa para que next build no inline un valor incorrecto.

Si vienes de la configuración anterior, borra los secrets DOKPLOY_WEBHOOK_WEB y DOKPLOY_WEBHOOK_API: ya no se usan.

Disparar una validación manual

Desde Actions → CI → Run workflow, puedes forzar web, api o both.

Despliegue en Dokploy (OVH)

Dokploy actúa en modo GitHub App connection: detecta el push a main, clona el repo en el servidor y construye la imagen Docker localmente usando el Dockerfile correspondiente. Los Watch Paths deciden si cada contenedor se reconstruye o no.

Los dominios de producción son:

App URL
Frontend https://ignixio.silvak.dev
API / Admin https://ignixio-api.silvak.dev

Paso 1: Conectar Dokploy con GitHub

En Dokploy → Settings → Git Providers → GitHub → Install. Esto instala la GitHub App de Dokploy en tu cuenta u organización y le da acceso al repo ignixio. Es zero-config: no hace falta crear PATs ni registrar ghcr.io.

Paso 2: Crear el servicio PostgreSQL

En Dokploy → Services → New Service → Database → PostgreSQL 16.

Anota el host interno, usuario y contraseña generados (se usan en las variables de la API).

Paso 3: Crear la aplicación ignixio-api

En Dokploy → Applications → New Application:

  • Source: GitHub (el conectado en el Paso 1)
  • Repository: <tu-usuario>/ignixio
  • Branch: main
  • Build Type: Dockerfile
  • Dockerfile path: apps/api/Dockerfile
  • Build context: . (raíz del repo, necesario para que turbo prune vea todo el monorepo)
  • Auto Deploy: ON
  • Port: 1337
  • Domains: ignixio-api.silvak.dev — activa HTTPS (Let's Encrypt) en la pestaña Domains

Variables de entorno (pestaña Environment):

NODE_ENV=production
HOST=0.0.0.0
PORT=1337
PUBLIC_URL=https://ignixio-api.silvak.dev
IS_PROXIED=true
CORS_ORIGINS=https://ignixio.silvak.dev,https://ignixio-api.silvak.dev
APP_KEYS=<openssl rand -base64 32>,<openssl rand -base64 32>
API_TOKEN_SALT=<openssl rand -base64 32>
ADMIN_JWT_SECRET=<openssl rand -base64 32>
TRANSFER_TOKEN_SALT=<openssl rand -base64 32>
JWT_SECRET=<openssl rand -base64 32>
ENCRYPTION_KEY=<openssl rand -base64 32>
DATABASE_CLIENT=postgres
DATABASE_HOST=<host interno de PostgreSQL en Dokploy>
DATABASE_PORT=5432
DATABASE_NAME=<nombre de la base de datos>
DATABASE_USERNAME=<usuario>
DATABASE_PASSWORD=<contraseña>
DATABASE_SSL=false
CLOUDINARY_NAME=<cloud name>
CLOUDINARY_KEY=<api key>
CLOUDINARY_SECRET=<api secret>
AUTH_GOOGLE_ID=<client id de Google>
AUTH_GOOGLE_SECRET=<client secret de Google>
RESEND_API_KEY=<api key de Resend>
EMAIL_FROM=Ignixio <noreply@tudominio.com>
EMAIL_REPLY_TO=noreply@tudominio.com
FRONTEND_URL=https://ignixio.silvak.dev

Paso 4: Crear la aplicación ignixio-web

En Dokploy → Applications → New Application:

  • Source: GitHub
  • Repository: <tu-usuario>/ignixio
  • Branch: main
  • Build Type: Dockerfile
  • Dockerfile path: apps/web/Dockerfile
  • Build context: .
  • Auto Deploy: ON
  • Port: 3000
  • Domains: ignixio.silvak.dev — activa HTTPS (Let's Encrypt) en la pestaña Domains

Build Args (pestaña Build → Build Args, se inyectan como ARG en el Dockerfile):

NEXT_PUBLIC_STRAPI_URL=https://ignixio-api.silvak.dev
NEXT_PUBLIC_GOOGLE_ENABLED=true

Variables de entorno (pestaña Environment, disponibles en runtime):

NODE_ENV=production
NEXT_PUBLIC_STRAPI_URL=https://ignixio-api.silvak.dev
STRAPI_URL=https://ignixio-api.silvak.dev
STRAPI_API_TOKEN=<token read-only generado en el panel de Strapi>
AUTH_SECRET=<openssl rand -base64 32>
AUTH_URL=https://ignixio.silvak.dev
NEXT_PUBLIC_APP_URL=https://ignixio.silvak.dev
AUTH_GOOGLE_ID=<client id de Google>
AUTH_GOOGLE_SECRET=<client secret de Google>
NEXT_PUBLIC_GOOGLE_ENABLED=true

NEXT_PUBLIC_STRAPI_URL aparece dos veces a propósito: una como Build Arg (lo necesita Next al compilar el bundle del cliente) y otra como env var de runtime.

AUTH_SECRET es obligatorio en producción. Sin él, /api/auth/session devuelve 500 y las rutas /login y /register pueden redirigir incorrectamente al dashboard. Tras añadirlo, redeploy ignixio-web.

Paso 5: Configurar Watch Paths (clave para el monorepo)

Sin Watch Paths, cualquier push a main reconstruiría las dos apps aunque solo cambies un README. Para evitarlo, en cada aplicación ve a la pestaña Deployments → Watch Paths y añade los siguientes patrones, pulsando el botón "+" tras cada uno (si solo escribes y das a "Save" sin pulsar "+", no se guardan — issue conocido #2415).

ignixio-web:

apps/web/**
packages/**
pnpm-lock.yaml
package.json
turbo.json
.npmrc

ignixio-api:

apps/api/**
packages/**
pnpm-lock.yaml
package.json
turbo.json
.npmrc

Con esta configuración:

  • Cambio solo en apps/web/** → solo reconstruye ignixio-web.
  • Cambio solo en apps/api/** → solo reconstruye ignixio-api.
  • Cambio en packages/**, pnpm-lock.yaml, turbo.json o package.json raíz → reconstruye ambas (es lo correcto, son compartidos).
  • Cambio solo en README.md, .github/**, docker-compose.dev.yml, etc. → no reconstruye nada.

Paso 6: Verificar el flujo completo

  1. Abre un PR contra main. Comprueba que el workflow CI se ejecuta y aparece como required check.
  2. Mergea el PR. Dokploy debería recibir el webhook al instante y, según los paths tocados, reconstruir ignixio-web, ignixio-api, ambas o ninguna.
  3. Sigue el progreso en Dokploy → la app → pestaña Deployments.

Verificación post-deploy

  1. https://ignixio-api.silvak.dev/_health → responde 204 No Content.
  2. https://ignixio-api.silvak.dev/admin → carga el panel sin advertencias de mixed-content.
  3. Sube una imagen desde el panel → la URL debe comenzar con https://res.cloudinary.com/.
  4. Desde DevTools en https://ignixio.silvak.dev, ejecuta:
    fetch('https://ignixio-api.silvak.dev/api/...')
    La respuesta debe incluir la cabecera Access-Control-Allow-Origin: https://ignixio.silvak.dev.
  5. En los logs de Strapi confirma que no aparece el warning koa-session: secure cookies require https.
  6. NextAuth en el frontend:
    curl.exe -s "https://ignixio.silvak.dev/api/auth/session"
    # Debe devolver {} o null, no 500 ni mensaje de configuración
    
    curl.exe -sI "https://ignixio.silvak.dev/login"
    # Sin cookies de sesión: debe ser 200, no 307 Location: /dashboard

Pruebas locales de Docker

Reproduce localmente lo que Dokploy ejecuta en OVH:

# Probar la imagen web localmente
docker build -f apps/web/Dockerfile -t ignixio-web:local \
  --build-arg NEXT_PUBLIC_STRAPI_URL=http://localhost:1337 .
docker run -p 3000:3000 ignixio-web:local

# Probar la imagen api localmente
docker build -f apps/api/Dockerfile -t ignixio-api:local .
docker run -p 1337:1337 --env-file .env ignixio-api:local

About

Crowdfunding platform for startups

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages