fix: resolve portal white screen via physical service isolation and fix financeiro UI bugs

This commit is contained in:
Sidney 2026-04-22 19:49:16 -03:00
parent c1c2c9d9b9
commit 5ee1524d8a
11 changed files with 29 additions and 10 deletions

View File

@ -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

View File

@ -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.

View File

@ -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)

15
portal/check_portal.mjs Normal file
View File

@ -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();
})();

View File

@ -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() });

View File

@ -83,7 +83,7 @@ export default function Header() {
overflow: 'hidden', flexShrink: 0,
}}>
{student.photo ? (
<img src={student.photo} alt={student.name}
<img src={normalizePhotoUrl(student.photo)} alt={student.name}
style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
) : (
student.name.charAt(0).toUpperCase()

View File

@ -158,7 +158,7 @@ export default function Sidebar() {
overflow: 'hidden', transition: 'all 0.3s ease', color: 'white'
}}>
{student.photo ? (
<img src={student.photo} alt={student.name}
<img src={normalizePhotoUrl(student.photo)} alt={student.name}
style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
) : (
student.name.charAt(0).toUpperCase()

View File

@ -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;

View File

@ -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 <span className={s.className}>{s.label}</span>;
};
@ -362,7 +362,7 @@ export default function Financeiro() {
>
<Printer size={14} /> Visualizar Recibo
</button>
) : isPending(payment.status) && link ? (
) : isPending(payment) && link ? (
<a
href={link}
target="_blank"

View File

@ -159,6 +159,7 @@ export interface Notification {
message: string;
read: boolean;
createdAt: string; // ISO string
type?: 'info' | 'alert' | 'success' | 'danger';
}
// ==========================================