feat(web): telas de Estoque e Faturamento no EDEN Core

Continuação direta, sem parar para autorização (a pedido do usuário).
2 subagentes eden-frontend em paralelo.

- Estoque: armazéns (CRUD), ativos com ações contextuais por status
  (só oferece Reservar/Instalar/Devolver quando válido para o status
  atual), entrada de ativo, detalhe com histórico de movimentos, ledger
  só-leitura, reservas genéricas. Achado real documentado no código:
  install/return gravam o movimento com reference_type='contract', não
  'serialized_asset' — filtrar o ledger só pelo id do ativo nunca traz
  esse histórico; contornado buscando também pelos movimentos do
  contrato atual do ativo, registrado como pendência de backend.
- Faturamento: assinaturas (valor mensal pré-preenchido do contrato,
  editável com aviso), fechamentos (aviso de idempotência ao regerar),
  detalhe do fechamento com tabela de faturas + consolidação com
  confirmação em duas etapas (irreversível), lista de faturas.

Reconciliação manual de App.tsx/AuthenticatedLayout.tsx entre os 2
agentes, confirmando typecheck limpo a cada mesclagem. Um dos agentes
restaurou a base do zero (sem git merge) — comparação byte a byte
(diff -rq) contra main confirmou zero desvio antes de aceitar qualquer
arquivo como genuinamente novo.

Verificado: pnpm turbo run typecheck build (28/28); containers
eden-api/eden-core reconstruídos; testado ao vivo através do proxy
same-origin (porta 3001); trilha de auditoria conferida no Postgres.
Os próprios agentes já haviam confirmado ao vivo contra a API real:
invariante de serial duplicado (409), ciclo completo de ativo, e o
fluxo idempotente de billing (gerar→regenerar→consolidar→409).

Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 23:32:48 -03:00
parent 19e67dbe63
commit 7021994d8e
23 changed files with 3078 additions and 0 deletions

View File

@@ -24,6 +24,19 @@ import { ClientRegistrationDetailPage } from "./routes/client-registrations/Clie
import { ContractsListPage } from "./routes/contracts/ContractsListPage.js";
import { ContractFormPage } from "./routes/contracts/ContractFormPage.js";
import { ContractDetailPage } from "./routes/contracts/ContractDetailPage.js";
import { WarehousesListPage } from "./routes/inventory/WarehousesListPage.js";
import { WarehouseFormPage } from "./routes/inventory/WarehouseFormPage.js";
import { AssetsListPage } from "./routes/inventory/AssetsListPage.js";
import { AssetFormPage } from "./routes/inventory/AssetFormPage.js";
import { AssetDetailPage } from "./routes/inventory/AssetDetailPage.js";
import { MovementsListPage } from "./routes/inventory/MovementsListPage.js";
import { ReservationsListPage } from "./routes/inventory/ReservationsListPage.js";
import { SubscriptionsListPage } from "./routes/billing/SubscriptionsListPage.js";
import { SubscriptionFormPage } from "./routes/billing/SubscriptionFormPage.js";
import { BillingRunsListPage } from "./routes/billing/BillingRunsListPage.js";
import { BillingRunFormPage } from "./routes/billing/BillingRunFormPage.js";
import { BillingRunDetailPage } from "./routes/billing/BillingRunDetailPage.js";
import { InvoicesListPage } from "./routes/billing/InvoicesListPage.js";
export function App() {
return (
@@ -67,6 +80,22 @@ export function App() {
<Route path="/contracts" element={<ContractsListPage />} />
<Route path="/contracts/new" element={<ContractFormPage />} />
<Route path="/contracts/:id" element={<ContractDetailPage />} />
<Route path="/inventory/assets" element={<AssetsListPage />} />
<Route path="/inventory/assets/new" element={<AssetFormPage />} />
<Route path="/inventory/assets/:id" element={<AssetDetailPage />} />
<Route path="/inventory/warehouses" element={<WarehousesListPage />} />
<Route path="/inventory/warehouses/new" element={<WarehouseFormPage />} />
<Route path="/inventory/warehouses/:id/edit" element={<WarehouseFormPage />} />
<Route path="/inventory/movements" element={<MovementsListPage />} />
<Route path="/inventory/reservations" element={<ReservationsListPage />} />
<Route path="/billing/subscriptions" element={<SubscriptionsListPage />} />
<Route path="/billing/subscriptions/new" element={<SubscriptionFormPage />} />
<Route path="/billing/runs" element={<BillingRunsListPage />} />
<Route path="/billing/runs/new" element={<BillingRunFormPage />} />
<Route path="/billing/runs/:id" element={<BillingRunDetailPage />} />
<Route path="/billing/invoices" element={<InvoicesListPage />} />
</Route>
</Route>
</Routes>