Skip to content

Mapa de Rotas — vue-spa (frontend)

Referência canônica e code-verified de TODAS as rotas do app web (contrasync-vue-spa). É a fonte de verdade que a IA (Zelor) consulta para montar URLs da plataforma: ela NUNCA inventa caminho nem id, só combina uma rota REAL desta lista com um id REAL vindo de uma tool/consulta. O egress do ai-api (sanitizeAgentLinks) faz o enforcement disso; este doc é o mapa que a IA usa para acertar a rota certa.

Convenção de URL

Toda tela autenticada vive sob o parent /company/:companyId (CompanyLayout, meta.requiresAuth: true). O prefixo /company/{companyId} é injetado automaticamente por patchRouterWithCompanyPrefix (src/router/companyPrefix.ts) quando se navega por path sem prefixo (exceto paths context-free: /auth/, /access, /company/new, /onboarding/, /signing/, /unauthorized). {companyId} é uma string opaca do tenant (UUID em produção; nos mocks aparece como c1, c101): trate como opaco, nunca deduza nem troque.

Tipos de proteção (guard em modules/auth/guards/authGuard.ts):

  • protected (requiresAuth !== false): exige login + companyId + role/permission. Falha redireciona para permission-denied.
  • guest-only (guestOnly: true): redireciona quem já está logado.
  • requiresLogin (requiresLogin: true, sem requiresAuth): logado, sem empresa selecionada.
  • public (requiresAuth: false): portais de token, sem login.

Rotas autenticadas — /company/{companyId}/...

Todas abaixo são protected. {id}/{providerId}/{contractId}/{periodId} são ids de item que a IA só usa com o valor REAL vindo de uma tool/consulta.

Painel, perfil, config

PathNomeParamsPermissão / nota
/company/{companyId}/dashboarddashboardcompanyIddashboard:view (borrower)
/company/{companyId}/profileprofilecompanyIdprovider, borrower
/company/{companyId}/supportsupportcompanyIdborrower; bloqueado em modo apresentação
/company/{companyId}/monitoring(redirect)companyIdteam/list (não é página)
/company/{companyId}/company-configcompany-configcompanyIdcompany-config/general
/company/{companyId}/company-config/generalcompany-config-generalcompanyIdborrower
/company/{companyId}/company-config/identitycompany-config-identitycompanyIdborrower
/company/{companyId}/company-config/addresscompany-config-addresscompanyIdborrower
/company/{companyId}/company-config/subscriptioncompany-config-subscriptioncompanyIdborrower
/company/{companyId}/company-config/permissionscompany-config-permissionscompanyIdborrower
/company/{companyId}/company-config/ssocompany-config-ssocompanyIdborrower
/company/{companyId}/company-config/securitycompany-config-securitycompanyIdborrower

Contratos (borrower — segmento plural contracts)

PathNomeParamsPermissão / nota
/company/{companyId}/contractscontractscompanyIdcontracts:view; → contracts/list
/company/{companyId}/contracts/listlist-contractcompanyIdlista
/company/{companyId}/contracts/newnew-contractcompanyIdcontracts:create
/company/{companyId}/contracts/detailcontract-timelinecompanyIdtimeline de vigência (sem id). Query ?ids=a,b,c (UUIDs)
/company/{companyId}/contracts/{id}/detailcontract-detailcompanyId, iddetalhe de contrato terminal. Query ?sidebar=info|providers|documents|history|compliance
/company/{companyId}/contracts/{id}edit-contractcompanyId, ideditor de contrato não-terminal
/company/{companyId}/contracts/{id}/renewalcontract-renewalcompanyId, idcontracts:edit
/company/{companyId}/contracts/{id}/amendmentscontract-amendmentscompanyId, idaditivos/distrato/substituição
/company/{companyId}/contracts/{id}/negotiationnegotiation-detailcompanyId, idnegociação/redlining
/company/{companyId}/contracts/at-riskcontracts-at-riskcompanyIddashboard de renovação
/company/{companyId}/contracts/legacycontracts-legacycompanyIdlegacy/list
/company/{companyId}/contracts/legacy/listlegacy-documentscompanyIddocumentos legados
/company/{companyId}/contracts/legacy/incorporatelegacy-incorporatecompanyIdincorporar documento
/company/{companyId}/contracts/legacy/{id}legacy-document-detailcompanyId, iddetalhe legado

Portal do prestador (provider — segmento singular contract)

Distinto do borrower: role provider, segmento contract (singular).

PathNomeParams
/company/{companyId}/contract/{contractId}provider-layoutcompanyId, contractId (→ hours)
/company/{companyId}/contract/{contractId}/hoursprovider-hourscompanyId, contractId
/company/{companyId}/contract/{contractId}/hours/{periodId}provider-hours-detailcompanyId, contractId, periodId
/company/{companyId}/contract/{contractId}/complianceprovider-compliancecompanyId, contractId
/company/{companyId}/contract/{contractId}/invoicesprovider-invoicescompanyId, contractId
/company/{companyId}/contract/{contractId}/historyprovider-historycompanyId, contractId

Templates, workflows, compliance, equipe, financeiro, usuários, notas

PathNomeParamsNota
/company/{companyId}/templates/listlist-templatecompanyIdtemplates:view (parent templateslist)
/company/{companyId}/templates/newnew-templatecompanyId
/company/{companyId}/templates/{id}edit-templatecompanyId, id
/company/{companyId}/templates/{id}/structuretemplate-structure-buildercompanyId, id
/company/{companyId}/workflows/listlist-workflowcompanyIdworkflows:view (parent workflowslist)
/company/{companyId}/workflows/newnew-workflowcompanyId
/company/{companyId}/workflows/{id}edit-workflowcompanyId, id
/company/{companyId}/workflows/revision/listrevision-workflowscompanyId(+ /new, /{id} = revision-workflow-new/edit)
/company/{companyId}/workflows/signature/listsignature-workflowscompanyId(+ /new, /{id} = signature-workflow-new/edit)
/company/{companyId}/compliance/listlist-compliancecompanyIdcompliance:view (parent compliancelist)
/company/{companyId}/compliance/newnew-compliancecompanyId
/company/{companyId}/compliance/{id}edit-compliancecompanyId, id{id} = cf-<uuid>
/company/{companyId}/team/listlist-teamcompanyIdproviders:view (Equipe = lista de prestadores)
/company/{companyId}/team/{id}team-detailcompanyId, identries
/company/{companyId}/team/{id}/entriesteam-detail-entriescompanyId, idhoras
/company/{companyId}/team/{id}/consolidatedteam-detail-consolidatedcompanyId, id
/company/{companyId}/team/{id}/complianceteam-detail-compliancecompanyId, id
/company/{companyId}/team/{id}/historyteam-detail-historycompanyId, id
/company/{companyId}/team/{id}/invoicesteam-detail-invoicescompanyId, id
/company/{companyId}/financialfinancial-overviewcompanyIdreports:view
/company/{companyId}/financial/providersfinancial-providerscompanyId
/company/{companyId}/financial/providers/{providerId}financial-provider-detailcompanyId, providerId
/company/{companyId}/user/listlist-usercompanyIdusers:view (parent userlist)
/company/{companyId}/user/{id}edit-usercompanyId, id
/company/{companyId}/reportreports-listcompanyIdreports:view (segmento singular report)
/company/{companyId}/invoices/listlist-invoicescompanyId(parent invoiceslist)
/company/{companyId}/invoices/emitemit-invoicecompanyId
/company/{companyId}/invoices/{id}/detaildetail-invoicecompanyId, id{id} = cert-### (não-UUID)
/company/{companyId}/subscriptions/planssubscription-planscompanyIdmemberRoles owner/admin
/company/{companyId}/subscriptions/successsubscription-successcompanyIdmemberRoles owner/admin

Rotas fora do /company/{companyId} (auth / público)

PathNomeTipo
/auth/login, /auth/register, /auth/recovery, /auth/first-access, /auth/unlocklogin, register, ...guest-only
/auth/callback/{provider}, /auth/sso/callbackauth-callback, sso-callbackguest-only
/accessaccessrequiresLogin (seleção de empresa). Só existe na aplicação principal: num subdomínio de tenant o guard sempre redireciona (ver RN-006)
/company/new, /company/new/basic|address|privacycompany-new*requiresLogin (onboarding de empresa)
/user/onboarding/personal-data|address|termsuser-onboarding-*requiresLogin
/public/review/{token}, /public/negotiation/{token}, /public/signing/{token}, /public/onboarding/{token}, /public/validateexternal-*público (portais de token)
/unauthorized, /{pathMatch}unauthorized, not-foundpúblico / 404

Regras semânticas que a IA deve aplicar

RN-001 — Status do contrato define a rota de detalhe

Ao linkar UM contrato, a rota depende do status (a IA já tem o status no dado que consultou):

  • Status terminalcontract-detail/company/{companyId}/contracts/{id}/detail.
  • Status não-terminaledit-contract/company/{companyId}/contracts/{id} (editor).

TERMINAL_STATUSES (src/domain/contract/step-engine.ts): completed, active, finished, overdue, cancelled, archived. Não-terminais: draft, parts, model, documents, in_review, provider, provider_filling, signature, signing. A SPA se autocorrige (redireciona) se a rota não bate com o status, mas a IA deve montar a certa de primeira.

RN-002 — Enum completo de ContractStatus

draft, parts, model, documents, in_review, provider, provider_filling, signature, signing, completed, active, finished, overdue, cancelled, archived (src/domain/contract/types.ts).

RN-003 — Query params que mudam a tela

  • contract-detail: ?sidebar=info|providers|documents|history|compliance.
  • contract-timeline (/contracts/detail, sem id): ?ids=a,b,c (UUIDs de contrato separados por vírgula).

RN-004 — Formato de id por entidade

EntidadeFormatoExemplo
Contrato, empresa, membro de equipe, providerUUIDc1a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c
Compliance flow (edit-compliance)cf-<uuid>cf-1a2b3c4d-...
Provider-compliancepc-<uuid> / pcf-<uuid>pc-1a2b3c4d-...
Nota fiscal (detail-invoice)cert-###cert-001

Nem todo id é UUID: nunca valide id de compliance/nota fiscal como UUID. O egress do ai-api valida por PROVENIÊNCIA (o id apareceu numa tool/consulta desta sessão), não por formato.

RN-005 — Portal do prestador usa contract (singular)

Borrower = contracts (plural); prestador = contract (singular). São componentes e gates de role diferentes (provider vs borrower). Não confundir.

RN-006 — /access nunca renderiza dentro de um tenant

Num subdomínio de tenant (useTenant().isTenant), o authGuard intercepta a rota access (handleTenantAccessRoute) e redireciona sempre: carrega o /me/access (já escopado ao tenant pelo backend), e então (a) se o usuário é membro da empresa do tenant → dashboard; (b) se é prestador com contrato naquela empresa → provider-hours do contrato; (c) caso contrário → unauthorized. A tela /access (seleção de empresa/contrato) só aparece na aplicação principal (host sem subdomínio). O bloqueio real é do backend (guard de tenant no core); o guard do front é só UX. Ver business/sso-acesso-tenant.md.

Exemplos canônicos

  • Feliz: contrato activehttps://app.contrasync.com/company/{companyId}/contracts/{uuid}/detail.
  • Borda: contrato draft → NÃO usar /detail; usar https://app.contrasync.com/company/{companyId}/contracts/{uuid} (editor).
  • Falha: id inventado (ex.: ctr_001, não veio de tool) → a IA não pode montar o link; manda a lista /company/{companyId}/contracts ou mostra os dados na conversa. O egress remove o link caso ela tente.

Regras operacionais de página

  • Sem <h1> na página: o título vem do TopHeader via meta.titleKey.
  • Botão voltar automático: rotas de lista marcam meta.isListPage: true (sem botão); detalhe/edição mostram o botão automaticamente.
  • meta.menuKey: mantém o item do menu lateral ativo em sub-rotas (deve casar com o group em ListMenu.vue).
  • Carregamento: navegação assíncrona não-bloqueante com barra fina (naive-ui) via src/router/routeProgress.ts; recuperação pós-deploy escutando vite:preloadError com um único reload protegido por timestamp.

Observações

  • Registros sem name (montar por path): /company, monitoring (redirect), wrappers de financial/report, parent de company-config.
  • negotiation-detail é montado direto sob /company/{companyId} e não herda contracts:view.
  • Fonte: os 21 router/index.ts do vue-spa (verificado 2026-07-03).