Proyectos y espacios
Un proyecto agrupa servicios que hablan entre sí; un espacio agrupa proyectos y a las personas que los comparten. Esta página explica los dos y el lienzo en el que se dibuja un proyecto.
Proyectos
El nombre del proyecto da nombre a los hosts de sus servicios: el proyecto tienda publica api en tienda-api.fundaia.com. Sus servicios comparten una red privada en la que cada uno se alcanza por su nombre.
Cada proyecto nace con un entorno, production, y puede tener más: ver Entornos. La API identifica casi todo por el par servicio en un entorno (serviceEnvironmentId), no por el servicio a secas; ver API HTTP.
fundaia project new tienda
fundaia project rename tienda "Tienda" --description "La web y su API"
fundaia services tienda
Foto del proyecto
Cada proyecto puede llevar una foto (su logo) en las tarjetas, la lista, la barra lateral, el lienzo y la app del iPhone. Sin foto se dibuja su inicial sobre un color sacado del nombre.
- Se busca sola: cuando se crea el primer servicio que sale de un repositorio de GitHub y el proyecto todavía no tiene foto, Fundaia busca en ese repositorio un
logo, unicono unfavicon(.svg,.png,.webp,.jpg,.gifo.ico). Mira primero en.fundaia/, luego en la raíz y enpublic/,app/,static/,assets/o.github/; en un monorepo, dentro de la carpeta del servicio. Si no hay ninguno y el repositorio es de una organización, usa su avatar. - Se sube a mano desde Editar el proyecto (PNG, JPEG, WebP, GIF, SVG o ICO, hasta 512 KB) y sustituye a la que hubiera. Para elegir la del repositorio sin subir nada, pon tu logo en
.fundaia/icon.pngy pulsa Buscar en el repositorio. - Quitarla es definitivo: la búsqueda automática no vuelve a poner una que alguien quitó; pulsar Buscar en el repositorio sí.
Para leer el repositorio hace falta la GitHub App de la instancia. Cada cambio queda en la historia del proyecto.
fundaia project picture tienda --file logo.svg
fundaia project picture tienda --find
fundaia project picture tienda --remove
Desde MCP: find_project_picture y remove_project_picture (subir bytes no es cosa de una herramienta).
Notas del proyecto
Cada proyecto tiene unas notas en Markdown para lo que no cabe en ningún ajuste: cómo se despliega, a quién preguntar, qué vigilar, la lista de antes de un lanzamiento. Las ve y las edita todo el que ve el proyecto, y cada cambio queda en su historia con quién lo hizo.
- En la web, el botón Notas del lienzo las muestra y las edita (Escribir y Vista previa; ⌘Enter guarda). En el iPhone, en Gestionar › Notas.
- Admiten títulos, listas, listas de tareas (
- [ ],- [x]), bloques de código, citas,código, negrita, cursiva y enlaceshttps://omailto:; nada de HTML. Hasta 20.000 caracteres. - Los agentes las leen:
read_project_notesantes de tocar un proyecto que no conocen, ywrite_project_notespara dejar lo que aprendieron (el texto entero, no un añadido).
fundaia project notes tienda
fundaia project notes tienda --set NOTAS.md
cat NOTAS.md | fundaia project notes tienda --set -
fundaia project notes tienda --clear
Recientes y lo que pasó mientras no estabas
- Recientes: los últimos proyectos y servicios que abriste salen en la portada y los primeros en la paleta (⌘K), para volver con un toque. Se guardan en ese navegador o en ese iPhone, no en tu cuenta.
- Desde tu última visita: si vuelves después de más de media hora, la portada resume los despliegues que hubo mientras tanto (cuántos salieron bien, cuántos fallaron y cuáles siguen en curso) con un enlace a cada servicio que falló. Mira como mucho las últimas 24 horas; la ✕ lo da por visto.
Favoritos
La estrella de una tarjeta (o fundaia project star tienda, o favorite_project) pone el proyecto el primero en la lista de proyectos y en la barra lateral, dentro de su espacio. Es personal: nadie más ve tu orden. fundaia project unstar tienda la quita y fundaia projects marca los favoritos con ★.
Nombres de servicio
Los nombres de servicio son únicos dentro del proyecto sin distinguir mayúsculas, porque las referencias se resuelven por nombre (${{ Postgres.DATABASE_URL }}). shared está reservado: es como se nombra en una referencia el alcance del proyecto. El nombre es del proyecto, no de un entorno: renombrar o eliminar un servicio lo hace en todos sus entornos a la vez.
Exportar e importar
Un proyecto cabe en un archivo: Exportar manifiesto en la paleta (o fundaia export tienda -o tienda.fundaia.json) escribe sus servicios, de dónde sale cada uno, sus ajustes, volúmenes, conexiones y variables. Importar en la lista de proyectos (o fundaia import) lo vuelve a crear, en esta instancia o en otra:
fundaia export tienda -o tienda.fundaia.json
fundaia import tienda.fundaia.json --name "Tienda (copia)"
fundaia import tienda.fundaia.json --workspace equipo --deploy
- Es una descripción, no una copia de seguridad: los secretos no viajan. Al importar se listan los que faltan, con la orden que rellena cada uno. Los componentes del catálogo nacen con credenciales nuevas, los volúmenes vacíos y un servicio de código subido espera a
fundaia up. - Primero se crean los componentes y después las aplicaciones, así que las conexiones (
${{ Postgres.DATABASE_URL }}) vuelven a apuntar a sus copias. Un servicio público recibe su propio dominio. - No se despliega nada salvo que lo pidas (
--deploy): mejor rellenar antes los secretos. Un servicio que aquí no se puede crear (un repositorio al que tu cuenta no llega) se salta y dice por qué; los demás siguen. - Con MCP,
export_projecteimport_project.
Importar un docker-compose
Importar acepta también un docker-compose.yml (o fundaia import docker-compose.yml): cada servicio del compose se convierte en un servicio, en un proyecto nuevo o, con Varios a la vez → Importar docker-compose… en el lienzo (o --project), en uno que ya tienes y en el entorno que estés mirando.
fundaia import docker-compose.yml --name tienda
fundaia import docker-compose.yml --repo pepito/tienda --branch main --deploy
fundaia import compose.yaml --project tienda --env staging
| En el compose | Aquí |
|---|---|
image: | Un servicio de imagen (postgres:16 pasa a docker.io/library/postgres:16) |
build: | Se construye desde el repositorio de GitHub que indiques (--repo), con build.context como directorio. Sin repositorio se omite y se dice por qué |
environment: (lista o mapa) | Variables. ${VAR:-valor} toma el valor por defecto; un ${VAR} que el archivo no define queda pendiente y se lista, como los secretos de un manifiesto. Las claves con pinta de contraseña se guardan cifradas |
ports: | El primero es el puerto del contenedor. Si se publicaba al host, el servicio se hace público con su dominio (nunca una base de datos ni lo que solo escuchaba en 127.0.0.1) |
volumes: con nombre o anónimos | Volúmenes vacíos en la misma ruta. Los bind mounts (./src:/app) no viajan y se avisa |
command: y entrypoint: | El comando de arranque (el entrypoint de la imagen no se sustituye: van juntos detrás) |
mem_limit: o deploy.resources.limits | Memoria y CPU |
depends_on: | El orden: primero los que otros usan |
- Los servicios se siguen encontrando por su nombre: el alias en la red es el slug del servicio. Si un nombre del compose no cabe en un host (
my_db), su slug esmy-db, se avisa y las direcciones de las variables que lo nombraban se reescriben. - Las imágenes de bases de datos conocidas (Postgres, MySQL, MariaDB, Redis, Mongo, ClickHouse, MinIO…) se importan tal cual, y el informe sugiere el componente del catálogo equivalente, con contraseña generada, copias y visor de datos.
- No se despliega nada salvo que lo pidas (
--deploy): antes conviene rellenar las variables pendientes. Un servicio que no se puede crear (un nombre que ya existe en el proyecto, un perfil, una imagen que depende de una variable sin valor) se omite con su razón. - Con MCP,
import_compose, que recibe el texto del YAML.
Plantillas de proyecto
Una plantilla es una pila de varios servicios lista en un clic: los componentes del catálogo que necesita, la aplicación con su imagen oficial, las variables que los unen (${{ Postgres.DATABASE_URL }}), contraseñas y claves generadas, sus volúmenes y un dominio para el servicio que se publica. Se elige en Nuevo proyecto → Desde una plantilla… o, dentro de un proyecto, con clic derecho en el lienzo → Varios a la vez → Plantilla de proyecto….
| Clave | Qué monta |
|---|---|
wordpress | WordPress sobre MySQL |
ghost | Ghost sobre MySQL |
metabase | Metabase con su configuración en Postgres |
umami | Umami (analítica web) sobre Postgres |
n8n | n8n con sus flujos en Postgres |
directus | Directus sobre Postgres, con caché en Valkey |
plausible | Plausible Community Edition: Postgres y ClickHouse |
gitea | Gitea sobre Postgres (Git por HTTPS) |
uptime-kuma | Uptime Kuma |
listmonk | Listmonk (newsletters) sobre Postgres |
fundaia stack list
fundaia stack new wordpress --name blog
fundaia stack add tienda umami --env staging
- Se despliega entera, primero las bases de datos, salvo
--no-deploy. No hay nada que rellenar: el informe dice cómo entrar la primera vez. - Un nombre que ya existe en el proyecto lleva sufijo (
MySQL-2) y las referencias lo siguen, así que una plantilla nunca toca lo que ya tenías. - Con MCP,
list_stacksyadd_stack(sinproject, crea el proyecto). - Cada plantilla, y cada componente del catálogo, tiene su página pública en
/plantillascon un botón para tu README: Plantillas y botón «Desplegar en Fundaia».
Eliminar un proyecto
Eliminar un proyecto se lleva todo: servicios, contenedores, volúmenes con sus datos, copias de seguridad, dominios con su registro DNS e historial. No hay archivado ni vuelta atrás, y por eso hay que escribir el nombre (o el slug) del proyecto para confirmarlo.
fundaia project delete tienda --confirm tienda
Entornos
Un entorno es una copia del proyecto que corre a la vez y sin tocar a las demás: staging para probar lo que va a salir, demo para enseñar algo. production es el entorno por defecto, se crea con el proyecto y no se puede eliminar ni dejar de ser el por defecto.
Cada entorno tiene sus propios contenedores, su red privada, sus variables, sus volúmenes y sus dominios. Un servicio está en un entorno cuando se ha creado o copiado ahí: crear un servicio lo crea solo en el entorno en el que estás, y para tenerlo en otro se copia.
fundaia envs tienda # los entornos, con sus servicios
fundaia env new tienda staging # copia de production, y se despliega
fundaia env new tienda demo --from staging --no-deploy
fundaia env new tienda sandbox --empty
fundaia env copy tienda api --from production --to staging
fundaia --env staging services tienda # cualquier comando, en otro entorno
fundaia env rename tienda staging "Preproducción"
fundaia env rm tienda staging --confirm staging
fundaia env promote tienda staging production --dry-run # qué cambiaría
fundaia env promote tienda staging production # producción arranca las imágenes de staging
fundaia env copy-data tienda production staging --confirm staging
fundaia env diff tienda production staging # qué variables cambian
fundaia env new tienda demo --ttl 7d # se borra solo dentro de una semana
fundaia env expire tienda demo never
En la interfaz, el entorno se elige junto al nombre del proyecto (Nuevo entorno… crea otro), va en la dirección (?entorno=staging) y se renombra o elimina desde Editar proyecto. Un servicio se copia a otro entorno desde su menú en el lienzo: Copiar a otro entorno…. El mismo selector, desde el entorno en el que estás, tiene Promover a…, Comparar variables con… y Copiar datos a….
Qué se copia y qué no
| Se copia | No se copia |
|---|---|
| Cada servicio, con todos sus ajustes: memoria, salud, reposo, puerto, comando, réplicas, rama, copias programadas… | El estado: la copia empieza sin desplegar |
| Su origen: el repositorio y la rama, la imagen o el componente del catálogo | El código subido a mano: se sube otra vez en ese entorno |
| Un Containerfile editado a mano, y el fichero de un balanceador o un gateway | El cifrado de un bucket: se activa cuando esté desplegado |
| Las variables: los secretos se cifran de nuevo, los sellados siguen sellados y las referencias apuntan a las copias del mismo entorno | Los datos: cada volumen empieza vacío, en la misma ruta y con el mismo tamaño (se copian aparte) |
| Los componentes del catálogo con contraseñas nuevas, y las variables que añadiste | Los dominios: un servicio público recibe uno nuevo con el entorno en el nombre |
| Las variables del propio entorno | Los workflows: son del proyecto |
Una copia sigue la misma rama que su origen y, si despliega sola al hacer push, despliega en los dos entornos: cambia la rama en los ajustes de la copia si staging debe seguir otra.
Una referencia a un servicio que el entorno de destino no tiene se queda fuera y se avisa. Al crear el entorno, las copias se despliegan en orden: primero lo que otros usan (las bases de datos), luego lo que lo usa. La respuesta dice qué pasó con cada servicio y por qué.
Promover un entorno a otro
Cuando lo que hay en staging está bien, promoverlo hace que production arranque exactamente las mismas imágenes, sin construir nada: lo que se probó es lo que sale. Para cada servicio que está en los dos entornos (o los que nombres), se crea en el destino un despliegue nuevo, con motivo promovido desde otro entorno, que arranca la imagen que sirve hoy el origen. Va en orden: primero lo que otros usan.
- Las variables no viajan: cada entorno conserva las suyas, así que producción sigue hablando con su base de datos y con sus claves.
- Antes de ejecutar, el plan: qué servicios cambian y de qué commit o imagen a cuál (
--dry-run, o la ventana de Promover a…). Un servicio sin un despliegue vivo en el origen, caído allí, que ya corre esa imagen o cuyo espacio no puede desplegar se deja como está y dice por qué. - Una imagen construida aquí pasa a llamarse también como las del destino, así que sus vueltas atrás y la limpieza de imágenes la tratan como suya; una de un registro se usa tal cual, por su id.
- El comando previo (las migraciones) sí se ejecuta: la base de datos del destino no las ha visto. Con MCP,
promote_environment(dryRun: truepara el plan).
Copiar datos entre entornos
Para probar con datos de verdad, Copiar datos a… (o fundaia env copy-data) sustituye lo que tienen los volúmenes de un entorno por lo que tienen los del otro, volumen a volumen y en la misma ruta. Para cada servicio:
- se archiva el volumen del origen, que sigue funcionando (igual que una copia de seguridad);
- se hace una copia de seguridad de lo que tenía el destino, y si falla no se toca nada;
- el servicio del destino se para, se escriben sus datos y vuelve a arrancar, falle o no.
Destruye los datos del destino, así que hay que escribir su nombre (o su slug) para confirmarlo; si el destino es el entorno por defecto, su nombre exacto. Lo que había se recupera con fundaia backups restore. Con MCP, copy_environment_data con confirm.
Comparar variables
Comparar variables con… (o fundaia env diff tienda production staging) enseña, servicio a servicio y para las variables compartidas del entorno, las claves que solo tiene uno, las que tienen valores distintos y cuántas coinciden. Un secreto nunca se muestra: se compara por una huella y solo se dice si es igual o distinto. Una referencia se compara tal como está escrita (${{ Postgres.DATABASE_URL }} es igual en los dos aunque apunte a bases distintas). Con MCP, compare_environments.
Entornos que caducan
Un entorno para enseñar o probar algo puede borrarse solo: al crearlo (Caduca en la ventana, --ttl 7d, ttl en MCP) o después, desde Editar proyecto → Entornos (el reloj), fundaia env expire tienda demo 3d o set_environment_expiry. Las duraciones son un número y una unidad (90m, 48h, 7d, 2w), entre una hora y un año, contadas desde ese momento; never la quita. El selector y los ajustes enseñan cuánto le queda.
Cada cinco minutos se borran los que han caducado, exactamente como si los eliminaras tú, y el historial lo apunta a nombre de Fundaia. El entorno por defecto no caduca nunca.
Nombres en cada entorno
production conserva los nombres de siempre. En los demás entornos, el slug del entorno va detrás del servicio, con dos guiones:
production | staging | |
|---|---|---|
| Dominio generado | tienda-api.fundaia.com | tienda-api--staging.fundaia.com |
| Red privada | infra-tienda-production | infra-tienda-staging |
Dentro de cada entorno los servicios se siguen llamando por su nombre (http://api:3000), porque cada uno tiene su red. Renombrar un entorno no cambia su slug, así que no cambia ninguna dirección.
Lo que cuesta
Un entorno consume lo mismo que sus servicios: una copia de un proyecto con un Postgres y una API reserva otra vez su memoria y sus volúmenes, y se factura igual. Las copias duermen como las de production.
Eliminar un entorno borra sus servicios en ese entorno, sus contenedores, sus volúmenes con lo que tengan dentro, sus copias de seguridad y sus dominios, y no toca los demás. Hay que escribir su nombre (o su slug) para confirmarlo.
Un entorno por pull request
Con Editar proyecto → Entornos → Un entorno por pull request (o fundaia previews tienda on), cada pull request que se abre en un repositorio del proyecto crea **pr-<número>**: una copia de producción en la que los servicios de ese repositorio construyen la rama del pull request y se vuelven a desplegar con cada push. Los servicios públicos reciben su propia dirección, así que el cambio se puede probar y enseñar antes de fusionarlo. Al cerrar el pull request, fusionado o no, el entorno se borra con todo lo que tenga.
fundaia previews tienda # si está activado y qué entornos de preview hay abiertos
fundaia previews tienda on
fundaia previews tienda off
- Nunca para un fork: su código es de otra persona y la copia lleva los secretos del proyecto.
- Cada preview es una copia entera (memoria, bases de datos nuevas y vacías, direcciones), con lo que eso cuesta; si no cabe en la máquina, no se crea y queda en los registros.
- **Necesita el webhook de la GitHub App con el evento *Pull request***: es lo único que avisa de que se abrió o se cerró uno. Sin él no se crea nada; un preview que se quede huérfano se borra como cualquier otro entorno.
- Con MCP,
read_preview_environmentsyset_preview_environments.
Promover sola: la promoción automática
Una regla entre dos entornos: **cuando staging despliega bien, promover a production. Cada treinta segundos, para cada servicio cuya versión en el origen lleve los minutos que digas en marcha y sana (diez si no), Fundaia hace exactamente lo que Promover a…**: arranca esa imagen en el destino, sin construir, con sus variables y su comando previo.
fundaia env auto-promote add tienda staging production # todos los servicios, 10 min
fundaia env auto-promote add tienda staging production api --minutes 30
fundaia env auto-promote list tienda # cómo fue la última revisión
fundaia env auto-promote rm tienda apm_…
En la web, en Editar proyecto → Entornos → Promoción automática; con MCP, add_auto_promotion, list_auto_promotions y remove_auto_promotion.
- Nunca promueve dos veces la misma versión: si en producción falla, no lo reintenta en bucle; el siguiente despliegue bueno de staging es el siguiente intento.
- Espera mientras el origen o el destino se están desplegando, mientras la versión no lleva el tiempo pedido o el servicio está caído, y mientras el destino está congelado: sale cuando la congelación termina.
- El historial lo apunta a nombre de Fundaia y con la regla (promovió automáticamente staging → production), y los avisos por webhook del proyecto reciben Promoción automática (
environment-promoted). - Una regla hacia un entorno protegido pide su nombre al crearla; después promueve sin preguntar.
Entornos protegidos
Marcar un entorno como protegido hace que cada acción a mano que lo cambia pida escribir su nombre: desplegar, reconstruir, reiniciar, volver atrás, dormir, actuar en lote, promover a él, cambiar sus variables (las del servicio y las compartidas de ese entorno), restaurar una copia, quitar un volumen y programar acciones o promociones automáticas hacia él.
fundaia env protect tienda production
fundaia deploy tienda api --confirm production
fundaia env unprotect tienda production --confirm production
En la web, un interruptor por entorno en Editar proyecto → Entornos, y al desplegar aparece una ventana donde escribirlo; con MCP, protect_environment y confirm en las herramientas que cambian algo (confirmEnvironment en seal_variable y restore_backup, cuyo confirm ya es otra cosa).
- Lo automático (un push, un deploy hook, una acción programada, una promoción automática) no pide nada: lo gobiernan las congelaciones.
- Quitar la protección también pide el nombre. Borrar un servicio o un entorno y copiar datos ya lo pedían; las variables compartidas de todo el proyecto no, porque no reinician nada y llegan con el siguiente despliegue, que sí lo pide.
- No hay aprobación de un administrador: proteger es pedir atención, no permisos.
Espacios
Todo proyecto pertenece a un espacio. Cada cuenta tiene el suyo, y se pueden crear espacios compartidos para trabajar con otras personas: quien pertenece a un espacio ve y opera todos sus proyectos, y nada más. Un recurso de otro espacio responde igual que uno que no existe.
| Rol en el espacio | Qué puede hacer |
|---|---|
| Administrador | Todo, más invitar, cambiar roles y quitar miembros |
| Miembro | Ver y operar los proyectos del espacio |
fundaia workspace list
fundaia workspace members equipo
fundaia workspace invite ana@ejemplo.com --workspace equipo
fundaia project move tienda equipo # compartir un proyecto es moverlo a un espacio
El espacio es también lo que se factura: plan, límite de gasto y crédito del agente van por espacio. Ver Facturación.
Exigir doble factor
Un administrador puede exigir doble factor a todo el espacio (Espacios → Seguridad, o fundaia workspace 2fa on --workspace equipo), como en una organización de GitHub: quien no tenga una passkey o un código de verificación no entra en ningún proyecto del espacio, por ninguna vía (web, fundaia, MCP, tokens), hasta que añada uno en Cuenta y seguridad; en cuanto lo añade, entra. La lista de miembros marca quién lo tiene (fundaia workspace members lo dice en la columna 2fa).
- Para activarlo hay que tenerlo: exigir lo que te falta te dejaría fuera de tu propio espacio.
- La cuenta que administra la instancia nunca se queda fuera.
- Con MCP,
require_second_factor;list_workspacesdice qué espacios lo exigen.
El lienzo
Cada proyecto se dibuja como un lienzo: los servicios son nodos y las conexiones, flechas.
- Clic derecho en el vacío añade un servicio en ese punto.
- Clic derecho en un nodo despliega, reinicia, para, conecta o elimina.
- Clic en un nodo abre el servicio.
Cada nodo lleva el logo de su tecnología, el host en el que responde, su estado y su volumen, si lo tiene. Las flechas salen de las referencias entre variables: una flecha por pareja, con las claves que se leen en la etiqueta.
fundaia canvas show tienda --map # el dibujo, con las coordenadas de cada nodo
fundaia canvas move tienda api --x 380 --y 80
fundaia canvas arrange tienda # recoloca todo: lo que alimenta a algo, a su izquierda
fundaia canvas arrange tienda --layout grid
Lo que pasa, en directo
La interfaz avisa de lo que hacen otras personas y la propia plataforma: un despliegue que alguien lanzó, un push que desplegó solo, una variable que cambió. En la terminal es fundaia watch, para toda la cuenta, un proyecto o un servicio. De las variables llega el nombre, nunca el valor.
El historial de un proyecto queda en su pestaña de actividad y en fundaia activity tienda: despliegues, variables, dominios y quién leyó qué registros, hecho desde la web, el CLI, el MCP o por la plataforma.