From 147ea6c26401dbfbdb1186dd1464090682f6783e Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 22 Apr 2026 06:44:52 -0300 Subject: [PATCH] fix: corrige import da sidebar na tela do portal --- GEMINI.md | 8 ++++++-- MEMORY.md | 8 ++++++++ diff_manager.txt | Bin 0 -> 366 bytes diff_portal.txt | Bin 0 -> 358 bytes portal/Dockerfile | 3 ++- portal/package.json | 4 ++-- portal/server.selfhosted.js | 5 +++-- portal/src/components/Header.tsx | 1 + portal/src/components/Sidebar.tsx | 3 ++- portal/src/pages/MeusDados.tsx | 3 ++- portal/src/services/storage.js | 20 ++++++++++++++++++-- portal/tsconfig.json | 1 + 12 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 diff_manager.txt create mode 100644 diff_portal.txt diff --git a/GEMINI.md b/GEMINI.md index 796a6c2..9c29009 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -6,9 +6,11 @@ ## 🛠️ Stack Tecnológica - **Frontend/Backend:** Remix (React) - **Banco de Dados:** PostgreSQL (100% Local/Self-Hosted) -- **Arquitetura de Storage:** Self-Hosted (MinIO) - 100% Desacoplado do Supabase Cloud. -- **Sincronização:** API Local de alta performance para conciliação bancária (Asaas). +- **Storage Architecture**: 100% Self-Hosted (MinIO) - Decoupled from Supabase Cloud. +- **Image Serving**: All images are served via a backend proxy route (`/storage/:bucket/:key`) to ensure cross-origin compatibility and security. +- **Synchronization**: High-performance local API for bank reconciliation (Asaas). - **Orquestração:** Portainer (Docker) +- **Production Entry Point**: All production deployments MUST use `server.selfhosted.js` renamed/copied as `server.js` in the Docker containers to ensure full local feature availability. ## ⚠️ Regras de Negócio Críticas (MANDATÓRIO) @@ -22,3 +24,5 @@ 2. **Segurança:** Todas as rotas sensíveis devem validar o token JWT local (via secrets do ambiente). Proibido usar Supabase SDK para lógica de autenticação ou sincronização no frontend. 3. **Resiliência:** Tratamento rigoroso de erros em chamadas de API de terceiros (Asaas, Evolution API). 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 Stability**: Dockerfiles MUST include `ENV NODE_OPTIONS="--max-old-space-size=4096"` before `npm run build` to prevent Vite/Rolldown crashes during ARM64 cross-compilation. +6. **Express Compatibility**: Avoid using raw `/*` wildcards in Express 5 routes; use Regex paths (`/^\/route\/(.+)$/`) for compatibility with `path-to-regexp` v8. diff --git a/MEMORY.md b/MEMORY.md index 1866c53..d7100b0 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -2,6 +2,14 @@ ## 📅 Estado Atual (21/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). +- [x] Correção dos Cards de Monitoramento (PostgreSQL/MinIO) com tratativa de erro independente. +- [x] Vacina de cache global: Injeção de `normalizePhotoUrl` nos módulos de Boletim, Turmas e Frequência. +- [x] Estabilização do Build ARM64: Injeção de `max_old_space_size=4096` nos Dockerfiles para evitar crashes do Vite no Github Actions. +- [x] Correção de Rota Express 5: Migração de curingas `*` para Regex para evitar falhas de inicialização no servidor. +- [ ] Próximo Passo: Validar o tempo de build no Github Actions e confirmar o carregamento das fotos na VPS Oracle. + ### 💳 Módulo Financeiro (Portal do Aluno) - **Funcionalidades Implementadas:** - Cards de resumo (Total em Aberto, Pago, Parcelas). diff --git a/diff_manager.txt b/diff_manager.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb0ffa72c313395c1833e3e99bd90ded2de87537 GIT binary patch literal 366 zcmezWkC%aq!IL46p@5;3p@hMoA&DW2A(bH+$W|Z%1~X(bqyW`}Oh^H;lNl0$I`bKd z7(nLgVui$*i(My36l88L(3U(PP6ygt#Gubm45rJ#q#l@;!;r?10dz+(&^4(*m+1k0 dRSfixErT5nUlBGJVgh#8+W<|*E(0G&7{ptJO9o6?VFNtWng4s z=Ej4LmRk8K8h73_>Nb6&yrz=w!-P@K!H84CI(s$h==rlI_2f8BpIH5!`Kss1OFd4T cwAw0@A15al%0GT$)So`QcOh>0$Ee5I0k~i*82|tP literal 0 HcmV?d00001 diff --git a/portal/Dockerfile b/portal/Dockerfile index 107db87..bc7de40 100644 --- a/portal/Dockerfile +++ b/portal/Dockerfile @@ -4,6 +4,7 @@ WORKDIR /app COPY package.json ./ RUN npm install COPY . . +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN npm run build # ---- Production Stage ---- @@ -11,7 +12,7 @@ FROM node:22-alpine AS production WORKDIR /app COPY package.json ./ RUN npm install --omit=dev -COPY server.js ./ +COPY server.selfhosted.js ./server.js COPY --from=builder /app/dist ./dist EXPOSE 3001 CMD ["node", "server.js"] diff --git a/portal/package.json b/portal/package.json index 4583f39..a14266a 100644 --- a/portal/package.json +++ b/portal/package.json @@ -5,10 +5,10 @@ "type": "module", "scripts": { "dev": "vite", - "dev:server": "node server.js", + "dev:server": "node server.selfhosted.js", "build": "vite build", "preview": "vite preview", - "start": "node server.js" + "start": "node server.selfhosted.js" }, "devDependencies": { "@tailwindcss/vite": "^4.2.2", diff --git a/portal/server.selfhosted.js b/portal/server.selfhosted.js index 3db9584..65bfffe 100644 --- a/portal/server.selfhosted.js +++ b/portal/server.selfhosted.js @@ -45,9 +45,10 @@ app.use(express.urlencoded({ limit: '50mb', extended: true })); // ============================================================ // Proxy de Imagens do MinIO (acesso público via backend) // ============================================================ -app.get('/storage/:bucket/:key', async (req, res) => { +app.get(/^\/storage\/([^\/]+)\/(.+)$/, async (req, res) => { try { - const { bucket, key } = req.params; + const bucket = req.params[0]; + const key = req.params[1]; const command = new GetObjectCommand({ Bucket: bucket, Key: key }); const data = await s3Client.send(command); diff --git a/portal/src/components/Header.tsx b/portal/src/components/Header.tsx index 6f9e999..c9f64a6 100644 --- a/portal/src/components/Header.tsx +++ b/portal/src/components/Header.tsx @@ -3,6 +3,7 @@ import { useTheme } from '../context/ThemeContext'; import { Moon, Sun } from 'lucide-react'; import { useLocation } from 'react-router-dom'; import Notifications from './Notifications'; +import { normalizePhotoUrl } from '../services/storage'; const pageTitles: Record = { '/': 'Dashboard', diff --git a/portal/src/components/Sidebar.tsx b/portal/src/components/Sidebar.tsx index 94b19d7..17d39db 100644 --- a/portal/src/components/Sidebar.tsx +++ b/portal/src/components/Sidebar.tsx @@ -5,6 +5,7 @@ import { FileText, Award, User, LogOut, GraduationCap, X, Menu, ClipboardList } from 'lucide-react'; import { useState, useEffect } from 'react'; +import { normalizePhotoUrl } from '../services/storage'; const navItems = [ { path: '/', label: 'Dashboard', icon: LayoutDashboard }, @@ -111,7 +112,7 @@ export default function Sidebar() { }}> {schoolLogo ? ( EduManager {student.photo ? ( - {student.name} diff --git a/portal/src/services/storage.js b/portal/src/services/storage.js index 5fc9690..5be8b52 100644 --- a/portal/src/services/storage.js +++ b/portal/src/services/storage.js @@ -46,10 +46,26 @@ export async function uploadFile(bucket, fileName, fileBuffer, contentType) { } /** - * Gera a URL pública de um arquivo existente + * Normaliza URLs de mídia para o formato de proxy (/storage/...) + */ +export function normalizePhotoUrl(url) { + if (!url || typeof url !== 'string') return ''; + if (url.startsWith('data:image')) return url; + if (url.startsWith('/storage/')) return url; + + try { + const match = url.match(/^https?:\/\/[^\/]+\/(.+)$/); + if (match) return `/storage/${match[1]}`; + } catch(e) {} + + return url; +} + +/** + * Gera a URL de proxy para um arquivo existente */ export function getPublicUrl(bucket, fileName) { - return `${MINIO_PUBLIC_URL}/${bucket}/${fileName}`; + return `/storage/${bucket}/${fileName}`; } /** diff --git a/portal/tsconfig.json b/portal/tsconfig.json index 1997b7e..8a7b911 100644 --- a/portal/tsconfig.json +++ b/portal/tsconfig.json @@ -7,6 +7,7 @@ "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, + "allowJs": true, "isolatedModules": true, "moduleDetection": "force", "noEmit": true,