chore: organize loose root files into archives, configs and docs
This commit is contained in:
parent
ed728bcd1a
commit
06e3458ba8
13 changed files with 374 additions and 0 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -5,3 +5,7 @@ credentials/*
|
||||||
|
|
||||||
# Terraform variable files can carry environment-specific secrets and IDs
|
# Terraform variable files can carry environment-specific secrets and IDs
|
||||||
*.tfvars
|
*.tfvars
|
||||||
|
|
||||||
|
# Ignore large archive files
|
||||||
|
archives/*.zip
|
||||||
|
archives/*.sql
|
||||||
|
|
|
||||||
1
archives/login_b64.txt
Normal file
1
archives/login_b64.txt
Normal file
File diff suppressed because one or more lines are too long
BIN
archives/login_b64_clean.txt
Normal file
BIN
archives/login_b64_clean.txt
Normal file
Binary file not shown.
51
dev-scripts/configs/ghj-docker-compose.yml
Normal file
51
dev-scripts/configs/ghj-docker-compose.yml
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: ghj-db
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: user
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
POSTGRES_DB: gohorsejobs
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- ghj-db-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U user -d gohorsejobs"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: ghj-backend
|
||||||
|
ports:
|
||||||
|
- "8521:8521"
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://user:password@db:5432/gohorsejobs?sslmode=disable
|
||||||
|
- JWT_SECRET=rede5-secret-key-at-least-32-chars-long
|
||||||
|
- PASSWORD_PEPPER=rede5-pepper
|
||||||
|
- COOKIE_SECRET=rede5-cookie-secret
|
||||||
|
- ENV=development
|
||||||
|
- BACKEND_PORT=8521
|
||||||
|
- CORS_ORIGINS=https://ghj.rede5.com.br,http://localhost:3000
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: ghj-frontend
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=https://api-ghj.rede5.com.br/api/v1
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
ghj-db-data:
|
||||||
53
dev-scripts/configs/ghj-nginx-ssl.conf
Normal file
53
dev-scripts/configs/ghj-nginx-ssl.conf
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name ghj.rede5.com.br api-ghj.rede5.com.br;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name ghj.rede5.com.br;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/ghj.rede5.com.br/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/ghj.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:3000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /_next/webpack-hmr {
|
||||||
|
proxy_pass http://127.0.0.1:3000/_next/webpack-hmr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name api-ghj.rede5.com.br;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/ghj.rede5.com.br/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/ghj.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8521;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
dev-scripts/configs/sim-air.toml
Normal file
20
dev-scripts/configs/sim-air.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
root = "."
|
||||||
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
bin = "./tmp/main"
|
||||||
|
cmd = "go build -o ./tmp/main ./cmd/api"
|
||||||
|
delay = 1000
|
||||||
|
exclude_dir = ["assets", "tmp", "vendor", "tests", "uploads", "node_modules", "frontend", "saveinmed-frontend"]
|
||||||
|
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||||
|
stop_on_error = true
|
||||||
|
|
||||||
|
[color]
|
||||||
|
app = ""
|
||||||
|
build = "yellow"
|
||||||
|
main = "magenta"
|
||||||
|
runner = "green"
|
||||||
|
watcher = "cyan"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
time = false
|
||||||
55
dev-scripts/configs/sim-docker-compose-dev.yml
Normal file
55
dev-scripts/configs/sim-docker-compose-dev.yml
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: sim-db-dev
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: "123"
|
||||||
|
POSTGRES_DB: saveinmed
|
||||||
|
ports:
|
||||||
|
- "55432:5432"
|
||||||
|
volumes:
|
||||||
|
- sim-db-dev-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres -d saveinmed"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: cosmtrek/air
|
||||||
|
container_name: sim-backend-dev
|
||||||
|
working_dir: /app
|
||||||
|
ports:
|
||||||
|
- "8522:8522"
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://postgres:123@db:5432/saveinmed?sslmode=disable
|
||||||
|
- JWT_SECRET=saveinmed-secret-key-at-least-32-chars-long
|
||||||
|
- ENV=development
|
||||||
|
- BACKEND_PORT=8522
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
- ./backend/air.toml:/app/.air.toml
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
command: -c .air.toml
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: node:22-alpine
|
||||||
|
container_name: sim-frontend-dev
|
||||||
|
working_dir: /app
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=https://api-sim.rede5.com.br
|
||||||
|
- NODE_ENV=development
|
||||||
|
- PORT=3001
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/app
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
command: sh -c "npm install && npm run dev"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
sim-db-dev-data:
|
||||||
53
dev-scripts/configs/sim-nginx-ssl.conf
Normal file
53
dev-scripts/configs/sim-nginx-ssl.conf
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name sim.rede5.com.br api-sim.rede5.com.br;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name sim.rede5.com.br;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/ghj.rede5.com.br/fullchain.pem; # Usando o mesmo cert por enquanto ou gerando novo
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/ghj.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:3001;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /_next/webpack-hmr {
|
||||||
|
proxy_pass http://127.0.0.1:3001/_next/webpack-hmr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name api-sim.rede5.com.br;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/ghj.rede5.com.br/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/ghj.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8522;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
dev-scripts/configs/sim-nginx-utf8.conf
Normal file
57
dev-scripts/configs/sim-nginx-utf8.conf
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name sim.rede5.com.br api-sim.rede5.com.br;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name sim.rede5.com.br;
|
||||||
|
|
||||||
|
charset utf-8; # FORÇAR UTF-8
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/sim.rede5.com.br/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/sim.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:3001;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /_next/webpack-hmr {
|
||||||
|
proxy_pass http://127.0.0.1:3001/_next/webpack-hmr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name api-sim.rede5.com.br;
|
||||||
|
|
||||||
|
charset utf-8; # FORÇAR UTF-8
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/sim.rede5.com.br/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/sim.rede5.com.br/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8522;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
docs/QA_PLAN.md
Normal file
45
docs/QA_PLAN.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# GoHorseJobs - Plano de QA Massivo (30 Atividades)
|
||||||
|
|
||||||
|
Este documento descreve os fluxos críticos de teste para garantir a estabilidade e segurança da plataforma.
|
||||||
|
|
||||||
|
## 🔐 Grupo 1: Segurança e Autenticação (HttpOnly & RBAC)
|
||||||
|
1. **Login Seguro**: Validar que após o login, o cookie `jwt` NÃO é acessível via `document.cookie` no console.
|
||||||
|
2. **Expiração de Sessão**: Alterar o JWT para expirar em 10 segundos e verificar se o frontend redireciona para `/login` automaticamente.
|
||||||
|
3. **Cross-Subdomain Auth**: Logar em `ghj.rede5.com.br` e verificar se a API em `api-ghj.rede5.com.br` aceita o cookie.
|
||||||
|
4. **RBAC Candidato**: Tentar acessar `/api/v1/users` com token de candidato e validar o erro `403 Forbidden`.
|
||||||
|
5. **RBAC Admin**: Validar que apenas administradores conseguem acessar o dashboard de auditoria.
|
||||||
|
6. **Logout Total**: Clicar em Logout e tentar dar um "Back" no navegador para ver se a sessão foi realmente invalidada.
|
||||||
|
|
||||||
|
## 🐎 Grupo 2: Fluxo de Recrutamento (Empresas & Vagas)
|
||||||
|
7. **Criação de Vaga**: Criar vaga com todos os campos e validar se aparece instantaneamente na Home.
|
||||||
|
8. **Upload de Logo**: Subir um logo de 5MB para a empresa e validar se o redimensionamento automático (Civo Storage) funciona.
|
||||||
|
9. **Edição de Vaga**: Alterar o status de uma vaga de `open` para `closed` e verificar se ela some das buscas públicas.
|
||||||
|
10. **Busca por Localização**: Testar o Autocomplete de Kyoto, Japão e validar se a vaga criada no QA anterior é encontrada.
|
||||||
|
11. **Filtro de Salário**: Filtrar vagas com salário > 15.000 e validar os resultados.
|
||||||
|
12. **Destaque de Vaga (Stripe)**: Simular o checkout de uma vaga "Featured" e validar se ela ganha o badge de destaque após o webhook do Stripe.
|
||||||
|
|
||||||
|
## 👥 Grupo 3: Experiência do Candidato
|
||||||
|
13. **Perfil Completo**: Preencher 10 habilidades e validar se o gráfico de radar (se houver) renderiza corretamente.
|
||||||
|
14. **Candidatura com Perguntas**: Responder a um formulário de 5 perguntas customizadas e validar se o recrutador recebe as respostas.
|
||||||
|
15. **Upload de CV**: Subir um PDF corrompido e validar se o sistema rejeita com mensagem amigável.
|
||||||
|
16. **Favoritos**: Adicionar 5 vagas aos favoritos e validar se a lista persiste após o refresh.
|
||||||
|
17. **Alertas de Vaga**: Criar um alerta para "Go Developer" e simular a criação de uma vaga para disparar o e-mail (LavinMQ).
|
||||||
|
|
||||||
|
## 💬 Grupo 4: Comunicação Real-time (Appwrite & FCM)
|
||||||
|
18. **Chat Instantâneo**: Abrir duas abas (Empresa e Candidato) e validar se as mensagens aparecem sem refresh.
|
||||||
|
19. **Notificação Push (FCM)**: Bloquear a tela do celular e validar se o Push chega quando uma nova mensagem é recebida.
|
||||||
|
20. **Status de Leitura**: Marcar mensagem como lida no Appwrite e validar o visual no frontend.
|
||||||
|
21. **Histórico de Chat**: Validar se mensagens antigas (mais de 50) carregam via infinite scroll.
|
||||||
|
|
||||||
|
## ⚡ Grupo 5: Performance e Infraestrutura (LavinMQ & Redis)
|
||||||
|
22. **Carga na Fila**: Disparar 100 candidaturas em 1 segundo e validar se o Worker do LavinMQ processa todas sem travar o sistema.
|
||||||
|
23. **Cache de Home**: Validar se a Home carrega em menos de 200ms após a primeira visita (Redis).
|
||||||
|
24. **Resiliência DB**: Derrubar o container do Postgres e validar se o Backend exibe erro de "Serviço Temporariamente Indisponível" em vez de crashar.
|
||||||
|
25. **Auto-reconnect AMQP**: Desligar o LavinMQ por 5 segundos e validar se o Backend reconecta automaticamente quando ele volta.
|
||||||
|
|
||||||
|
## 🛠️ Grupo 6: Ferramentas Administrativas
|
||||||
|
26. **Seeder Reset**: Rodar o seeder de reset e validar se o banco volta ao estado inicial perfeito.
|
||||||
|
27. **Purge Cache Cloudflare**: Clicar no botão de Purge no Dashboard e validar via header `CF-Cache-Status: MISS`.
|
||||||
|
28. **Teste de SMTP**: Usar a nova ferramenta de "Testar Envio" para validar as credenciais do Gmail/Sendgrid.
|
||||||
|
29. **Logs de Auditoria**: Verificar se a tentativa de login falha de um IP desconhecido gera um alerta no sistema.
|
||||||
|
30. **Configurações de Tema**: Alterar a cor primária para Verde e validar se toda a UI (botões, badges) muda instantaneamente.
|
||||||
35
docs/TASKS.md
Normal file
35
docs/TASKS.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Rede5 - Gestão de Atividades Maestro
|
||||||
|
|
||||||
|
## 🐎 GoHorseJobs (Plano de Ação Detalhado)
|
||||||
|
|
||||||
|
### ⚡ Épico 3: Otimização e Mensageria (LavinMQ + FCM)
|
||||||
|
- [ ] **Arquitetura de Mensageria (LavinMQ)**:
|
||||||
|
- Implementar o `LavinMQService` no Backend (Go) para conexões AMQP persistentes.
|
||||||
|
- Criar o produtor de eventos genérico (ex: `PublishEvent(exchange, key, payload)`).
|
||||||
|
- Configurar filas principais: `notifications`, `image_processing`, `system_audits`.
|
||||||
|
- [ ] **Sistema de Notificações Push (Firebase/FCM)**:
|
||||||
|
- Implementar o `FCMService` usando o Admin SDK do Firebase.
|
||||||
|
- Criar funcionalidade para salvar tokens FCM dos usuários no banco de dados (`fcm_tokens`).
|
||||||
|
- Desenvolver o Worker de Notificações que:
|
||||||
|
1. Consome a fila `notifications` do LavinMQ.
|
||||||
|
2. Identifica o dispositivo do usuário.
|
||||||
|
3. Dispara o Push via FCM.
|
||||||
|
- [ ] **Telemetria e Analytics**:
|
||||||
|
- Integrar o Firebase Analytics no frontend para monitorar funis de conversão (ex: Cliques em Vaga -> Aplicação).
|
||||||
|
|
||||||
|
### 🎨 Épico 2: Refatoração de UI e Design System
|
||||||
|
- [ ] **Autocomplete de Localização (Cidade/Estado)**:
|
||||||
|
- Implementar busca preditiva integrada com as 153k cidades do Postgres.
|
||||||
|
- [x] **Espaçamento Global**: Corrigir `Label` colado no `Input` - CONCLUÍDO.
|
||||||
|
- [ ] **Dashboards**: Padronizar telas de Candidatos e Aplicações.
|
||||||
|
|
||||||
|
### 🧪 Épico 1: QA e Fluxos de Usuário (End-to-End)
|
||||||
|
- [ ] **Fluxo do SuperAdmin**: Aprovar empresas e gerenciar planos.
|
||||||
|
- [ ] **Fluxo da Empresa**: Criar vaga, pagar destaque (Stripe) e gerenciar candidatos.
|
||||||
|
- [ ] **Fluxo do Candidato**: Perfil completo, busca por raio de KM e aplicação.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏥 SaveInMed (Próximos Passos)
|
||||||
|
- [ ] Criar Dashboard de Vendas para Distribuidoras.
|
||||||
|
- [ ] Implementar sistema de chat em tempo real via Appwrite.
|
||||||
BIN
docs/relatorio.pdf
Normal file
BIN
docs/relatorio.pdf
Normal file
Binary file not shown.
BIN
docs/relatorio_completo.pdf
Normal file
BIN
docs/relatorio_completo.pdf
Normal file
Binary file not shown.
Loading…
Reference in a new issue