backup
This commit is contained in:
744
subdomain_stores_plan.md
Normal file
744
subdomain_stores_plan.md
Normal file
@@ -0,0 +1,744 @@
|
||||
# Subdomain Stores Plan
|
||||
|
||||
## Objetivo
|
||||
|
||||
Reorganizar o ecossistema do PediFoods para um modelo claro de subdomínios, mantendo a integração com o backend do Atomenta onde ela faz sentido, mas separando melhor identidade, navegação e contexto de cada área.
|
||||
|
||||
## Cenário Desejado
|
||||
|
||||
### 1. `pedifoods.com.br`
|
||||
|
||||
Papel:
|
||||
- home pública
|
||||
- landing page
|
||||
- login
|
||||
- onboarding inicial
|
||||
- após login, exibir lista de lojas do usuário
|
||||
|
||||
Responsabilidade:
|
||||
- identidade pública do PediFoods
|
||||
- autenticação do usuário final/parceiro
|
||||
- seleção da loja
|
||||
|
||||
### 2. `parceiro.pedifoods.com.br`
|
||||
|
||||
Papel:
|
||||
- painel do lojista
|
||||
- equivalente ao atual "Atomenta Store"
|
||||
- gestão operacional da loja
|
||||
|
||||
Responsabilidade:
|
||||
- backoffice do parceiro
|
||||
- configuração da loja
|
||||
- cardápio
|
||||
- pedidos
|
||||
- financeiro
|
||||
- onboarding do parceiro
|
||||
|
||||
### 3. `nome-curto-loja.pedifoods.com.br`
|
||||
|
||||
Papel:
|
||||
- storefront da loja
|
||||
- vitrine pública ou semi-logada da loja
|
||||
- produtos, categorias, carrinho e experiência do cliente
|
||||
|
||||
Responsabilidade:
|
||||
- experiência da loja individual
|
||||
- branding e contexto por loja
|
||||
- leitura do catálogo
|
||||
|
||||
## Princípio Arquitetural
|
||||
|
||||
O PediFoods não deve mais parecer "um Atomenta renomeado".
|
||||
|
||||
Ele pode continuar:
|
||||
- consumindo APIs do Atomenta
|
||||
- reutilizando lógica de OTP
|
||||
- reutilizando cookies/tokens e integração segura quando necessário
|
||||
|
||||
Mas deve deixar claro:
|
||||
- qual domínio é PediFoods
|
||||
- qual domínio é painel parceiro
|
||||
- qual domínio é storefront da loja
|
||||
|
||||
## Direção Técnica
|
||||
|
||||
### Separar 3 contextos
|
||||
|
||||
1. `public app`
|
||||
- domínio base `pedifoods.com.br`
|
||||
- homepage, login, seleção de lojas
|
||||
|
||||
2. `partner app`
|
||||
- subdomínio fixo `parceiro.pedifoods.com.br`
|
||||
- painel do lojista
|
||||
|
||||
3. `store app`
|
||||
- subdomínio dinâmico `{slug}.pedifoods.com.br`
|
||||
- storefront da loja
|
||||
|
||||
### Manter 1 base de código no curto prazo
|
||||
|
||||
No curto prazo, o melhor custo-benefício é manter uma única codebase do PediFoods com roteamento por host.
|
||||
|
||||
Ou seja:
|
||||
- o app lê o `Host`
|
||||
- identifica o contexto
|
||||
- renderiza a área correta
|
||||
|
||||
Exemplo de resolução:
|
||||
- `pedifoods.com.br` => contexto `public`
|
||||
- `parceiro.pedifoods.com.br` => contexto `partner`
|
||||
- `slug.pedifoods.com.br` => contexto `store`
|
||||
|
||||
Isso evita:
|
||||
- duplicação de projeto
|
||||
- deploy múltiplo desnecessário
|
||||
- divergência de regra de negócio
|
||||
|
||||
## Regras de Resolução de Host
|
||||
|
||||
### Contexto `public`
|
||||
|
||||
Hosts:
|
||||
- `pedifoods.com.br`
|
||||
- `www.pedifoods.com.br` se existir
|
||||
|
||||
Fluxos:
|
||||
- home
|
||||
- login
|
||||
- cadastro
|
||||
- recuperação de conta
|
||||
- listagem de lojas do usuário autenticado
|
||||
|
||||
### Contexto `partner`
|
||||
|
||||
Host:
|
||||
- `parceiro.pedifoods.com.br`
|
||||
|
||||
Fluxos:
|
||||
- login do parceiro
|
||||
- dashboard da loja
|
||||
- onboarding
|
||||
- catálogo
|
||||
- pedidos
|
||||
- financeiro
|
||||
|
||||
### Contexto `store`
|
||||
|
||||
Host:
|
||||
- `{storeSlug}.pedifoods.com.br`
|
||||
|
||||
Fluxos:
|
||||
- catálogo público da loja
|
||||
- detalhes da loja
|
||||
- carrinho
|
||||
- pedidos do cliente
|
||||
|
||||
## Mudanças Estruturais Necessárias
|
||||
|
||||
### 1. Resolver host de forma centralizada
|
||||
|
||||
Criar uma camada única para:
|
||||
- ler `req.hostname`
|
||||
- classificar o contexto
|
||||
- extrair `storeSlug` quando aplicável
|
||||
|
||||
Saída esperada:
|
||||
- `appContext.type = public | partner | store`
|
||||
- `appContext.storeSlug = string | null`
|
||||
|
||||
### 2. Parar de usar defaults de domínio do Atomenta no PediFoods
|
||||
|
||||
Hoje o PediFoods ainda carrega vários defaults como:
|
||||
- `https://atomenta.com.br`
|
||||
- `atomenta_token`
|
||||
- `atomenta_auth`
|
||||
- nomes e textos herdados
|
||||
|
||||
Isso precisa ser separado em 2 grupos:
|
||||
|
||||
#### Pode continuar apontando para Atomenta
|
||||
- integração de API interna
|
||||
- OTP/crypto
|
||||
- comunicação backend-to-backend
|
||||
- consulta de dados mestres, se esta for a arquitetura
|
||||
|
||||
#### Não deve mais apontar para Atomenta
|
||||
- branding
|
||||
- domínio público
|
||||
- base URL de navegação do usuário
|
||||
- nomes do app
|
||||
- `package.json` e `ecosystem.config.js`
|
||||
|
||||
### 3. Definir estratégia de sessão/cookies
|
||||
|
||||
Decisão importante:
|
||||
|
||||
O sistema terá **dois contextos de autenticação diferentes**:
|
||||
|
||||
1. **partner session**
|
||||
- usada no `parceiro.pedifoods.com.br`
|
||||
- representa o lojista/operador
|
||||
- dá acesso ao painel administrativo
|
||||
|
||||
2. **customer session**
|
||||
- usada em `pedifoods.com.br` e em `{slug}.pedifoods.com.br`
|
||||
- representa o cliente/comprador
|
||||
- dá acesso à navegação, seleção de lojas, carrinho e compra
|
||||
|
||||
Essas duas sessões **não devem ser compartilhadas entre si**.
|
||||
|
||||
Se fossem compartilhadas:
|
||||
- um usuário logado como parceiro poderia cair autenticado na storefront da própria loja
|
||||
- haveria risco de misturar permissões administrativas com experiência de compra
|
||||
- o modelo de segurança e UX ficaria ambíguo
|
||||
|
||||
#### Opção A
|
||||
Sessão única compartilhada em `.pedifoods.com.br`
|
||||
|
||||
Resultado:
|
||||
- mesma sessão valeria para:
|
||||
- `pedifoods.com.br`
|
||||
- `parceiro.pedifoods.com.br`
|
||||
- `{slug}.pedifoods.com.br`
|
||||
|
||||
Problema:
|
||||
- **não serve para este cenário**
|
||||
- mistura sessão de lojista com sessão de cliente
|
||||
|
||||
#### Opção B
|
||||
Sessões separadas por contexto
|
||||
|
||||
Modelo recomendado:
|
||||
- `parceiro.pedifoods.com.br`
|
||||
- cookie próprio de parceiro
|
||||
- escopo exclusivo do painel
|
||||
- `pedifoods.com.br`
|
||||
- cookie próprio de cliente
|
||||
- pode ser compartilhado com `{slug}.pedifoods.com.br` se fizer sentido para a jornada do comprador
|
||||
- `{slug}.pedifoods.com.br`
|
||||
- usa sessão do cliente, nunca sessão do parceiro
|
||||
|
||||
Vantagens:
|
||||
- separa claramente os perfis
|
||||
- evita vazamento de autenticação entre painel e loja
|
||||
- reduz risco de autorização indevida
|
||||
- deixa a jornada de compra independente da jornada administrativa
|
||||
|
||||
Desvantagens:
|
||||
- exige mais cuidado no desenho de login/logout
|
||||
- exige nomes de cookies e middleware distintos
|
||||
|
||||
Recomendação:
|
||||
- usar **sessões separadas por contexto**
|
||||
- nunca compartilhar sessão de `partner` com `customer`
|
||||
- se necessário, compartilhar apenas a sessão do **cliente** entre:
|
||||
- `pedifoods.com.br`
|
||||
- `{slug}.pedifoods.com.br`
|
||||
|
||||
Implementação sugerida:
|
||||
- cookie de parceiro:
|
||||
- exemplo `pedifoods_partner_session`
|
||||
- domínio restrito a `parceiro.pedifoods.com.br`
|
||||
- cookie de cliente:
|
||||
- exemplo `pedifoods_customer_session`
|
||||
- domínio `.pedifoods.com.br` apenas se a jornada do cliente precisar navegar entre domínio principal e subdomínios de loja
|
||||
|
||||
## Estratégia de Dados
|
||||
|
||||
### Fonte de verdade
|
||||
|
||||
Precisamos assumir explicitamente:
|
||||
- o Atomenta continua sendo a fonte de verdade operacional
|
||||
- o PediFoods atua como camada especializada de experiência/lojista/storefront
|
||||
|
||||
Isso significa:
|
||||
- login e sessão podem existir no PediFoods
|
||||
- mas dados de loja, catálogo, usuário parceiro e regras sensíveis podem continuar vindo do Atomenta via API
|
||||
|
||||
## Fases de Implementação
|
||||
|
||||
## Fase 1. Higiene e identidade
|
||||
|
||||
Objetivo:
|
||||
- remover confusão estrutural atual
|
||||
|
||||
Itens:
|
||||
- corrigir `package.json` do PediFoods
|
||||
- corrigir `ecosystem.config.js`
|
||||
- revisar `env.example`
|
||||
- revisar nomes, textos e defaults públicos
|
||||
- separar claramente o que é branding PediFoods e o que é integração Atomenta
|
||||
|
||||
Saída:
|
||||
- o projeto deixa de se identificar como Atomenta
|
||||
|
||||
## Fase 2. Resolver host e contexto
|
||||
|
||||
Objetivo:
|
||||
- introduzir leitura de subdomínio
|
||||
|
||||
Itens:
|
||||
- criar utilitário central de hostname
|
||||
- classificar `public`, `partner`, `store`
|
||||
- disponibilizar contexto em middleware
|
||||
- ajustar templates/layouts e rotas para reagirem ao contexto
|
||||
|
||||
Saída:
|
||||
- uma única app responde diferente por host
|
||||
|
||||
## Fase 3. Fluxo público `pedifoods.com.br`
|
||||
|
||||
Objetivo:
|
||||
- consolidar homepage + login + listagem de lojas
|
||||
|
||||
Itens:
|
||||
- manter home atual
|
||||
- após login, mostrar lojas do usuário
|
||||
- ao clicar na loja, redirecionar para `slug.pedifoods.com.br`
|
||||
|
||||
Saída:
|
||||
- domínio principal vira hub do usuário
|
||||
|
||||
## Fase 4. Fluxo parceiro `parceiro.pedifoods.com.br`
|
||||
|
||||
Objetivo:
|
||||
- isolar o backoffice do lojista
|
||||
|
||||
Itens:
|
||||
- mover/ajustar as telas que hoje se comportam como "Atomenta Store"
|
||||
- garantir que esse host sempre abra painel parceiro
|
||||
- revisar permissões e middleware
|
||||
|
||||
Saída:
|
||||
- painel do lojista com identidade própria
|
||||
|
||||
## Fase 5. Fluxo loja `slug.pedifoods.com.br`
|
||||
|
||||
Objetivo:
|
||||
- transformar storefront em domínio por loja
|
||||
|
||||
Itens:
|
||||
- mapear slug -> loja
|
||||
- carregar tema, catálogo e dados por slug
|
||||
- revisar SEO/meta tags
|
||||
- revisar links absolutos
|
||||
|
||||
Saída:
|
||||
- cada loja com seu subdomínio
|
||||
|
||||
## Fase 6. Sessão compartilhada
|
||||
|
||||
Objetivo:
|
||||
- permitir navegação fluida entre subdomínios
|
||||
|
||||
Itens:
|
||||
- cookie domain `.pedifoods.com.br`
|
||||
- revisar login/logout
|
||||
- revisar redirecionamentos
|
||||
- revisar callbacks OTP
|
||||
|
||||
Saída:
|
||||
- usuário loga uma vez e navega entre contextos compatíveis
|
||||
|
||||
## Riscos
|
||||
|
||||
### 1. Misturar branding com integração
|
||||
|
||||
Se trocar tudo de `atomenta` cegamente, pode quebrar integrações reais.
|
||||
|
||||
### 2. Cookies atuais
|
||||
|
||||
Se hoje os cookies ainda usam nomes herdados, uma troca brusca pode invalidar sessões e OTP.
|
||||
|
||||
### 3. Links absolutos hardcoded
|
||||
|
||||
Há muitos pontos do PediFoods ainda apontando para Atomenta.
|
||||
Eles precisam ser classificados antes de alterar.
|
||||
|
||||
### 4. Deploy atual
|
||||
|
||||
Hoje o deploy sobe um projeto que ainda está semanticamente misturado.
|
||||
Sem limpeza mínima, a arquitetura nova vai nascer confusa.
|
||||
|
||||
## Recomendações Práticas
|
||||
|
||||
### Curto prazo
|
||||
|
||||
- corrigir identidade mínima do projeto PediFoods
|
||||
- mapear todos os usos de:
|
||||
- `atomenta.com.br`
|
||||
- `atomenta_token`
|
||||
- `atomenta_auth`
|
||||
- `ATOMENTA_*`
|
||||
- classificar cada ocorrência em:
|
||||
- branding
|
||||
- integração legítima
|
||||
|
||||
### Médio prazo
|
||||
|
||||
- implementar middleware de contexto por host
|
||||
- separar layouts `public`, `partner`, `store`
|
||||
- começar pelo domínio `parceiro.pedifoods.com.br`
|
||||
|
||||
### Longo prazo
|
||||
|
||||
- consolidar storefront por slug
|
||||
- revisar autenticação multi-subdomínio
|
||||
- avaliar se no futuro compensa separar em múltiplos apps
|
||||
|
||||
## Ordem Recomendada de Execução
|
||||
|
||||
1. Higienizar identidade do projeto PediFoods
|
||||
2. Mapear referências herdadas de Atomenta
|
||||
3. Criar resolvedor central de host/subdomínio
|
||||
4. Subir `parceiro.pedifoods.com.br`
|
||||
5. Ajustar `pedifoods.com.br` para login + lista de lojas
|
||||
6. Implementar `slug.pedifoods.com.br`
|
||||
7. Revisar cookies e sessão compartilhada
|
||||
|
||||
## Decisão Recomendada Agora
|
||||
|
||||
A melhor decisão agora é:
|
||||
|
||||
- **não tentar “desatomentar” tudo de uma vez**
|
||||
- primeiro separar:
|
||||
- identidade pública
|
||||
- painel parceiro
|
||||
- storefront por subdomínio
|
||||
- e só depois revisar dependências herdadas uma a uma
|
||||
|
||||
## Próximo Passo
|
||||
|
||||
Próxima entrega recomendada:
|
||||
|
||||
1. fazer uma auditoria do repositório PediFoods
|
||||
2. classificar referências herdadas em:
|
||||
- `pode trocar agora`
|
||||
- `depende de integração com Atomenta`
|
||||
3. implementar o resolvedor de subdomínio
|
||||
4. subir primeiro o contexto `parceiro.pedifoods.com.br`
|
||||
|
||||
## Tasks de Implementação
|
||||
|
||||
Legenda:
|
||||
- 🔴 pendente
|
||||
- 🟢 concluído
|
||||
|
||||
### Fase 1. Higiene do projeto PediFoods
|
||||
|
||||
- 🟢 Corrigir identidade básica do projeto em `package.json`
|
||||
- 🟢 Corrigir identidade básica do processo em `ecosystem.config.js`
|
||||
- 🔴 Revisar `env.example` para separar branding PediFoods de integração Atomenta
|
||||
- 🟢 Mapear todas as referências a `atomenta` no repositório
|
||||
- 🟢 Classificar cada referência como:
|
||||
- branding/UI
|
||||
- integração técnica legítima
|
||||
- legado morto
|
||||
- 🟢 Remover ou ajustar branding incorreto do PediFoods
|
||||
|
||||
### Fase 2. Contexto de domínio e subdomínio
|
||||
|
||||
- 🟢 Criar utilitário central para resolver o host atual
|
||||
- 🟢 Criar classificador de contexto:
|
||||
- `public`
|
||||
- `partner`
|
||||
- `store`
|
||||
- 🟢 Extrair `storeSlug` automaticamente quando o host for `{slug}.pedifoods.com.br`
|
||||
- 🟢 Injetar esse contexto em middleware global
|
||||
- 🟢 Expor o contexto para views/templates
|
||||
- 🔴 Garantir fallback seguro para domínio desconhecido
|
||||
|
||||
### Fase 3. Sessões separadas
|
||||
|
||||
- 🟢 Criar sessão de parceiro independente
|
||||
- 🔴 Criar sessão de cliente independente
|
||||
- 🔴 Garantir que `parceiro.pedifoods.com.br` nunca reutilize sessão de cliente
|
||||
- 🔴 Garantir que `{slug}.pedifoods.com.br` nunca reutilize sessão de parceiro
|
||||
- 🟢 Revisar nomes dos cookies
|
||||
- 🟢 Revisar `login`, `logout` e middleware de autenticação
|
||||
- 🟢 Revisar redirecionamentos pós-login por contexto
|
||||
|
||||
### Fase 4. `pedifoods.com.br`
|
||||
|
||||
- 🟢 Consolidar a home pública
|
||||
- 🟢 Consolidar login/cadastro/recuperação
|
||||
- 🔴 Criar tela pós-login com listagem de lojas do usuário
|
||||
- 🟢 Fazer o clique na loja redirecionar para `{slug}.pedifoods.com.br`
|
||||
- 🟢 Revisar meta tags, canonical e links absolutos
|
||||
|
||||
### Fase 5. `parceiro.pedifoods.com.br`
|
||||
|
||||
- 🟢 Isolar o painel do lojista nesse host
|
||||
- 🟢 Revisar middleware e permissões do painel
|
||||
- 🟢 Revisar links internos do painel para não mandar ao domínio errado
|
||||
- 🟢 Ajustar onboarding do parceiro
|
||||
- 🟢 Ajustar rotas administrativas de loja, pedidos, catálogo e financeiro
|
||||
- 🟢 Garantir que o painel não renderize a experiência pública da loja
|
||||
|
||||
### Fase 6. `{slug}.pedifoods.com.br`
|
||||
|
||||
- 🟢 Criar resolução da loja por slug
|
||||
- 🟢 Buscar loja e catálogo pelo slug
|
||||
- 🟢 Renderizar storefront por loja
|
||||
- 🟢 Ajustar tema, título, descrição e identidade da loja
|
||||
- 🟢 Ajustar links compartilháveis da loja
|
||||
- 🟢 Revisar SEO e OpenGraph por loja
|
||||
- 🔴 Garantir fallback para slug inexistente
|
||||
|
||||
### Fase 7. Gestão de slug da loja
|
||||
|
||||
- 🟢 Adicionar campo `storeSlug` como atributo persistido da loja
|
||||
- 🟢 Validar unicidade global do slug
|
||||
- 🟢 Validar formato do slug
|
||||
- 🟢 Gerar pré-preenchimento automático do slug no fim do onboarding com base no nome fantasia da loja
|
||||
- 🟢 Criar tela de configuração do slug no painel parceiro
|
||||
- 🟢 Exibir aviso de impacto da troca de slug
|
||||
- 🟢 Salvar data da última alteração de slug
|
||||
- 🟢 Bloquear nova alteração por 90 dias
|
||||
- 🟢 Exibir contador ou data de desbloqueio para nova alteração
|
||||
- 🔴 Criar redirect temporário do slug antigo para o novo, se viável
|
||||
|
||||
### Fase 8. Integração com Atomenta
|
||||
|
||||
- 🟢 Revisar quais chamadas devem continuar indo ao Atomenta
|
||||
- 🟢 Centralizar base URL interna da API do Atomenta
|
||||
- 🔴 Revisar OTP e autenticação compartilhada
|
||||
- 🟢 Revisar cookies herdados `atomenta_*`
|
||||
- 🔴 Revisar endpoints de catálogo, loja, financeiro e customer lookup
|
||||
- 🔴 Remover dependências herdadas desnecessárias
|
||||
|
||||
### Fase 9. Deploy e infraestrutura
|
||||
|
||||
- 🔴 Ajustar nginx/proxy para:
|
||||
- `pedifoods.com.br`
|
||||
- `parceiro.pedifoods.com.br`
|
||||
- `*.pedifoods.com.br`
|
||||
- 🔴 Validar wildcard localmente antes da etapa de DNS público
|
||||
- 🔴 Garantir certificado TLS compatível com wildcard
|
||||
- 🔴 Validar resolução correta de host até a app Node
|
||||
|
||||
## Status Atual
|
||||
|
||||
Legenda:
|
||||
- 🟢 concluído
|
||||
- 🟡 parcial
|
||||
- 🔴 pendente
|
||||
|
||||
Resumo do que já foi entregue no app:
|
||||
- 🟢 identidade básica do projeto corrigida
|
||||
- 🟢 resolução central de host/subdomínio
|
||||
- 🟢 separação inicial entre `public`, `partner` e `store`
|
||||
- 🟢 slug canônico com preview, unicidade, cooldown de 90 dias e geração automática no onboarding
|
||||
- 🟢 storefront canônica em `{slug}.pedifoods.com.br`
|
||||
- 🟢 links públicos e links do painel abrindo a loja publicada correta
|
||||
- 🟢 limpeza principal de branding visível do PediFoods
|
||||
- 🟢 frontend priorizando `pedifoods_partner_token` com fallback para legado
|
||||
|
||||
O que ainda falta para fechar o fluxo completo:
|
||||
- 🔴 autenticação real do cliente
|
||||
- 🔴 tela pós-login do cliente com listagem de lojas
|
||||
- 🔴 fallback para slug inexistente
|
||||
- 🔴 redirect temporário de slug antigo para slug novo
|
||||
- 🔴 wildcard real em proxy/Cloudflare/TLS
|
||||
- 🔴 Validar deploy do PediFoods sem contaminar com Atomenta
|
||||
- 🔴 Configurar wildcard DNS no Cloudflare
|
||||
- esta task deve ficar por último
|
||||
- quando chegarmos nela, você executa manualmente no Cloudflare
|
||||
- eu só vou te avisar e te passar o valor exato
|
||||
|
||||
### Fase 10. Testes de ponta a ponta
|
||||
|
||||
- 🔴 Testar login de cliente em `pedifoods.com.br`
|
||||
- 🔴 Testar seleção de loja e redirecionamento para `{slug}.pedifoods.com.br`
|
||||
- 🔴 Testar login de parceiro em `parceiro.pedifoods.com.br`
|
||||
- 🔴 Testar isolamento entre sessão de parceiro e sessão de cliente
|
||||
- 🔴 Testar troca de slug com bloqueio de 90 dias
|
||||
- 🔴 Testar slug inválido/inexistente
|
||||
- 🔴 Testar logout em cada contexto
|
||||
- 🔴 Testar links absolutos, redirects e cookies
|
||||
|
||||
## Política de Slug da Loja
|
||||
|
||||
Sua ideia funciona e faz sentido.
|
||||
|
||||
### Recomendação
|
||||
|
||||
O slug deve ser:
|
||||
- criado uma primeira vez no onboarding da loja
|
||||
- editável pelo parceiro no painel
|
||||
- bloqueado por 90 dias após cada alteração
|
||||
|
||||
### Motivos para essa regra
|
||||
|
||||
- evita troca frequente de URL
|
||||
- reduz confusão para clientes recorrentes
|
||||
- protege links já compartilhados
|
||||
- reduz impacto operacional em cache, indexing e hábito do usuário
|
||||
|
||||
### Como funcionaria
|
||||
|
||||
Cada loja teria campos como:
|
||||
- `storeSlug`
|
||||
- `slugUpdatedAt`
|
||||
- `slugLockedUntil`
|
||||
- `slugGeneratedBySystemAt`
|
||||
- `slugFirstManualUpdateAt`
|
||||
|
||||
Regra:
|
||||
- se nunca definiu slug:
|
||||
- o sistema pré-preenche automaticamente
|
||||
- o usuário pode ajustar antes de concluir
|
||||
- se já definiu:
|
||||
- só pode alterar novamente após 90 dias
|
||||
|
||||
### Geração inicial do slug
|
||||
|
||||
Recomendação:
|
||||
- ao terminar o onboarding, gerar um pré-preenchimento automático baseado no nome fantasia
|
||||
|
||||
Exemplo:
|
||||
- `Pizzaria do Zé` -> `pizzaria-do-ze`
|
||||
- `Temaki House Prime` -> `temaki-house-prime`
|
||||
|
||||
O usuário:
|
||||
- vê o slug sugerido
|
||||
- pode editar antes de salvar pela primeira vez
|
||||
|
||||
Importante:
|
||||
- o slug gerado automaticamente pelo sistema **não inicia** a janela de bloqueio de 90 dias
|
||||
- ele serve apenas como valor inicial/sugestão persistida
|
||||
- o contador de 90 dias só começa quando houver a **primeira alteração manual do lojista**
|
||||
|
||||
### Limite de tamanho
|
||||
|
||||
Recomendação:
|
||||
- limitar o slug a **30 caracteres**
|
||||
|
||||
Esse limite deve contar:
|
||||
- letras
|
||||
- números
|
||||
- hífens
|
||||
|
||||
Na prática:
|
||||
- espaços viram hífen
|
||||
- então o total final do slug salvo não pode passar de `30`
|
||||
|
||||
Exemplo de regra:
|
||||
- nome fantasia muito grande:
|
||||
- `Loja Muito Grande Com Nome Enorme da Silva`
|
||||
- slug gerado:
|
||||
- `loja-muito-grande-com-nome`
|
||||
|
||||
### Regra de sanitização sugerida
|
||||
|
||||
O gerador automático deve:
|
||||
- converter para minúsculas
|
||||
- remover acentos
|
||||
- trocar espaços por hífen
|
||||
- remover caracteres especiais
|
||||
- colapsar hífens duplicados
|
||||
- cortar em `30` caracteres
|
||||
- remover hífen do início/fim
|
||||
|
||||
### Se o slug já existir
|
||||
|
||||
Se o slug gerado já estiver em uso:
|
||||
- adicionar sufixo incremental curto
|
||||
|
||||
Exemplo:
|
||||
- `pizzaria-do-ze`
|
||||
- `pizzaria-do-ze-2`
|
||||
- `pizzaria-do-ze-3`
|
||||
|
||||
Sempre respeitando o limite final de `30` caracteres
|
||||
|
||||
### Regra de bloqueio de 90 dias
|
||||
|
||||
Regra correta:
|
||||
|
||||
- **geração automática pelo sistema**
|
||||
- não conta como alteração manual
|
||||
- não bloqueia o campo
|
||||
|
||||
- **primeira edição manual feita pelo lojista**
|
||||
- passa a contar como alteração real
|
||||
- grava `slugFirstManualUpdateAt`
|
||||
- grava `slugUpdatedAt`
|
||||
- define `slugLockedUntil = slugUpdatedAt + 90 dias`
|
||||
|
||||
- **edições seguintes**
|
||||
- só permitidas após `slugLockedUntil`
|
||||
|
||||
### Exemplo prático
|
||||
|
||||
1. onboarding termina
|
||||
2. sistema gera:
|
||||
- `pizzaria-do-ze`
|
||||
3. lojista vê o valor e troca para:
|
||||
- `pizza-do-ze-centro`
|
||||
4. essa troca manual:
|
||||
- conta como primeira alteração real
|
||||
- inicia a trava de 90 dias
|
||||
|
||||
Se o lojista aceitar o slug automático sem mexer:
|
||||
- nenhum bloqueio de 90 dias deve ser iniciado
|
||||
- ele ainda pode fazer a primeira alteração manual depois
|
||||
|
||||
### Ajuste das tasks
|
||||
|
||||
- 🔴 Persistir metadado informando se o slug atual foi gerado automaticamente ou definido manualmente
|
||||
- 🔴 Garantir que a geração automática no onboarding não inicie `slugLockedUntil`
|
||||
- 🔴 Iniciar a janela de 90 dias somente na primeira alteração manual do lojista
|
||||
|
||||
### Validações necessárias
|
||||
|
||||
- slug único no sistema
|
||||
- somente letras minúsculas, números e hífen
|
||||
- tamanho mínimo e máximo
|
||||
- blacklist de reservados, por exemplo:
|
||||
- `www`
|
||||
- `api`
|
||||
- `admin`
|
||||
- `app`
|
||||
- `parceiro`
|
||||
- `mail`
|
||||
- `git`
|
||||
- `proxy`
|
||||
|
||||
### Redirect do slug antigo
|
||||
|
||||
Se possível, é recomendável:
|
||||
- guardar o slug antigo
|
||||
- fazer redirect `301` do slug antigo para o novo por um período
|
||||
|
||||
Isso ajuda:
|
||||
- SEO
|
||||
- links salvos
|
||||
- usuários acostumados com a URL antiga
|
||||
|
||||
### Sobre DNS e Cloudflare
|
||||
|
||||
Isso funciona bem se você usar:
|
||||
- wildcard DNS `*.pedifoods.com.br`
|
||||
- proxy reverso lendo o `Host`
|
||||
|
||||
Nesse modelo:
|
||||
- você **não precisa criar um registro DNS novo por loja**
|
||||
- o wildcard cobre todos os slugs
|
||||
- a troca de slug depende mais da aplicação e do cache HTTP do que de propagação DNS individual
|
||||
|
||||
Ou seja:
|
||||
- a trava de 90 dias continua fazendo sentido por produto e UX
|
||||
- mas não por limitação técnica de DNS em si
|
||||
|
||||
### Recomendação final para slug
|
||||
|
||||
Implementar assim:
|
||||
|
||||
- slug definido no onboarding
|
||||
- edição permitida no painel parceiro
|
||||
- nova alteração somente após 90 dias
|
||||
- aviso visual claro antes de salvar
|
||||
- registro do slug antigo para redirect temporário
|
||||
Reference in New Issue
Block a user