# L4.1 — Build de produção no deploy (assets minificados + hasheados)

**Objetivo (P1):** entregar o CSS do admin compilado, minificado e versionado por hash,
habilitando a regra `immutable` de L0.3 sem risco de invalidação quebrada no redeploy.

Seed: `51dd` (L4.1 Build de producao no deploy).

## Contexto / problema encontrado

- `public/assets/css/app.css` estava com **0 bytes**: o `deploy.sh` nunca rodava o build
  de assets e o `webpack.mix.js` compilava para `public/css/app.css` (caminho não
  referenciado por nenhuma view — as views usam `public/assets/**`). Resultado: o admin
  perdia o estilo principal (Bootstrap + icheck) desde sempre.
- `public/mix-manifest.json` era um **arquivo frankenstein**: mesclava os campos de PWA
  (`short_name`/`name`/`description`) com entradas obsoletas do Mix (`/css/app.css`,
  `/js/icheck.js` — arquivos que nem existiam). 8 layouts de portal referenciavam
  `/mix-manifest.json` como PWA manifest.
- **Toolchain incompatível:** `laravel-mix@1.7` / `webpack@3` / `node-sass@4.14` não
  compilam em Node 26 (erro de build nativo do `node-sass` — Python 2 em `node-gyp`).
  Decisão: **build em CI/local + commit do resultado** (não rodar `npm` no `deploy.sh`),
  e **versionar com hash** para a regra `immutable` de L0.3 funcionar corretamente.

## O que foi feito

1. **Manifest do Mix desacoplado do PWA**
   - `git mv public/mix-manifest.json public/manifest.webmanifest` (preserva os campos PWA).
   - 8 layouts de portal (`default`, `modelo1…6`, `newsbit`) atualizados para
     `<link rel="manifest" href="{{ url('/manifest.webmanifest') }}">`.
   - `public/mix-manifest.json` agora é **só** o manifest do Mix:
     `{ "/assets/css/app.css": "/assets/css/app.css?id=<hash>" }`.

2. **CSS do admin compilado e versionado**
   - `resources/assets/sass/app.scss` (Bootstrap + icheck) →
     `public/assets/css/app.css` (**minificado, 176 KB**).
   - `webpack.mix.js` aponta a saída para `public/assets/css` e remove as cópias órfãs
     em `public/js` (não referenciadas).
   - `admin/layouts/app.blade.php:46` usa `{{ HTML::style(mix('assets/css/app.css')) }}`
     → gera `<link ... href="/assets/css/app.css?id=<hash>">`. Sob a regra L0.3
     (`<FilesMatch "\.(css|js|...)">` + `immutable`), o nome hasheado garante bust de
     cache no redeploy sem CSS stalecado.
   - O `icheck` (todas as skins) é **inline** no `app.css`; suas sprites PNG foram
     copiadas para `public/assets/css/icheck/*.png` e os `url()` reescritos para
     `/assets/css/icheck/...`.

3. **Validação**
   - `app.css` > 0 e minificado (176326 bytes, 4 quebras de linha).
   - `mix('assets/css/app.css')` resolve para `/assets/css/app.css?id=22aa071c1d`
     (testado via `php artisan tinker`).
   - `HTML::style(mix(...))` renderiza `<link rel="stylesheet" href="…/assets/css/app.css?id=22aa071c1d">`.
   - PWA servido em `/manifest.webmanifest`; nenhuma referência restante a `/mix-manifest.json`.

## Como reconstruir (reproducibilidade)

O `node-sass` não builda em Node moderno. Duas opções:

- **CI com Node compatível (recomendado para o pipeline real):** `npm ci && npm run production`
  com `node-sass`/`webpack` funcionais regenera `public/assets/css/app.css` e sobrescreve
  `public/mix-manifest.json`. O `webpack.mix.js` já está correto para isso.
- **Fallback Dart Sass (usado neste ambiente Node 26):** como `node-sass` falha, o artifact
  foi gerado com `sass` (Dart Sass, puro-JS) compilando `resources/assets/sass/app.scss`
  com `loadPaths=[node_modules, resources/assets/sass]`, inlining o `icheck` (incluindo
  `@import url()` aninhados e sprites) e copiando as PNG para `public/assets/css/icheck/`.
  O hash no `mix-manifest.json` deve ser recalculado (`md5sum public/assets/css/app.css`)
  caso o CSS mude.

`package.json` ganhou `sass` como `devDependency` para documentar esse fallback.

## Arquivos

- `webpack.mix.js`, `resources/assets/sass/app.scss` (fonte, inalterado semanticamente)
- `public/assets/css/app.css` (gerado), `public/assets/css/icheck/*.png` (gerado)
- `public/mix-manifest.json` (manifest do Mix), `public/manifest.webmanifest` (PWA)
- `resources/views/admin/layouts/app.blade.php`
- `resources/views/portal/layouts/{default,modelo1…6,newsbit}/.../head.blade.php`
