Lalabase
티켓·문서·근무시간·고객대화를 한 곳에 모아 KI로 검색, 소프트웨어 기업 고객 프로젝트용, 오픈소스로 자체 서버·독일 클라우드에 배포
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Report Distribuidora — Balanço e Detalhamento de Estoque Dashboard executivo de estoque da distribuidora, com a hierarquia Armazém › Marca › Família em listagem que abre e fecha, no modelo do dash financeiro usado como referência.README 전문 보기 ↗
Dashboard executivo de estoque da distribuidora, com a hierarquia Armazém › Marca › Família em listagem que abre e fecha, no modelo do dash financeiro usado como referência.
A base técnica e a identidade visual são herdadas do Report E-commerce
(CD Vulcabras — Extrema/MG), mas este é um projeto independente: repositório
próprio, banco Supabase próprio e deploy próprio. As demais páginas — romaneio,
faturamento, entrega por transportadora — entram depois nesta mesma base, sem
mudança de estrutura: cada uma vira uma nova linha em dashboard_snapshots.
Três camadas, com separação rígida de responsabilidade:
Extração TXT do sistema (Posição de Stock)
│ upload manual, feito pelo operador no navegador
▼
┌───────────────┐
│ ingest.js │ Lê o arquivo, cruza com os gabaritos, calcula
│ (processa e │ os indicadores e grava tudo já pronto.
│ só escreve) │ NUNCA desenha nada na tela.
└───────┬────────┘
│ grava
▼
┌───────────────┐
│ Supabase │ Postgres (dados + snapshot) +
│ │ Storage (backup gzip do TXT original)
└───────┬────────┘
│ lê o snapshot já pronto
▼
┌───────────────┐
│ index.html │ Desenha cards, gráficos e a árvore.
│ (renderiza e │ NUNCA recalcula regra de negócio.
│ só lê) │
└───────────────┘
▼
Vercel
Essa separação não é opcional. Número errado na tela se investiga no
ingest.js (como foi calculado); aparência se ajusta no index.html (como é
exibido). Foi o que economizou tempo de debug no projeto do e-commerce e é o
que mantém a tela rápida com base grande.
| Arquivo | O que é |
|---|---|
index.html | O dashboard. Single-file, sem build step. |
ingest.js | Parse, agregação e gravação (página Estoque). |
distr-fluxo.js | Renderizador + editor da página Fluxo de Processos (ver seção 10). |
esquema.sql | Todo o banco: tabelas, gabaritos, RLS. Já aplicado. |
embarque.js | Setor Embarque: leitura da base histórica, forecast mensal ÷ dias úteis e o gráfico Expedição × Forecast / Análise Prevista de Backlog (mesmo traço do Report E-commerce). |
migracao_embarque.sql | Tabelas embarque_diario (histórico diário) e embarque_forecast_mensal. Já aplicada. |
testes-embarque.js | Testes do Embarque (node testes-embarque.js). |
seed_distr_fluxo.sql | Semente da primeira versão do Fluxo de Processos (ver seção 10). |
vercel.json | Diz ao Vercel que é estático puro, sem build. |
favicon.png | Ícone da aba e marca no menu. |
| Projeto | report-distribuidora |
| Organização | Vulca |
| Região | sa-east-1 (São Paulo) |
| URL | https://qaehjplsasumuhszjcnu.supabase.co |
| Custo | R$ 0/mês |
O schema e os gabaritos já estão aplicados (7 armazéns, 37 famílias com
marca e segmento). A publishable key já está preenchida no index.html —
ela é pública por design: quem protege o dado é a RLS no Postgres, não o fato
de a chave estar escondida no front.
backups, Public: OFF.
É onde fica a cópia comprimida de cada TXT enviado, para auditoria.insert into perfis_acesso (user_id, role, nome)
values ('COLE-O-UUID-AQUI', 'admin', 'Seu Nome');
Sem esse passo o login recusa: a tela exige perfil cadastrado.Crie um repositório novo (ex. report-distribuidora) e suba estes arquivos na
raiz dele. Nada além do que está aqui é necessário.
vercel.json já cuida disso.O
index.htmltambém funciona aberto direto do disco (duplo clique): ele fala com o Supabase pela internet, não depende do servidor de hospedagem. Serve de plano B se o deploy travar na véspera de uma apresentação.
O ingest aceita os dois formatos e detecta qual é pelo conteúdo do arquivo, não pelo nome:
| Layout | Extração | Observação |
|---|---|---|
Delimitado por | | EX000796 | Preferido. Traz St e Em Linha como colunas separadas, e artigo/descrição/cor/tamanho cada um na sua coluna. |
| Largura fixa | EX000914 | Mantido por compatibilidade. É o único que imprime o ** TOTAL GERAL do sistema, útil para conferência. |
Não abra o arquivo no Excel e salve por cima. No layout de largura fixa as colunas são lidas por posição de caractere, e qualquer reformatação quebra a leitura.
Quando a extração é a de largura fixa, o ingest compara o que leu com o
** TOTAL GERAL impresso pelo próprio sistema:
Quando a extração é a delimitada, o arquivo não imprime totais. A tela diz exatamente isso — "não há conferência externa" — em vez de fingir uma validação que não houve.
Valor total, quantidade, disponível para venda (armazéns DISPONIVEL —
hoje só o AC190), bloqueado / em análise, SKUs com estoque e custo médio
unitário.
A leitura imediata: dos R$ 127,2 mi de estoque, R$ 120,5 mi (94,7%) disponíveis e R$ 6,7 mi (5,3%) travados em análise, qualidade ou devolução.
O relatório traz dois status independentes, que respondem a perguntas diferentes — e por isso são dois filtros separados, não um só:
| Filtro | Valores | O que significa |
|---|---|---|
| Válido | Sim (V) / Não (I) | O artigo é válido? |
| Em linha | Sim (S) / Não (N) | O artigo está em linha? |
Clicar no filtro já ativo desliga — para ninguém ficar preso num recorte sem perceber no meio de uma apresentação. O filtro atinge tudo ao mesmo tempo: KPIs, gráficos e a árvore inteira, e o recorte ativo fica escrito no rodapé da tabela.
Isso funciona porque cada nó da árvore já vem do ingest com o total quebrado nas quatro combinações. O navegador só soma baldes já calculados — não reprocessa regra de negócio.
No layout antigo os dois status vinham colados num código só (
VS/VN/IS/IN). O ingest desmembra na leitura, então os dois layouts produzem exatamente o mesmo dado.
Fechada, mostra os 7 armazéns e o TOTAL GERAL. Cada + abre um nível:
AC190 [DISPONÍVEL] Armazém Físico segregado em PULMÃO e PICKING
└ MIZUNO
├ 102 TÊNIS MIZUNO | TÊNIS MIZUNO
├ 103 VESTUÁRIO MIZUNO | TÊXTIL/ACESSÓRIOS MIZUNO
└ ...
Colunas: Qtd · % do nível · SKUs · R$ · % do nível.
O % é sempre em relação ao nível pai, não ao total geral — dentro de um armazém as marcas somam 100%; dentro de uma marca, as famílias somam 100%. É o que responde à pergunta que a gestão faz de verdade: "quanto desse armazém é Mizuno?"
Os nomes de família e o segmento ao lado vêm do gabarito da operação
(dim_familias), não do relatório — o sistema escreve "VESTUARIO
OLYMP.TERCEIROS" onde a operação lê "VESTUÁRIO OLY".
A coluna KPI traz a bandeira nos armazéns cujo estoque não está disponível para venda, mesma função da bandeira do dash financeiro de referência.
Botões Expandir tudo / Recolher tudo e CSV (exporta a árvore inteira, não só o que está aberto, respeitando os filtros ativos).
| Linhas com estoque | 24.973 |
| Linhas de SKU zerado | 8.480 — fora do total |
| Artigos distintos | 3.009 |
| Quantidade | 2.931.823 un |
| Valor | R$ 127.199.303,46 |
| Famílias | 21 com estoque, todas mapeadas |
Por armazém:
| Armazém | Qtd | Valor | % valor |
|---|---|---|---|
| AC190 (disponível) | 2.834.432 | R$ 120.514.650,87 | 94,7% |
| ARMRP (bloqueado) | 77.662 | R$ 4.997.283,39 | 3,9% |
| ARAMO (análise) | 13.957 | R$ 1.369.869,23 | 1,1% |
| DEVFT (bloqueado) | 3.848 | R$ 269.372,02 | 0,2% |
| ARMFT (análise) | 1.737 | R$ 41.268,88 | 0,0% |
| ARMC1 (análise) | 42 | R$ 2.349,60 | 0,0% |
| SEM_ARMAZEM | 145 | R$ 4.509,47 | 0,0% |
Por marca: Mizuno R$ 68,9 mi (54,1%) · Under Armour R$ 32,3 mi (25,4%) · Olympikus R$ 26,1 mi (20,5%).
Por status:
| Válido | Em linha | Qtd | Valor |
|---|---|---|---|
| Sim | Sim | 2.240.615 | R$ 81.667.203,02 |
| Sim | Não | 690.053 | R$ 45.494.599,30 |
| Não | Não | 805 | R$ 30.027,08 |
| Não | Sim | 350 | R$ 7.474,05 |
Stock Zero: N), por isso ele não tem essas linhas.ARMC1 (materiais de consumo, 42 un) está somado no total geral. Se
materiais de consumo não devem contar como estoque de produto, o certo é
filtrar no ingest.js — não esconder na tela — e isso muda o total
apresentado.St | Em Linha | Fam | Artigo | Descricao | Cor | Tamanho | Um |
Armazem | Local | Stock_Minimo | Qtd_Stock | Preco_Medio | Valor_Stock |
O cabeçalho é lido pelo nome das colunas, não por posição: se o sistema
passar a exportar uma coluna a mais ou em outra ordem, o parser continua
achando cada campo. O armazém vem como EXTRE-AC190; linhas sem armazém
(EXTRE sozinho) viram SEM_ARMAZEM e aparecem no relatório — estoque
escondido é pior do que estoque estranho.
Relatório de terminal paginado, com cabeçalho repetido a cada página. Não é
CSV: separar por espaço quebra, porque a descrição do artigo tem espaços. As
posições vieram da própria linha de régua do relatório e estão em
COLUNAS_LINHA / COLUNAS_ARTIGO, no topo do ingest.js — se o layout
mudar, é só ali que se mexe.
Dois detalhes que não são óbvios nesse layout:
Familia ...: no
cabeçalho de cada página e vale para as linhas seguintes. O parser a carrega
como estado enquanto varre.UA casa dentro de
outras palavras — a relação família → marca é dado, em dim_familias.
Família nova que apareça e não esteja cadastrada cai em NÃO MAPEADA e o
dashboard avisa, em vez de somar silenciosamente no lugar errado.Implementados desde o primeiro commit, para não repetir bugs já resolvidos no report do e-commerce:
Intl.DateTimeFormat com timezone fixo. Nunca somar ou subtrair horas na
mão: quebra em horário de verão.:last-child. Estilizar "a
última linha" por posição fez a 10ª linha de um Top 10 parecer total geral.Segue a skill vulcabras-visual-identity: Segoe UI, cards neutros sem sombra
pesada, kicker em caixa alta com linha fina dourada, tema escuro como padrão e
claro como alternativo (o botão Tema troca e a escolha fica salva).
Cor tem significado, nunca é decoração: verde = disponível/positivo, âmbar = atenção, vermelho = bloqueado/negativo, e as cores de marca só identificam marca.
Antes de liberar para mais gente:
select em
estoque_posicoes usando só a publishable key, sem login. Tem que voltar
vazio. Se voltar dado, a RLS não está valendo — pare e corrija.admin / gestor / operador do CD, que pode não ser a hierarquia certa
aqui.Perguntas de negócio em aberto:
ARMC1 (materiais de consumo) deve entrar no total de estoque?Evoluções naturais desta base:
estoque_posicoes; é só carregar sob demanda ao abrir a família.estoque_extracoes já guarda o histórico.dim_familias e no snapshot, falta só o seletor de hierarquia na tela.dashboard_snapshots, sem mudança de schema.Fluxograma do processo operacional do CD (Recebimento → Armazenagem → Expedição, mais o fluxo à parte de Reversa), no menu Processos → Fluxo de Processos - DISTR, visível a todos os perfis — é material de treinamento, não só de gestão. Quem tem perfil admin também edita, ao vivo, no navegador.
Segue a mesma separação do restante do app — só que aqui não existe
ingest.js porque não há arquivo externo pra processar: o próprio Admin é
quem gera o dado, editando na tela.
distr-fluxo.js Lê e desenha o fluxograma (retângulo=etapa,
(renderiza e, losango=decisão, pílula=início/fim). Para admin,
p/ admin, edita) também liga o editor por cima: clicar numa seta
│ insere etapa/quebra/B.O.; clicar numa etapa ou
│ lê/grava losango abre o painel de edição.
▼
dashboard_snapshots pagina='distr_fluxo' — mesma tabela e mesmo
(Postgres) padrão "uma versão = uma linha nova" do resto
do app (seção 1). "Salvar" nunca dá UPDATE, então
toda versão anterior continua no banco — é o
histórico/undo de graça.
RLS: nenhuma policy nova foi criada. A leitura (ler_snapshots) já libera
qualquer pagina pra todo autenticado, e a escrita (gravar_snapshots) já é
só-admin — exatamente a regra que essa página precisa. O botão "Editar fluxo"
na tela é conveniência de interface; a proteção de verdade é essa RLS.
payload jsonb){
"versao_schema": 1,
"setores": ["Comercial", "Coleta", ...], // autocomplete do campo Responsável
"lanes": [
{ "id": "principal", "titulo": "...", "sub": "...",
"fases": [
{ "id": "receb", "titulo": "Recebimento",
"blocos": [ ["step","1"], ["step","2"],
["guard","A quantidade bateu na conferência?", ["4.1","4.2"],
{"exc":"Não","ok":"Sim","rejoin":true}], ... ] },
...
] },
{ "id": "reversa", "titulo": "Reversa", "fases": [ ... ] }
],
"nos": { "receb:1": { "nome":"...", "resumo":"...", "original":"...",
"resp":"...", "orig":"—", "dest":"AC190", ... } }
}
blocos é a topologia de cada fase — step/gate (retângulo), guard
(losango com um ramo lateral de desvio) ou fork (losango com duas colunas,
ambas legítimas). nos guarda o detalhe de cada etapa, indexado por
"fase:número". Ícones (o conjunto de 37 SVGs de linha) vivem só no
JavaScript, não no payload — é gabarito fixo, não dado editável.
Botão ✏️ Editar fluxo liga o modo edição (começa desligado, mesmo pra admin — ninguém edita sem querer só por ter a permissão):
dashboard_snapshots. Enquanto não salva, nada é permanente — Descartar
volta pra última versão publicada.Numeração (1, 6.1, 6.1.2, 5A...) é recalculada sozinha a cada
inserção/exclusão, com raio de ação limitado ao que a edição realmente
afeta — nunca renumera nada fora dali. O número sugerido sempre aparece
num campo editável, então dá pra ajustar à mão quando o padrão automático não
for exatamente o que se quer.
Fora do escopo desta versão (registrado, não esquecido): criar uma lane inteiramente nova (só fase nova dentro de lane existente); reordenar fases/etapas do tronco (inserir sim, reordenar não); criar um losango do zero a partir de uma seta (editar um já existente, sim); uma tela de "versões anteriores" (cada save já vira linha nova no banco, recuperável por SQL).
A tabela nasce vazia — sem uma primeira linha, a tela mostra "Nenhuma versão
do fluxo publicada ainda". Rode seed_distr_fluxo.sql inteiro no SQL
Editor do Supabase (mesmo projeto de esquema.sql) uma vez: ele insere a
versão validada com a operação (66 etapas, 4 fases + Reversa) como a primeira
linha de dashboard_snapshots para pagina='distr_fluxo'. Depois disso, é
editor na tela — não precisa rodar esse arquivo de novo (e se rodar, só cria
mais uma versão igual, não quebra nada).