Add Recebimento e Conferência web app, Supabase schema and TeraBox backend - #3
Add Recebimento e Conferência web app, Supabase schema and TeraBox backend#3hhhthiti wants to merge 6 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 24818b767e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pl2, | ||
| paletes_total: paletesTotal, | ||
| inicio_carga: inicioCarga, | ||
| fim_carga: fimCarga, | ||
| reabertura_finalizada: !!nota.reaberta, |
There was a problem hiding this comment.
Persist conference fields in schema before inserting
The conference submit path writes pl2, paletes_total, inicio_carga, fim_carga, and reabertura_finalizada into conferencias, but supabase-schema.sql does not create those columns. In Supabase mode this insert will fail with a missing-column error, and your maybeSwitchToLocalMode logic then downgrades the app to local storage, so conferences stop syncing to the shared database immediately after the first submission.
Useful? React with 👍 / 👎.
| inicio_descarga: inicioCarga, | ||
| fim_descarga: fimCarga, | ||
| pl2, | ||
| paletes_total: paletesTotal, | ||
| reaberta: false, |
There was a problem hiding this comment.
Add notas columns used by conference updates
The post-conference update writes fields like inicio_descarga, fim_descarga, pl2, paletes_total, and reaberta to notas, but these columns are absent from the schema file that the README instructs users to apply. In Supabase mode this update fails with column-not-found, which again triggers the local-mode fallback and causes ADM/Operação data divergence instead of persisting workflow state online.
Useful? React with 👍 / 👎.
| try { | ||
| await dbUpdate('usuarios', { matricula }, { senha: novaSenha }); | ||
| if (state.mode === 'supabase') { | ||
| const { error } = await supabase.functions.invoke('send-email', { body: { to: 'leseliv487@fengnu.com', subject: 'Nova senha', text: `Nova senha: ${novaSenha}` } }); |
There was a problem hiding this comment.
Send recovery email to the requested user
recoverByEmail always sends the new password to a hardcoded address (leseliv487@fengnu.com) instead of the account owner's email. This both leaks credentials to an unrelated recipient and prevents the requesting user from receiving their reset password, effectively breaking email recovery in production.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f4dc69d6d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await dbInsert('usuarios', { | ||
| matricula: f.get('matricula'), | ||
| senha: f.get('senha'), | ||
| role: f.get('role'), |
There was a problem hiding this comment.
Block unauthenticated creation of ADM users
The registration flow writes whatever role comes from the public form directly into usuarios without any privilege check, so any visitor can self-register as adm and immediately gain full admin access. This is an authorization bypass in environments where the app is reachable beyond a trusted internal audience.
Useful? React with 👍 / 👎.
| await dbUpdate('usuarios', { matricula }, { senha: novaSenha }); | ||
| if (state.mode === 'supabase') { | ||
| const { error } = await supabase.functions.invoke('send-email', { body: { to: 'leseliv487@fengnu.com', subject: 'Nova senha', text: `Nova senha: ${novaSenha}` } }); | ||
| if (error) throw error; | ||
| } | ||
| alert(`Senha resetada. Nova senha: ${novaSenha}`); |
There was a problem hiding this comment.
Require verification before completing email recovery
This reset path updates the password using only matricula and then shows the new password in an alert, which means anyone who knows a matrícula can reset that account and read the new credential immediately. In production this enables straightforward account takeover without proving control of the user’s email.
Useful? React with 👍 / 👎.
| const alreadyExists = await dbSelect('notas', { eq: { numero_nota: nota.numeroNota } }); | ||
| if ((alreadyExists || []).length) { |
There was a problem hiding this comment.
Deduplicate notes by NF-e key, not invoice number alone
The publish guard treats numero_nota as globally unique, but invoice numbers are typically only unique per emitter. If two suppliers issue the same number, the second valid NF-e is rejected as duplicate and cannot be published, blocking normal receiving operations; use chave_nfe (or emitter+number) for uniqueness.
Useful? React with 👍 / 👎.
| app.post('/exportar-txt-terabox', async (req, res) => { | ||
| try { | ||
| ensureConfig(); | ||
| ensureToken(); | ||
|
|
There was a problem hiding this comment.
Authenticate export endpoint before using shared TeraBox token
The upload endpoint has no caller authentication/authorization check; it only verifies that a global in-memory token exists. After any admin completes OAuth once, any client that can reach this backend can POST arbitrary fileName/content and write files into the same TeraBox directory.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8bd9cb2a89
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| (nota.itens_json || []).forEach((item) => { | ||
| const code = normalizeProductCode(item.codigo); | ||
| const fardosPorPalete = getFardosPorPalete(code); | ||
| conferenciaForm.insertAdjacentHTML('beforeend', `<div class="item"><p><strong>${code}</strong> - ${item.descricao}</p><p class="hint">${fardosPorPalete} fardos por palete</p><label>Quantidade conferida<input type="number" step="0.01" min="0" required name="${code}" /></label><label class="fracao-fardo hidden" data-fracao="${code}">Fardos fracionados (quando conferir em paletes)<input type="number" step="0.01" min="0" name="${code}__fracao" value="0" /></label></div>`); |
There was a problem hiding this comment.
Escape invoice fields before rendering HTML
item.descricao comes directly from uploaded XML and is interpolated into innerHTML without escaping. A crafted NF-e payload (for example with an <img onerror=...> in xProd) will execute script when Operação opens the conference form, creating a stored XSS that can exfiltrate localStorage/session data from any user who views the note.
Useful? React with 👍 / 👎.
| app.get('/auth/terabox/callback', async (req, res) => { | ||
| try { | ||
| ensureConfig(); | ||
| const { code } = req.query; | ||
| if (!code) return res.status(400).send('Código de autorização não recebido.'); |
There was a problem hiding this comment.
Bind TeraBox OAuth callback to an authenticated session
The callback accepts any code and writes its access token into the global teraboxToken without checking who initiated OAuth or validating a state value. In a public deployment, any external caller can complete OAuth against this backend and overwrite the shared token, redirecting all subsequent exports to their own TeraBox account.
Useful? React with 👍 / 👎.
| const data = await dbSelect('usuarios', { eq: { matricula: f.get('matricula'), senha: f.get('senha') }, single: true }); | ||
| if (!data) return alert('Matrícula ou senha inválida.'); |
There was a problem hiding this comment.
Handle unknown credentials without throwing in login flow
login expects dbSelect(..., single: true) to return null for invalid credentials, but Supabase .single() returns an error when no rows match. In Supabase mode, failed login attempts therefore raise an uncaught exception instead of showing the intended "Matrícula ou senha inválida" message, breaking normal authentication UX for wrong-password cases.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8a4de2568b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| numero_nota: nota.numeroNota, | ||
| chave_nfe: nota.chave, | ||
| motorista: nota.transporte.motorista, | ||
| transportadora: nota.transporte.transportadora, |
There was a problem hiding this comment.
Remove unsupported notas field from publish insert
publishInvoice inserts transportadora into notas, but supabase-schema.sql never defines that column in public.notas (table block at lines 12–28). In Supabase mode this makes the first publish fail with a missing-column error, and the error path switches the app to local mode, so shared online synchronization is lost right when ADM tries to publicar a nota.
Useful? React with 👍 / 👎.
| const { error } = await supabase.functions.invoke('send-sms', { body: { to: telefone, message: `Nova senha: ${novaSenha}` } }); | ||
| if (error) throw error; | ||
| } | ||
| alert(`Senha resetada. Nova senha: ${novaSenha}`); |
There was a problem hiding this comment.
Stop exposing new password in SMS recovery alert
The SMS recovery flow resets the password and then shows the new credential directly in a browser alert, so anyone who knows a user's matrícula and registered phone number can take over the account without proving phone possession. This is especially risky in production because the attacker gets the usable password immediately from the UI.
Useful? React with 👍 / 👎.
Motivation
Description
index.html,styles.cssandmain.jsimplementing UI, Supabase integration (with localStorage fallback when schema is missing), XML parsing, PDF generation (jsPDF + html2canvas), NQ line export, logs, chat and role-based views.server.jsandpackage.jsonproviding TeraBox OAuth flow (/auth/terabox,/auth/terabox/callback) and an endpoint to upload TXT logs (/exportar-txt-terabox), plus.env.examplewith required env vars:TERABOX_CLIENT_ID,TERABOX_CLIENT_SECRET,TERABOX_REDIRECT_URI,TERABOX_TARGET_DIRandPORT.supabase-schema.sqlcontaining idempotentCREATE TABLE IF NOT EXISTSstatements forusuarios,notas,conferencias,logs,chatsandnq_reports, and migration-safeALTER TABLEclauses.README.mdwith setup and run instructions (includingcp .env.example .env,npm installandnpm startguidance) and details about running only on Render or withlocalhostbackend URL.Testing
Codex Task