diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8ec59ff..ae20b1e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -48,6 +48,6 @@ jobs: docker run --rm \ -e DOCKER_API_VERSION=1.44 \ -v /var/run/docker.sock:/var/run/docker.sock \ - -v ~/.docker/config.json:/config.json \ + -v $DOCKER_CONFIG/config.json:/config.json \ containrrr/watchtower \ --run-once --cleanup diff --git a/GEMINI.md b/GEMINI.md index 44940b4..d6b34d9 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -26,4 +26,4 @@ 4. **Upload de Arquivos:** Proibido o uso de Base64 para envio de novos arquivos ao servidor. Use obrigatoriamente `FormData` e envie o objeto `File/Blob` para as rotas de API que integram com o MinIO. 5. **Build & Deploy Stability:** O pipeline de deploy deve obrigatoriamente utilizar `runs-on: self-hosted` e compilar apenas a plataforma `linux/arm64` (sem emulação QEMU). A atualização da stack em produção deve ser automatizada via container transiente do Watchtower. 6. **Express Compatibility**: Avoid using raw `/*` wildcards in Express 5 routes; use Regex paths (`/^\/route\/(.+)$/`) for compatibility with `path-to-regexp` v8. -7. **Frontend Independence**: NEVER import files from `services/` or `server.js` directly into React components to prevent Node.js/SDK leakage (causes White Screen). Use `helpers.ts` for UI logic. +7. **Frontend Independence**: NEVER import files from `services/` or `server.js` directly into React components to prevent Node.js/SDK leakage (causes White Screen). Physical isolation is enforced: backend-only services (like MinIO/S3 storage) MUST stay outside the `src/` directory in Vite/React projects. Use `helpers.ts` for UI logic and standard `fetch` for API calls. diff --git a/MEMORY.md b/MEMORY.md index 6fb05bf..a4cc17a 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -1,6 +1,6 @@ # MEMORY.md - Contexto de Desenvolvimento -## 📅 Estado Atual (21/04/2026) +## 📅 Estado Atual (22/04/2026) - [x] Correção do "Bug da Tela Preta" na câmera ao alternar para câmera traseira no celular. - [x] Unificação do servidor de produção: Dockerfile agora utiliza `server.selfhosted.js` (Manager e Portal). @@ -11,7 +11,10 @@ - [x] Correção do Crash 404 no Portal: Injeção da pasta `src/services` no container de produção para permitir o import do `storage.js`. - [x] Correção das Imagens de Prova: Normalização das URLs nas questões de avaliações (Portal e Manager). - [x] Estabilização de CI/CD: Transição para `runs-on: self-hosted` (ARM64 nativo) eliminando lentidão e crashes do QEMU. -- [x] Fix Tela Branca (Portal): Refatoração de `normalizePhotoUrl` para `helpers.ts` isolado, evitando vazamento de SDK de Backend no Navegador. +- [x] Fix Tela Branca (Portal): Isolamento Físico absoluto do `storage.js` (SDK Backend) para pasta fora do `src` (server-only). Isso impede vazamentos de Node.js no navegador. +- [x] Correção Financeiro (Portal): Resolvido erros de renderização em `Financeiro.tsx` e inconsistência de tipos em `Notifications.ts`. +- [x] Pipeline Deploy: Ajustado volume do Docker no GitHub Actions de `~/.docker` para `$DOCKER_CONFIG` para compatibilidade total com o Runner. +- [x] Normalização de Imagens: Todas as fotos de alunos no Portal agora passam pela vacina `normalizePhotoUrl`. - [ ] Próximo Passo: Verificar se o Watchtower sincronizou as imagens corretamente na produção. ### 💳 Módulo Financeiro (Portal do Aluno) diff --git a/portal/check_portal.mjs b/portal/check_portal.mjs new file mode 100644 index 0000000..f24bd89 --- /dev/null +++ b/portal/check_portal.mjs @@ -0,0 +1,15 @@ +import puppeteer from 'puppeteer'; + +(async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + + page.on('console', msg => console.log('BROWSER CONSOLE:', msg.text())); + page.on('pageerror', error => console.error('BROWSER ERROR:', error.message)); + page.on('requestfailed', request => console.error('REQUEST FAILED:', request.url(), request.failure().errorText)); + + await page.goto('http://localhost:5173/', { waitUntil: 'networkidle0' }).catch(e => console.log(e)); + + await page.screenshot({ path: 'screenshot.png' }); + await browser.close(); +})(); diff --git a/portal/server.selfhosted.js b/portal/server.selfhosted.js index 65bfffe..3d8fffd 100644 --- a/portal/server.selfhosted.js +++ b/portal/server.selfhosted.js @@ -17,7 +17,7 @@ import pg from 'pg'; import path from 'path'; import { fileURLToPath } from 'url'; import multer from 'multer'; -import { uploadAtestado, s3Client } from './src/services/storage.js'; +import { uploadAtestado, s3Client } from './server/services/storage.js'; import { GetObjectCommand } from '@aws-sdk/client-s3'; const upload = multer({ storage: multer.memoryStorage() }); diff --git a/portal/src/services/storage.js b/portal/server/services/storage.js similarity index 100% rename from portal/src/services/storage.js rename to portal/server/services/storage.js diff --git a/portal/src/components/Header.tsx b/portal/src/components/Header.tsx index 1d94d0a..0a8eab5 100644 --- a/portal/src/components/Header.tsx +++ b/portal/src/components/Header.tsx @@ -83,7 +83,7 @@ export default function Header() { overflow: 'hidden', flexShrink: 0, }}> {student.photo ? ( - {student.name} ) : ( student.name.charAt(0).toUpperCase() diff --git a/portal/src/components/Sidebar.tsx b/portal/src/components/Sidebar.tsx index 0162ee6..16a55db 100644 --- a/portal/src/components/Sidebar.tsx +++ b/portal/src/components/Sidebar.tsx @@ -158,7 +158,7 @@ export default function Sidebar() { overflow: 'hidden', transition: 'all 0.3s ease', color: 'white' }}> {student.photo ? ( - {student.name} ) : ( student.name.charAt(0).toUpperCase() diff --git a/portal/src/helpers.ts b/portal/src/helpers.ts index 0e68fa3..32b829e 100644 --- a/portal/src/helpers.ts +++ b/portal/src/helpers.ts @@ -1,7 +1,7 @@ /** * Helpers compartihados de UI */ -export function normalizePhotoUrl(url) { +export function normalizePhotoUrl(url?: string | null): string { if (!url || typeof url !== 'string') return ''; if (url.startsWith('data:image')) return url; if (url.startsWith('/storage/')) return url; diff --git a/portal/src/pages/Financeiro.tsx b/portal/src/pages/Financeiro.tsx index a5187cb..663fa2e 100644 --- a/portal/src/pages/Financeiro.tsx +++ b/portal/src/pages/Financeiro.tsx @@ -91,7 +91,7 @@ export default function Financeiro() { overdue: { className: 'badge badge-danger', label: 'Atrasado' }, cancelled: { className: 'badge badge-info', label: 'Cancelado' }, }; - const s = map[norm] || { className: 'badge badge-info', label: status }; + const s = map[norm] || { className: 'badge badge-info', label: norm }; return {s.label}; }; @@ -362,7 +362,7 @@ export default function Financeiro() { > Visualizar Recibo - ) : isPending(payment.status) && link ? ( + ) : isPending(payment) && link ? (