Skip to content

Add Recebimento e Conferência web UI, Supabase schema and TeraBox backend (MVP) - #2

Open
hhhthiti wants to merge 3 commits into
mainfrom
codex/integrate-supabase-user-authentication-system-q2hc09
Open

Add Recebimento e Conferência web UI, Supabase schema and TeraBox backend (MVP)#2
hhhthiti wants to merge 3 commits into
mainfrom
codex/integrate-supabase-user-authentication-system-q2hc09

Conversation

@hhhthiti

@hhhthiti hhhthiti commented Apr 2, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Provide a minimal viable web app for receiving and checking NF-e with separated adm and operacao workflows and Supabase persistence.
  • Allow local fallback when the Supabase schema is missing so the UI remains usable for testing.
  • Enable exporting/appending logs to TeraBox via a small Node backend implementing OAuth + pre-upload/upload/create file flow.

Description

  • Added a static frontend: index.html, styles.css, and main.js implementing login/register, role-based Admin/Operação UI, XML parsing, PDF generation (NFe + etiquetas), chat, logs view, NQ export lines and localStorage fallback when Supabase schema is absent.
  • Integrated Supabase client in main.js with helper DB wrappers dbSelect, dbInsert, dbUpdate, dbDeleteAll that automatically switch to local mode on schema errors.
  • Added a Node backend server.js with routes GET /auth/terabox, GET /auth/terabox/callback, and POST /exportar-txt-terabox to handle TeraBox OAuth and TXT upload (uses axios, form-data), plus package.json and .env.example for configuration.
  • Included supabase-schema.sql to create the required tables (usuarios, notas, conferencias, logs, chats, nq_reports) and README.md with setup and run instructions.

Testing

  • No automated tests were added or executed as part of this change.

Codex Task

@vercel

vercel Bot commented Apr 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recebimento Ready Ready Preview, Comment Apr 3, 2026 0:46am

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54e633af9e

ℹ️ 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".

Comment thread main.js
Comment on lines +630 to +633
await dbUpdate('usuarios', { matricula, telefone }, { senha: novaSenha });
if (state.mode === 'supabase') {
const { error } = await supabase.functions.invoke('send-sms', { body: { to: telefone, message: `Nova senha: ${novaSenha}` } });
if (error) throw error;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid persisting new password before delivery succeeds

In recoverBySms the password is written to usuarios before the SMS edge function is called. If send-sms fails (missing function, provider error, transient outage), the catch path reports failure but the account password has already changed and the user never receives the new value, which can lock them out. The same ordering is repeated in recoverByEmail.

Useful? React with 👍 / 👎.

Comment thread main.js
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}` } });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the user's email instead of a hard-coded recipient

The email recovery flow sends the reset message to a fixed address (leseliv487@fengnu.com) rather than the target user's registered email. In production this leaks credentials to an unrelated mailbox and prevents the intended account owner from receiving the reset notification.

Useful? React with 👍 / 👎.

Comment thread main.js
async function login(evt) {
evt.preventDefault();
const f = new FormData(loginForm);
const data = await dbSelect('usuarios', { eq: { matricula: f.get('matricula'), senha: f.get('senha') }, single: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle missing login rows without throwing

Login requests single: true, which maps to Supabase .single(). When credentials are invalid and zero rows match, .single() returns an error, dbSelect throws, and login never reaches the intended Matrícula ou senha inválida alert path. This makes normal failed-login attempts surface as runtime errors instead of a controlled auth response.

Useful? React with 👍 / 👎.

Comment thread main.js Outdated
(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">NF: ${item.quantidadeFardo} fardos | ${fardosPorPalete} fardos por palete</p><label>Quantidade conferida<input type="number" step="0.01" min="0" required name="${code}" /></label></div>`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Give conference inputs unique field names per item row

Each conference quantity input uses name="${code}", so repeated SKU codes in the same NF generate duplicate field names. During submit, form.get(code) returns one value for all duplicated rows, causing incorrect per-item divergences and wrong NQ/log records whenever the XML has multiple det entries with the same product code.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba0d2a66ab

ℹ️ 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".

Comment thread main.js
Comment on lines +401 to +403
const minhasConferencias = await dbSelect('conferencias', { eq: { conferente_matricula: state.user.matricula } }) || [];
const conferidasPorMim = new Set(minhasConferencias.map((c) => String(c.nota_id)));
visibleInvoices = allInvoices.filter((n) => !conferidasPorMim.has(String(n.id)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent duplicate conferências across operators

loadInvoices only hides notes already reviewed by the current matrícula, so the same NF stays available to other operators and each submission creates additional conferencias/nq_reports rows. In practice, if operator A and B both process the same note, divergence totals and NQ exports are duplicated and no longer represent a single physical conference for that carga.

Useful? React with 👍 / 👎.

Comment thread main.js Outdated
(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">NF: ${item.quantidadeFardo} fardos | ${fardosPorPalete} fardos por palete</p><label>Quantidade conferida<input type="number" step="0.01" min="0" required name="${code}" /></label></div>`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Escape XML fields before injecting conference item HTML

This HTML is built with insertAdjacentHTML using item.descricao/code derived from uploaded XML. A crafted NF-e payload containing HTML/JS in product text can execute script when the conference form is rendered, which allows browser-side takeover of the session context. Build nodes with textContent (or sanitize) instead of interpolating raw values into HTML.

Useful? React with 👍 / 👎.

Comment thread main.js
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}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not disclose reset password in recovery success alert

The recovery flow displays the newly generated credential directly in the browser alert. Because recoverByEmail starts from matrícula input, this exposes account takeover risk: anyone who can trigger recovery can immediately read the new password from the UI instead of proving mailbox ownership. Recovery should send a one-time token/link and never reveal plaintext passwords client-side.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant