Virtual Stores System — Visao Geral do Sistema
Documento de referencia para administradores de sistema da In All Web. Audiencia: equipa tecnica interna (SysAdmin).
Arquitectura Geral
O Virtual Stores System e uma plataforma SaaS multi-tenant de e-commerce composta por tres camadas principais:
| Camada | Tecnologia | Funcao |
|---|---|---|
| Backend API | FastAPI + Python 3.12 | Logica de negocio, autenticacao, REST API |
| Admin Panel | React 19 + Vite (SPA) | Painel de gestao para admins de tenant |
| Storefront | Next.js 15 (App Router, SSR/SSG) | Loja publica indexavel pelo Google |
Cada camada e deployada como container Docker independente e orquestrada via Docker Compose + Traefik como reverse proxy.
Internet
|
Traefik (reverse proxy + TLS)
|
+-- /api/* --> Backend (FastAPI, porta 8000)
+-- /admin/* --> Admin Panel (React SPA, porta 5173)
+-- {slug}.store.* --> Storefront (Next.js, porta 3001)
Multi-Tenant
Isolamento de dados
O isolamento entre tenants e garantido por Row-Level Security (RLS) ao nivel da base de dados. Cada tabela relevante tem a coluna tenant_id e todas as queries sao filtradas automaticamente.
Nunca e possivel, por design, que um tenant aceda a dados de outro tenant.
UnifiedTenantMiddleware
O middleware UnifiedTenantMiddleware resolve qual o tenant activo em cada pedido, seguindo esta ordem de prioridade:
- JWT token (campo
tenant_idno payload) - Subdominio (
{slug}.store.inallweb.com) - Dominio custom (mapeado na tabela
custom_domains) - Fallback (rejeicao com 401 ou 404)
O tenant resolvido e injectado no contexto do pedido e propagado para todas as queries da BD.
FeatureGateMiddleware
O FeatureGateMiddleware verifica, para cada endpoint protegido, se o tenant tem o plano ou addon necessario. Endpoints marcados com @require_plan("business") ou @require_addon("wishlist") sao bloqueados automaticamente se o tenant nao tiver a funcionalidade activa.
Base de Dados
PostgreSQL 15 — usado em todos os ambientes (dev, uat, staging, prod). SQLite nunca e usado.
Configuracao de pool recomendada:
engine = create_async_engine(
DATABASE_URL,
pool_pre_ping=True,
pool_size=10,
max_overflow=20,
pool_recycle=3600,
)
Migracoes geridas via Alembic. Sempre testar migracoes em dev antes de aplicar em staging ou prod.
Porta padrao em dev/uat: 5435 (mapeada do container para o host).
Cache
Redis e usado para:
- Cache de sessoes e tokens JWT revogados
- Cache de resultados de pesquisa e catalogo
- Rate limiting
- Filas de tarefas async (Celery, quando aplicavel)
Armazenamento de Imagens
MinIO (S3-compatible) armazena todas as imagens de produtos, logos e banners dos tenants.
O acesso publico e feito via Cloudflare CDN como proxy, o que garante:
- Cache de imagens no edge (menor latencia para utilizadores finais)
- Proteccao do endpoint MinIO directo
- URLs limpas sem expor o storage interno
Configuracao no bucket: products (bucket principal).
Utilizador --> Cloudflare CDN --> MinIO
(cache edge) (storage)
Pagamentos — Stripe Connect
Os pagamentos sao orquestrados pelo iaw-platform, que actua como hub central de Stripe Connect. O virtual-stores nunca interage directamente com a API do Stripe — chama sempre o iaw-platform.
Fluxo:
Loja (checkout) --> Backend VSS --> iaw-platform API --> Stripe Connect
/api/stripe-connect/*
(JWT Bearer)
Cada tenant tem um stripe_connect_account_id registado apos completar o onboarding KYC federado.
Referencia: /opt/contracts/stripe-connect-flow.md
Emails
Zeptomail e o servico de envio de emails transacionais. Os templates estao disponiveis em 6 idiomas: PT, EN, FR, ES, IT, DE.
Tipos de email enviados:
- Confirmacao de registo e verificacao de email
- Confirmacao de encomenda
- Actualizacao de estado de envio
- Recuperacao de password
- Faturas (em conjunto com Moloni)
Referencia de templates: /opt/contracts/email-templates.md
Modulos Backend
O backend esta organizado em modulos independentes. Cada modulo vive em src/modules/<modulo>/ e contem routes.py, schemas.py, service.py e models.py.
| Modulo | Descricao |
|---|---|
auth | Login, registo, JWT, refresh tokens, roles |
products | CRUD de produtos, variantes, precos |
categories | Hierarquia de categorias por tenant |
cart | Carrinho de compras (sessao ou autenticado) |
checkout | Fluxo de checkout multi-passo |
orders | Gestao de encomendas, estados, historico |
payments | Integracao com iaw-platform / Stripe Connect |
coupons | Codigos de desconto e promocoes |
customers | Perfis de clientes finais |
reviews | Avaliacoes e comentarios de produtos |
wishlist | Lista de desejos (addon) |
loyalty | Programa de pontos e fidelizacao (addon) |
search | Pesquisa por tags e atributos |
recommendations | Recomendacoes de produtos |
reports | Relatorios de vendas, produtos, clientes |
faq | Perguntas frequentes por tenant |
suppliers | Gestao de fornecedores |
inventory | Controlo de stock |
shipping | Metodos e zonas de envio |
pages | Paginas de conteudo (sobre, politicas, etc.) |
storefront | API publica consumida pelo Next.js storefront |
dashboard | Metricas e KPIs para o admin do tenant |
sysadmin | Endpoints exclusivos da equipa In All Web |
Ambientes
| Ambiente | URL base | Dados | Stripe | Testes |
|---|---|---|---|---|
| dev | dev.store.inallweb.com | Seed/demo | Sandbox | E2E completo |
| uat | uat.store.inallweb.com | Seed/demo | Sandbox | E2E completo |
| staging | staging.store.inallweb.com | Reais anonimizados | Sandbox | E2E completo |
| prod | {slug}.store.inallweb.com | Reais | LIVE keys | Dry-run apenas |
DEMO_DATA_ENABLED=true em dev e uat. DEMO_DATA_ENABLED=false em staging e prod.
CI/CD — Pipeline GitLab
O repositorio usa GitLab CI com os seguintes stages em sequencia:
| Stage | O que faz |
|---|---|
validate | Linting (Ruff, ESLint), type check (mypy, tsc) |
security | pip-audit, npm audit, Semgrep OWASP |
quality | SonarQube — quality gate: 0 bugs, 0 vulnerabilities, <3% duplicacao |
build | Build das imagens Docker |
test | pytest (backend), vitest (frontend) |
release | Push de imagens para registry |
deploy | Deploy no ambiente alvo |
verify | Verificacao de health checks pos-deploy |
e2e | Testes Playwright end-to-end (bloqueante em uat/staging) |
evidence | Captura de screenshots e artefactos |
docs | Geracao automatica de documentacao |
promote | Promove para o ambiente seguinte (dev->uat->staging->prod) |
Branches protegidas (sem push directo): main, prod, staging.
Runners registados com tags: stores-ci (validate, build, test, E2E) e stores-deploy (deploy, verify, promote).
Endpoints de Monitoring
O Zabbix monitoriza todos os ambientes. O backend expoe:
GET /api/health
Retorna 200 se o servidor esta a correr. Sem autenticacao. Usado pelo load balancer.
{"status": "ok"}
GET /api/ready
Retorna 200 se todas as dependencias estao operacionais (BD + Redis + MinIO). Retorna 503 se alguma dependencia estiver em baixo. O deploy script verifica este endpoint antes de trocar trafego.
{"ready": true}
Graceful shutdown configurado a 30 segundos (timeout_graceful_shutdown=30).
Feature Gating
O FeatureGateMiddleware controla o acesso a funcionalidades com base no plano do tenant e nos addons activos.
Exemplos de restricoes:
| Funcionalidade | Plano minimo |
|---|---|
| Multi-utilizador (staff) | Business |
| Wishlist | Addon activado |
| Loyalty program | Addon activado |
| Relatorios avancados | Professional |
| Multi-sistema | Professional |
O middleware consulta o plano e addons activos do tenant em cada pedido e rejeita com 403 se o acesso nao for permitido.
Seguranca e RGPD
- Passwords com bcrypt
- JWT com refresh tokens (dual-token)
- RLS na BD por
tenant_id - Dados pessoais nunca em logs (nomes, emails, NIF, moradas)
- Anonimizacao obrigatoria ao copiar dados de prod para staging/dev
- Script:
stores-management/backend/scripts/anonymize_db.py - Credenciais em Vault (
secret/data/stores/*) — nunca em codigo ou commits
Contactos e Recursos
| Recurso | URL / Path |
|---|---|
| GitLab | https://gitlab.inallweb.com |
| SonarQube | https://sonarqube.inallweb.com |
| Vault | https://vault.inallweb.com |
| Mattermost | https://mattermost.inallweb.com |
| Contratos inter-projecto | /opt/contracts/ |
| Repositorio | /opt/products/virtual-stores-system/ |