🏗️ feat(admin): criar scaffold inicial do orquestrador-admin
parent
498836fd38
commit
17583236a6
@ -0,0 +1,3 @@
|
||||
from admin_app.main import app
|
||||
|
||||
__all__ = ["app"]
|
||||
@ -0,0 +1,10 @@
|
||||
from fastapi import Request
|
||||
|
||||
from admin_app.core.settings import AdminSettings, get_admin_settings
|
||||
|
||||
|
||||
def get_settings(request: Request) -> AdminSettings:
|
||||
app_settings = getattr(request.app.state, "admin_settings", None)
|
||||
if isinstance(app_settings, AdminSettings):
|
||||
return app_settings
|
||||
return get_admin_settings()
|
||||
@ -0,0 +1,6 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from admin_app.api.routes.system import router as system_router
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(system_router)
|
||||
@ -0,0 +1,27 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from admin_app.api.dependencies import get_settings
|
||||
from admin_app.api.schemas import AdminHealthResponse, AdminRootResponse, AdminSystemInfoResponse
|
||||
from admin_app.core.settings import AdminSettings
|
||||
from admin_app.services.system_service import SystemService
|
||||
|
||||
router = APIRouter(tags=["system"])
|
||||
|
||||
|
||||
def _build_service(settings: AdminSettings) -> SystemService:
|
||||
return SystemService(settings=settings)
|
||||
|
||||
|
||||
@router.get("/", response_model=AdminRootResponse)
|
||||
def root(settings: AdminSettings = Depends(get_settings)):
|
||||
return _build_service(settings).build_root_payload()
|
||||
|
||||
|
||||
@router.get("/health", response_model=AdminHealthResponse)
|
||||
def health_check(settings: AdminSettings = Depends(get_settings)):
|
||||
return _build_service(settings).build_health_payload()
|
||||
|
||||
|
||||
@router.get("/system/info", response_model=AdminSystemInfoResponse)
|
||||
def system_info(settings: AdminSettings = Depends(get_settings)):
|
||||
return _build_service(settings).build_system_info_payload()
|
||||
@ -0,0 +1,23 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AdminRootResponse(BaseModel):
|
||||
service: str
|
||||
status: str
|
||||
message: str
|
||||
environment: str
|
||||
|
||||
|
||||
class AdminHealthResponse(BaseModel):
|
||||
service: str
|
||||
status: str
|
||||
version: str
|
||||
|
||||
|
||||
class AdminSystemInfoResponse(BaseModel):
|
||||
service: str
|
||||
app_name: str
|
||||
environment: str
|
||||
version: str
|
||||
api_prefix: str
|
||||
debug: bool
|
||||
@ -0,0 +1,17 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
from admin_app.api.router import api_router
|
||||
from admin_app.core.settings import AdminSettings, get_admin_settings
|
||||
|
||||
|
||||
# Fabrica explicita do runtime administrativo para facilitar testes e futura configuracao.
|
||||
def create_app(settings: AdminSettings | None = None) -> FastAPI:
|
||||
resolved_settings = settings or get_admin_settings()
|
||||
app = FastAPI(
|
||||
title=resolved_settings.admin_app_name,
|
||||
version=resolved_settings.admin_version,
|
||||
debug=resolved_settings.admin_debug,
|
||||
)
|
||||
app.state.admin_settings = resolved_settings
|
||||
app.include_router(api_router, prefix=resolved_settings.admin_api_prefix)
|
||||
return app
|
||||
@ -0,0 +1,48 @@
|
||||
from functools import lru_cache
|
||||
|
||||
from pydantic import field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class AdminSettings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
admin_app_name: str = "Orquestrador Admin"
|
||||
admin_environment: str = "production"
|
||||
admin_debug: bool = False
|
||||
admin_version: str = "0.1.0"
|
||||
admin_api_prefix: str = ""
|
||||
|
||||
# Banco administrativo do runtime interno.
|
||||
admin_db_host: str = "127.0.0.1"
|
||||
admin_db_port: int = 3306
|
||||
admin_db_user: str = "root"
|
||||
admin_db_password: str = ""
|
||||
admin_db_name: str = "orquestrador_admin"
|
||||
admin_db_cloud_sql_connection_name: str | None = None
|
||||
|
||||
@field_validator("admin_debug", mode="before")
|
||||
@classmethod
|
||||
def parse_debug_aliases(cls, value):
|
||||
if isinstance(value, str):
|
||||
normalized = value.strip().lower()
|
||||
if normalized in {"debug", "development", "dev"}:
|
||||
return True
|
||||
if normalized in {"release", "production", "prod"}:
|
||||
return False
|
||||
return value
|
||||
|
||||
@field_validator("admin_environment", "admin_api_prefix", mode="before")
|
||||
@classmethod
|
||||
def normalize_text_settings(cls, value):
|
||||
if isinstance(value, str):
|
||||
return value.strip()
|
||||
return value
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_admin_settings() -> AdminSettings:
|
||||
return AdminSettings()
|
||||
@ -0,0 +1,32 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import declarative_base, sessionmaker
|
||||
|
||||
from admin_app.core.settings import get_admin_settings
|
||||
|
||||
settings = get_admin_settings()
|
||||
admin_cloud_sql = settings.admin_db_cloud_sql_connection_name
|
||||
|
||||
if admin_cloud_sql:
|
||||
ADMIN_DATABASE_URL = (
|
||||
f"mysql+pymysql://{settings.admin_db_user}:{settings.admin_db_password}@/{settings.admin_db_name}"
|
||||
f"?unix_socket=/cloudsql/{admin_cloud_sql}"
|
||||
)
|
||||
else:
|
||||
ADMIN_DATABASE_URL = (
|
||||
f"mysql+pymysql://{settings.admin_db_user}:{settings.admin_db_password}@"
|
||||
f"{settings.admin_db_host}:{settings.admin_db_port}/{settings.admin_db_name}"
|
||||
)
|
||||
|
||||
admin_engine = create_engine(
|
||||
ADMIN_DATABASE_URL,
|
||||
pool_pre_ping=True,
|
||||
connect_args={"connect_timeout": 5},
|
||||
)
|
||||
|
||||
AdminSessionLocal = sessionmaker(
|
||||
autocommit=False,
|
||||
autoflush=False,
|
||||
bind=admin_engine,
|
||||
)
|
||||
|
||||
AdminBase = declarative_base()
|
||||
@ -0,0 +1,3 @@
|
||||
from admin_app.db.models.base import AdminTimestampedModel
|
||||
|
||||
__all__ = ["AdminTimestampedModel"]
|
||||
@ -0,0 +1,17 @@
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from admin_app.db.database import AdminBase
|
||||
|
||||
|
||||
# Base abstrata com timestamps para futuras entidades administrativas.
|
||||
class AdminTimestampedModel(AdminBase):
|
||||
__abstract__ = True
|
||||
|
||||
created_at: Mapped[object] = mapped_column(DateTime, server_default=func.current_timestamp())
|
||||
updated_at: Mapped[object] = mapped_column(
|
||||
DateTime,
|
||||
server_default=func.current_timestamp(),
|
||||
onupdate=func.current_timestamp(),
|
||||
)
|
||||
@ -0,0 +1,3 @@
|
||||
from admin_app.app_factory import create_app
|
||||
|
||||
app = create_app()
|
||||
@ -0,0 +1,3 @@
|
||||
from admin_app.repositories.base_repository import BaseRepository
|
||||
|
||||
__all__ = ["BaseRepository"]
|
||||
@ -0,0 +1,6 @@
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
class BaseRepository:
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
@ -0,0 +1,3 @@
|
||||
from admin_app.services.system_service import SystemService
|
||||
|
||||
__all__ = ["SystemService"]
|
||||
@ -0,0 +1,31 @@
|
||||
from admin_app.core.settings import AdminSettings
|
||||
|
||||
|
||||
class SystemService:
|
||||
def __init__(self, settings: AdminSettings):
|
||||
self.settings = settings
|
||||
|
||||
def build_root_payload(self) -> dict:
|
||||
return {
|
||||
"service": "orquestrador-admin",
|
||||
"status": "ok",
|
||||
"message": "Servico administrativo inicializado.",
|
||||
"environment": self.settings.admin_environment,
|
||||
}
|
||||
|
||||
def build_health_payload(self) -> dict:
|
||||
return {
|
||||
"service": "orquestrador-admin",
|
||||
"status": "ok",
|
||||
"version": self.settings.admin_version,
|
||||
}
|
||||
|
||||
def build_system_info_payload(self) -> dict:
|
||||
return {
|
||||
"service": "orquestrador-admin",
|
||||
"app_name": self.settings.admin_app_name,
|
||||
"environment": self.settings.admin_environment,
|
||||
"version": self.settings.admin_version,
|
||||
"api_prefix": self.settings.admin_api_prefix,
|
||||
"debug": self.settings.admin_debug,
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
# ADR 0001 - Separar usuario de atendimento de conta administrativa interna
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Contexto
|
||||
Hoje o sistema possui um conceito principal de usuario em `app/db/mock_models.py` (`User`).
|
||||
Esse registro representa a identidade operacional do atendimento e nasce a partir de canais externos, como Telegram.
|
||||
Ele serve para vincular conversas, pedidos, locacoes, revisoes e contexto transacional do usuario final.
|
||||
|
||||
Para a frente de auto-incremento de tools, precisaremos de uma area interna com login, permissao, auditoria e publicacao controlada.
|
||||
Misturar essa conta interna com o `User` atual criaria problemas de seguranca, modelagem e isolamento de dominio.
|
||||
|
||||
## Decisao
|
||||
Vamos separar explicitamente dois dominios de identidade:
|
||||
|
||||
1. `AtendimentoUser`
|
||||
- Continua sendo o `User` atual do banco operacional/mock.
|
||||
- Representa clientes e pessoas atendidas por canais externos.
|
||||
- Continua vinculado a conversa, pedido, revisao, locacao e historico operacional.
|
||||
|
||||
2. `StaffAccount`
|
||||
- Sera uma nova entidade para acesso administrativo interno.
|
||||
- Representa funcionarios e administradores da empresa.
|
||||
- Sera usada para login no painel interno, configuracao do sistema, criacao/aprovacao de tools e auditoria.
|
||||
|
||||
## Fronteira entre os dois tipos de conta
|
||||
|
||||
### AtendimentoUser
|
||||
- Banco: operacional/mock (`MockBase`)
|
||||
- Origem: canal externo (`channel`, `external_id`)
|
||||
- Autenticacao: indireta, via canal de atendimento
|
||||
- Responsabilidade: atendimento ao cliente e contexto de negocio
|
||||
- Nao deve receber credenciais de painel interno
|
||||
|
||||
### StaffAccount
|
||||
- Banco: administrativo/tools (`Base`)
|
||||
- Origem: cadastro interno controlado
|
||||
- Autenticacao: login web proprio
|
||||
- Responsabilidade: administracao, configuracao e governanca de tools
|
||||
- Nao deve ser usado para identificar cliente do atendimento
|
||||
|
||||
## Racional para usar o banco administrativo/tools para StaffAccount
|
||||
O projeto ja possui um banco administrativo ligado a `Base`, hoje usado para `tools`.
|
||||
Como a nova frente trata de governanca do sistema e nao de jornada do cliente final, o lugar mais coerente para `StaffAccount` e para os metadados de geracao/publicacao e esse mesmo dominio administrativo.
|
||||
|
||||
Isso reduz acoplamento com o banco operacional e evita misturar seguranca interna com dados de atendimento.
|
||||
|
||||
## Entidades alvo derivadas desta decisao
|
||||
As proximas fases devem introduzir, no banco administrativo, entidades como:
|
||||
|
||||
- `StaffAccount`
|
||||
- `StaffSession` ou estrategia equivalente de token
|
||||
- `ToolDraft`
|
||||
- `ToolGenerationJob`
|
||||
- `ToolValidationRun`
|
||||
- `ToolPublication`
|
||||
- `AuditLog`
|
||||
|
||||
O banco operacional continua com entidades como:
|
||||
|
||||
- `User`
|
||||
- `Order`
|
||||
- `ReviewSchedule`
|
||||
- `RentalContract`
|
||||
- `ConversationTurn`
|
||||
|
||||
## Regras arquiteturais obrigatorias
|
||||
|
||||
1. Nenhuma rota administrativa deve reutilizar `User` do atendimento como identidade autenticada.
|
||||
2. Nenhuma regra de atendimento deve depender de `StaffAccount` para funcionar.
|
||||
3. O pipeline de geracao/publicacao de tools deve operar fora do caminho critico do atendimento.
|
||||
4. Toda ativacao de tool gerada deve ser auditavel e vinculada a um `StaffAccount`.
|
||||
5. O atendimento continua decidindo execucao com base no modelo; o painel administrativo apenas governa cadastro, validacao e publicacao.
|
||||
|
||||
## Papel inicial de permissao
|
||||
A primeira versao deve prever ao menos estes papeis:
|
||||
|
||||
- `admin`: gerencia contas internas, aprova e publica tools, altera configuracoes sensiveis
|
||||
- `staff`: cria drafts, acompanha geracao, revisa resultados e solicita aprovacao
|
||||
- `viewer`: consulta status e auditoria, sem publicar
|
||||
|
||||
## Estrutura tecnica sugerida
|
||||
|
||||
### Banco administrativo (`Base`)
|
||||
- `app/db/models/staff_account.py`
|
||||
- `app/db/models/tool_draft.py`
|
||||
- `app/db/models/tool_generation_job.py`
|
||||
- `app/db/models/audit_log.py`
|
||||
|
||||
### Repositorios
|
||||
- `app/repositories/staff_account_repository.py`
|
||||
- `app/repositories/tool_draft_repository.py`
|
||||
- `app/repositories/tool_generation_job_repository.py`
|
||||
|
||||
### Servicos
|
||||
- `app/services/admin/auth_service.py`
|
||||
- `app/services/admin/tool_draft_service.py`
|
||||
- `app/services/admin/tool_generation_service.py`
|
||||
- `app/services/admin/audit_service.py`
|
||||
|
||||
### API interna
|
||||
- `app/api/routes/admin_auth.py`
|
||||
- `app/api/routes/admin_tools.py`
|
||||
- `app/api/routes/admin_audit.py`
|
||||
|
||||
## Fluxo alvo de alto nivel
|
||||
1. `StaffAccount` faz login no painel interno.
|
||||
2. O usuario interno cria um `ToolDraft` com nome, descricao e parametros.
|
||||
3. Um job isolado gera a implementacao e executa validacoes.
|
||||
4. O resultado fica disponivel para revisao humana.
|
||||
5. Um `admin` aprova e publica.
|
||||
6. A tool publicada passa a integrar o registry ativo sem afetar o dominio de identidade do atendimento.
|
||||
|
||||
## Impacto nas proximas etapas
|
||||
A partir desta decisao, as proximas implementacoes devem seguir esta ordem:
|
||||
|
||||
1. Criar `StaffAccount` e autenticacao administrativa.
|
||||
2. Criar autorizacao por papel.
|
||||
3. Criar entidades de draft/versionamento/validacao.
|
||||
4. Criar pipeline isolado de geracao.
|
||||
5. Criar painel e rotas administrativas.
|
||||
|
||||
## Consequencias
|
||||
### Positivas
|
||||
- Isola seguranca interna do atendimento ao cliente.
|
||||
- Facilita auditoria e governanca.
|
||||
- Evita acoplamento indevido entre canal externo e painel interno.
|
||||
- Deixa clara a separacao entre operacao e administracao do sistema.
|
||||
|
||||
### Custos
|
||||
- Introduz novo conjunto de entidades e rotas.
|
||||
- Exige autenticacao e autorizacao dedicadas.
|
||||
- Aumenta a complexidade de bootstrap e persistencia do dominio administrativo.
|
||||
|
||||
## Fora do escopo desta ADR
|
||||
- Escolha definitiva do modelo para geracao de codigo.
|
||||
- Implementacao do frontend administrativo.
|
||||
- Definicao detalhada do sandbox de execucao das tools geradas.
|
||||
@ -0,0 +1,246 @@
|
||||
# ADR 0002 - Separar o runtime de produto do serviço administrativo
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Relacao com ADRs anteriores
|
||||
Esta decisao complementa a ADR 0001.
|
||||
A ADR 0001 separa identidade de atendimento e identidade administrativa.
|
||||
A ADR 0002 amplia essa separacao para o nivel de servicos e runtime.
|
||||
|
||||
## Contexto
|
||||
O sistema atual nasceu como um unico runtime orientado ao atendimento.
|
||||
Hoje ele concentra no mesmo projeto e no mesmo ciclo operacional:
|
||||
|
||||
- atendimento conversacional
|
||||
- orquestracao de tools
|
||||
- integracao com Telegram
|
||||
- estado conversacional
|
||||
- regras operacionais de vendas, revisao e locacao
|
||||
- administracao futura do sistema
|
||||
- geracao futura de novas tools
|
||||
- relatorios e configuracoes internas
|
||||
|
||||
A nova frente de evolucao exige um modulo administrativo mais robusto, com:
|
||||
|
||||
- login interno de funcionarios e administradores
|
||||
- configuracao do sistema
|
||||
- relatorios de vendas, arrecadacao e operacao
|
||||
- cadastro, geracao, validacao e publicacao de novas tools
|
||||
- auditoria de alteracoes e aprovacoes
|
||||
|
||||
Se tudo isso continuar no mesmo runtime do atendimento, teremos aumento de risco em quatro eixos:
|
||||
|
||||
1. Performance
|
||||
- jobs pesados de geracao e validacao podem concorrer com o atendimento.
|
||||
|
||||
2. Seguranca
|
||||
- login administrativo, aprovacoes e publicacao de codigo ficariam expostos no mesmo servico do produto.
|
||||
|
||||
3. Operacao
|
||||
- qualquer falha ou deploy administrativo pode impactar diretamente o atendimento.
|
||||
|
||||
4. Evolucao
|
||||
- o painel e a automacao interna possuem cadencia, dependencias e necessidades diferentes do runtime conversacional.
|
||||
|
||||
## Decisao
|
||||
Vamos separar a solucao em dois servicos distintos, inicialmente no mesmo repositorio.
|
||||
|
||||
### 1. Servico de produto
|
||||
Nome conceitual: `orquestrador-product`
|
||||
|
||||
Responsabilidades:
|
||||
- atendimento conversacional
|
||||
- integracao com Telegram e futuros canais de atendimento
|
||||
- orquestracao de tools em tempo de execucao
|
||||
- fluxos operacionais de vendas, revisao e locacao
|
||||
- leitura apenas de tools publicadas e configuracoes ativas
|
||||
|
||||
Esse servico continua sendo o runtime critico do produto.
|
||||
Ele deve permanecer leve, previsivel e protegido de cargas administrativas.
|
||||
|
||||
### 2. Servico administrativo
|
||||
Nome conceitual: `orquestrador-admin`
|
||||
|
||||
Responsabilidades:
|
||||
- autenticacao e autorizacao interna
|
||||
- painel administrativo
|
||||
- configuracoes do sistema
|
||||
- relatorios de vendas, arrecadacao e operacao
|
||||
- cadastro de drafts de tools
|
||||
- geracao de implementacoes
|
||||
- validacao automatica
|
||||
- aprovacao humana
|
||||
- publicacao controlada
|
||||
- auditoria de mudancas
|
||||
|
||||
Esse servico nao participa do hot path do atendimento.
|
||||
Ele governa o sistema, mas nao executa atendimento em tempo real.
|
||||
|
||||
## Decisao sobre repositorio
|
||||
Neste primeiro momento, os dois servicos permanecem no mesmo repositorio.
|
||||
|
||||
Motivos:
|
||||
- menor custo operacional inicial
|
||||
- versionamento conjunto das fronteiras compartilhadas
|
||||
- mais facilidade para evoluir contratos internos
|
||||
- menos atrito no inicio da iniciativa
|
||||
|
||||
No futuro, se a operacao justificar, eles podem ser separados em repositorios diferentes.
|
||||
Essa separacao nao e obrigatoria agora.
|
||||
|
||||
## Fronteira entre os servicos
|
||||
|
||||
### O que pertence ao servico de produto
|
||||
- LLM do atendimento
|
||||
- orquestrador
|
||||
- registry de tools ativas
|
||||
- execucao de tools aprovadas
|
||||
- fluxo de conversa
|
||||
- integracoes com canais externos de atendimento
|
||||
- persistencia operacional do usuario final
|
||||
|
||||
### O que pertence ao servico administrativo
|
||||
- `StaffAccount`
|
||||
- permissao por papel
|
||||
- painel interno
|
||||
- configuracao administrativa
|
||||
- relatorios e dashboards
|
||||
- pipeline de geracao de tools
|
||||
- versionamento de tools
|
||||
- aprovacao/publicacao
|
||||
- trilha de auditoria
|
||||
|
||||
## Principio de integracao entre os servicos
|
||||
A integracao entre `product` e `admin` deve ser preferencialmente assincrona ou orientada a publicacao de estado.
|
||||
O runtime de produto nao deve depender de uma chamada online ao servico administrativo para responder ao cliente.
|
||||
|
||||
Regra obrigatoria:
|
||||
- o atendimento deve continuar funcionando mesmo se o servico administrativo estiver indisponivel.
|
||||
|
||||
## Modelo de acoplamento permitido
|
||||
|
||||
### Permitido
|
||||
- leitura de tools publicadas
|
||||
- leitura de configuracoes marcadas como ativas
|
||||
- leitura de versoes aprovadas
|
||||
- sincronizacao de metadados publicados
|
||||
- consumo de eventos ou snapshots administrativos
|
||||
|
||||
### Nao permitido no hot path do atendimento
|
||||
- gerar tool sob demanda durante o atendimento
|
||||
- validar codigo em tempo real no runtime do produto
|
||||
- depender de login administrativo para executar atendimento
|
||||
- bloquear resposta ao usuario aguardando operacao do servico administrativo
|
||||
|
||||
## Estrategia de dados
|
||||
|
||||
### Banco do servico de produto
|
||||
Responsavel por:
|
||||
- usuarios de atendimento
|
||||
- pedidos
|
||||
- revisoes
|
||||
- locacoes
|
||||
- conversas
|
||||
- estado operacional
|
||||
- referencias de tools ativas necessarias ao runtime
|
||||
|
||||
### Banco do servico administrativo
|
||||
Responsavel por:
|
||||
- contas internas (`StaffAccount`)
|
||||
- sessoes e credenciais administrativas
|
||||
- configuracoes do sistema
|
||||
- relatorios consolidados
|
||||
- drafts de tools
|
||||
- jobs de geracao
|
||||
- execucoes de validacao
|
||||
- publicacoes
|
||||
- auditoria
|
||||
|
||||
## Conexao entre dados dos dois servicos
|
||||
Existem duas estrategias validas para as proximas fases:
|
||||
|
||||
1. Banco administrativo consulta dados consolidados do produto por replicacao, ETL ou views dedicadas para relatorios.
|
||||
2. Banco administrativo recebe snapshots/eventos do produto para alimentar relatorios e auditoria operacional.
|
||||
|
||||
Decisao inicial recomendada:
|
||||
- manter o produto como fonte operacional
|
||||
- usar o servico administrativo para leitura consolidada, auditoria e governanca
|
||||
- evitar escrita administrativa direta nas tabelas operacionais do atendimento, salvo casos explicitamente versionados e controlados
|
||||
|
||||
## Estrutura tecnica sugerida no monorepo
|
||||
|
||||
### Produto
|
||||
- `app/` permanece como nucleo do runtime de atendimento
|
||||
- entrypoints de atendimento e integracoes continuam aqui
|
||||
|
||||
### Administrativo
|
||||
Criar uma nova arvore dedicada, por exemplo:
|
||||
- `admin_app/`
|
||||
- `api/`
|
||||
- `services/`
|
||||
- `repositories/`
|
||||
- `models/`
|
||||
- `main.py`
|
||||
|
||||
Ou, se quisermos maximizar reaproveitamento de convencao atual:
|
||||
- `app_admin/`
|
||||
|
||||
A escolha do nome pode ser definida na fase de scaffold.
|
||||
O importante nesta ADR e a separacao de runtime e responsabilidade.
|
||||
|
||||
## Deploy esperado
|
||||
No medio prazo, o deploy deve prever dois servicos distintos:
|
||||
|
||||
- `orquestrador-product`
|
||||
- `orquestrador-admin`
|
||||
|
||||
Cada um com:
|
||||
- variaveis de ambiente proprias
|
||||
- processo/servico dedicado
|
||||
- observabilidade propria
|
||||
- escala independente
|
||||
|
||||
## Implicacoes para modelo de IA
|
||||
A geracao de tools e automacao administrativa podem usar um modelo diferente do atendimento.
|
||||
Essa escolha fica facilitada pela separacao de servicos, pois:
|
||||
- evita disputa de recurso e custo com o chat principal
|
||||
- permite tuning de latencia e qualidade por caso de uso
|
||||
- reduz risco de sobrecarregar o atendimento
|
||||
|
||||
## Regras obrigatorias decorrentes desta ADR
|
||||
1. O runtime de produto nao executa pipeline de geracao de tools.
|
||||
2. O servico administrativo nao participa do hot path de resposta ao cliente.
|
||||
3. Toda tool nova nasce no servico administrativo e so chega ao produto depois de publicada.
|
||||
4. Relatorios e configuracoes internas pertencem ao servico administrativo.
|
||||
5. O produto so consome estado publicado e aprovado.
|
||||
6. Deploys do servico administrativo nao devem exigir redeploy simultaneo do produto, salvo mudanca de contrato compartilhado.
|
||||
|
||||
## Sequencia recomendada de implementacao
|
||||
1. Formalizar esta arquitetura em documentacao.
|
||||
2. Criar fundacao do servico administrativo no monorepo.
|
||||
3. Implementar `StaffAccount`, auth e papeis.
|
||||
4. Criar area de configuracao e relatorios basicos.
|
||||
5. Criar entidades de draft/publicacao de tools.
|
||||
6. Implementar pipeline isolado de geracao e validacao.
|
||||
7. Integrar publicacao de tools com o runtime de produto.
|
||||
|
||||
## Consequencias
|
||||
### Positivas
|
||||
- isola o atendimento das cargas administrativas
|
||||
- melhora seguranca
|
||||
- facilita escalabilidade independente
|
||||
- prepara o sistema para governanca e auditoria reais
|
||||
- reduz risco operacional no produto
|
||||
|
||||
### Custos
|
||||
- aumenta a complexidade arquitetural
|
||||
- exige contratos claros entre servicos
|
||||
- traz mais trabalho de deploy, observabilidade e configuracao
|
||||
- exige estrategia de compartilhamento de dados para relatorios
|
||||
|
||||
## Fora do escopo desta ADR
|
||||
- implementar o scaffold real do segundo servico
|
||||
- escolher o modelo definitivo de geracao
|
||||
- definir o formato final de sincronizacao de dados analiticos
|
||||
- definir a UI final do painel administrativo
|
||||
@ -0,0 +1,67 @@
|
||||
import unittest
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from admin_app.app_factory import create_app
|
||||
from admin_app.core.settings import AdminSettings
|
||||
|
||||
|
||||
class AdminAppBootstrapTests(unittest.TestCase):
|
||||
def test_admin_app_root_endpoint(self):
|
||||
app = create_app(AdminSettings(admin_environment="staging"))
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response.json(),
|
||||
{
|
||||
"service": "orquestrador-admin",
|
||||
"status": "ok",
|
||||
"message": "Servico administrativo inicializado.",
|
||||
"environment": "staging",
|
||||
},
|
||||
)
|
||||
|
||||
def test_admin_app_health_endpoint(self):
|
||||
app = create_app(AdminSettings(admin_version="1.2.3"))
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/health")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response.json(),
|
||||
{"service": "orquestrador-admin", "status": "ok", "version": "1.2.3"},
|
||||
)
|
||||
|
||||
def test_admin_app_system_info_endpoint(self):
|
||||
settings = AdminSettings(
|
||||
admin_app_name="Admin Interno",
|
||||
admin_environment="development",
|
||||
admin_version="0.9.0",
|
||||
admin_api_prefix="/admin",
|
||||
admin_debug=True,
|
||||
)
|
||||
app = create_app(settings)
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/admin/system/info")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response.json(),
|
||||
{
|
||||
"service": "orquestrador-admin",
|
||||
"app_name": "Admin Interno",
|
||||
"environment": "development",
|
||||
"version": "0.9.0",
|
||||
"api_prefix": "/admin",
|
||||
"debug": True,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue