Skip to content

Deploy y mantenimiento

Mindset & Code edited this page Aug 18, 2026 · 5 revisions

Deploy y mantenimiento

🇬🇧 English first · 🇪🇸 Español más abajo.

The two commands

"deploy:marca":    "npm run build && firebase deploy --only hosting:marca",
"deploy:personal": "npm run build:personal && node scripts/desplegar-personal.mjs"

Everything else in package.json is dev, build, build:personal, lint and preview. There is no CI, no GitHub Action and no deploy hook: publishing is one command run by hand.

The brand build — npm run deploy:marca

npm install
npm run dev            # http://localhost:5173
npm run deploy:marca   # build + publish

firebase.json and .firebaserc between them fix the destination:

Field Value
Firebase project sales-weather-etl
Hosting target marca
Site proyectos-mindset-code
Public directory dist
Rewrite **/index.html

The rewrite is what makes a single-page app work on static hosting: any path returns index.html and React Router resolves it in the browser. The consequence is that every URL returns 200, including ones that do not exist — a typo in a link does not show up as a 404 in the logs.

--only hosting:marca is not optional dressing. The Firebase project hosts more than one site, and a bare firebase deploy would touch what the target excludes.

The personal build — npm run deploy:personal

scripts/desplegar-personal.mjs exists because the destination site's identifier cannot live in this repository: it is public and belongs to the organisation, and whoever reads it must not be able to reach the signed portfolio from here. So the script:

  1. Reads SITIO_PERSONAL from .env.personal — gitignored, present on one machine — and exits with a clear message if it is missing.
  2. Writes firebase.personal.json on the fly, pointing at that site and at dist-personal. That file is gitignored too.
  3. Copies personal/retrato.jpg into dist-personal/, warning rather than failing if it is not there.
  4. Deploys with --config firebase.personal.json.
  5. Deletes the temporary config in a finally, so it disappears whether or not the deploy succeeded.

Point 5 is the one that matters: a failed deploy that left the config behind would leave the site identifier sitting in the working tree, one git add . away from being published.

The portrait is copied after the build for the same class of reason. It lives in personal/ rather than public/ because Vite copies public/ wholesale into the output, so a portrait there would ship with the brand build — the one that must not carry a face.

Updating a dashboard's data

The JSON files are committed, so this is a normal commit:

# 1. Regenerate in the project that owns the data
#    (the three .mjs generators live in project-sales-weather-etl)
node generate_churn_json.mjs

# 2. Copy the files across
cp web/public/data/churn/*.json ../project-portfolio/public/data/churn/

# 3. Commit and publish
cd ../project-portfolio
git add public/data && git commit -m "Actualiza los datos de churn"
npm run deploy:marca

Nothing automates step 2. See Arquitectura del sitio for which generator produces which folder.

The embedded simulator is copied the same way and has already drifted. public/demos/revenue/ is a copy of project-revenue-management-web; the copy here carries a fix to the 7-day chart that the original does not. Copying the original over it would undo that fix. Back-porting the fix first is the way round it.

Local development

npm run dev

Vite serves public/ directly, so changing a JSON needs a browser refresh and no rebuild. npm run preview serves the built dist/ if you need to check the production bundle, and npm run lint runs ESLint 9 with the React Hooks and React Refresh plugins.

What .gitignore keeps out, and why

Entry Reason
.env.personal, personal/, firebase.personal.json everything that identifies or signs the personal variant
dist/, dist-marca/, dist-personal/, .firebase/ build output — the source is the source
CLAUDE.md, .claude/, agents/, skills/, .engram/ local tooling, not part of the site

Note that plain .env is not on the list: under Vite only VITE_-prefixed variables reach the bundle, and that file holds the shared build configuration, while anything that identifies a person goes in .env.personal.


🇪🇸 Español

Los dos comandos

"deploy:marca":    "npm run build && firebase deploy --only hosting:marca",
"deploy:personal": "npm run build:personal && node scripts/desplegar-personal.mjs"

Lo demás en package.json es dev, build, build:personal, lint y preview. No hay CI, ni GitHub Action, ni hook de despliegue: publicar es un comando lanzado a mano.

La compilación de marca — npm run deploy:marca

npm install
npm run dev            # http://localhost:5173
npm run deploy:marca   # compila y publica

Entre firebase.json y .firebaserc queda fijado el destino:

Campo Valor
Proyecto de Firebase sales-weather-etl
Destino de hosting marca
Sitio proyectos-mindset-code
Directorio público dist
Reescritura **/index.html

La reescritura es lo que hace que una aplicación de una sola página funcione sobre hosting estático: cualquier ruta devuelve index.html y React Router la resuelve en el navegador. La consecuencia es que todas las URL devuelven 200, también las que no existen — una errata en un enlace no aparece como un 404 en los registros.

--only hosting:marca no es un adorno. El proyecto de Firebase aloja más de un sitio, y un firebase deploy a secas tocaría lo que el destino deja fuera.

La compilación personal — npm run deploy:personal

scripts/desplegar-personal.mjs existe porque el identificador del sitio de destino no puede vivir en este repositorio: es público y pertenece a la organización, y quien lo lea no debe poder llegar desde aquí al portafolio firmado. Así que el script:

  1. Lee SITIO_PERSONAL de .env.personal —en .gitignore, presente en una sola máquina— y sale con un mensaje claro si falta.
  2. Escribe firebase.personal.json al vuelo, apuntando a ese sitio y a dist-personal. Ese fichero también está en .gitignore.
  3. Copia personal/retrato.jpg a dist-personal/, avisando en vez de fallar si no está.
  4. Despliega con --config firebase.personal.json.
  5. Borra la configuración temporal en un finally, de modo que desaparece haya salido bien o mal el despliegue.

El punto 5 es el que importa: un despliegue fallido que dejara la configuración atrás dejaría el identificador del sitio en el árbol de trabajo, a un git add . de publicarse.

El retrato se copia después de compilar por la misma clase de razón. Vive en personal/ y no en public/ porque Vite copia public/ entera a la salida, así que un retrato ahí se publicaría también en la compilación de marca — justo la que no debe llevar cara.

Actualizar los datos de un dashboard

Los JSON están commiteados, así que esto es un commit normal:

# 1. Regenerar en el proyecto dueño de los datos
#    (los tres generadores .mjs viven en project-sales-weather-etl)
node generate_churn_json.mjs

# 2. Copiar los ficheros
cp web/public/data/churn/*.json ../project-portfolio/public/data/churn/

# 3. Commit y publicación
cd ../project-portfolio
git add public/data && git commit -m "Actualiza los datos de churn"
npm run deploy:marca

El paso 2 no lo automatiza nada. En Arquitectura del sitio está qué generador produce cada carpeta.

El simulador embebido se copia igual y ya se ha separado del original. public/demos/revenue/ es una copia de project-revenue-management-web; la copia de aquí lleva un arreglo del gráfico de 7 días que el original no tiene. Copiar el original encima desharía ese arreglo. Llevar antes el arreglo al original es la forma de evitarlo.

Desarrollo local

npm run dev

Vite sirve public/ directamente, así que cambiar un JSON solo pide recargar el navegador, sin recompilar. npm run preview sirve el dist/ ya compilado si hace falta comprobar el bundle de producción, y npm run lint pasa ESLint 9 con los plugins de React Hooks y React Refresh.

Qué deja fuera .gitignore, y por qué

Entrada Razón
.env.personal, personal/, firebase.personal.json todo lo que identifica o firma la variante personal
dist/, dist-marca/, dist-personal/, .firebase/ salida de compilación — la fuente es la fuente
CLAUDE.md, .claude/, agents/, skills/, .engram/ herramientas locales, que no son parte del sitio

Conviene notar que el .env a secas no está en la lista: con Vite solo llegan al bundle las variables con prefijo VITE_, y ese fichero lleva la configuración de compilación compartida, mientras que todo lo que identifica a una persona va en .env.personal.

Clone this wiki locally