Decisão de 2026-09-04, revendo a de 2026-09-03 (sem de-para): o .md continua mandando, e a tabela contrato/linhas-os.yaml (OS Mãe × linha × item) só entra quando o entregável não declara `linha_os`. Linha declarada vai como está e não é conferida contra a tabela; existência/item/status seguem sendo do banco. - caminhos.LINHAS_OS; regras_sd: Canonico(itens, linhas_os), carregar_linhas_os (arquivo ausente = fallback desligado), preparar_linhas_os (valida: formato, linha repetida, dois `padrao`, `padrao` não booleano) e linha_da_tabela. - exporta_sd: ausente → padrão do item; 2+ candidatas sem padrão → pendência nomeando-as; item fora da tabela → pendência. CLI informa quantas linhas vieram da tabela. - app: sessao.adotar_linhas_da_tabela grava a linha no frontmatter da sessão com comentário de origem, para o Salvar SD.md deixar a SD autodeclarada; a tela marca `tabela` e mostra a data da tabela. - testes: SD18, SD27, SD31–36 passam a exportar de saída; SD10 só PO+objetivo; casos sintéticos para tabela ausente, ambígua, sem o item e malformada. - deploy: linhas-os.yaml vive em clientes/ (gitignored) — vai por scp ao volume. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
53 lines
2.5 KiB
YAML
53 lines
2.5 KiB
YAML
# Deploy em VPS pelo painel Coolify (recurso do tipo "Docker Compose").
|
|
#
|
|
# ANTES do primeiro deploy, ponha os dados do cliente em um caminho FIXO do
|
|
# host, FORA da pasta que o Coolify clona — ele re-clona a cada deploy, e
|
|
# clientes/ está no .gitignore, então o clone nunca traz esses dados:
|
|
#
|
|
# scp -r clientes/ usuario@vps:/dados/exporta-sd/clientes
|
|
#
|
|
# Não precisa de chown manual: o entrypoint.sh da imagem roda como root no
|
|
# início do container e ajusta o dono do volume para o usuário `sd` antes de
|
|
# derrubar privilégio e subir o gunicorn — ver entrypoint.sh e o ENTRYPOINT
|
|
# no Dockerfile. (Uma reconsequência: cada `scp` novo devolve os arquivos ao
|
|
# usuário do ssh no host; some sozinho no próximo restart do container.)
|
|
# Depois, no Coolify → Environment Variables, aponte o volume para lá:
|
|
#
|
|
# CLIENTES_DIR=/dados/exporta-sd/clientes
|
|
# DERIVADOS_DIR=/dados/exporta-sd/_derivados # só se usar a linha de comando
|
|
#
|
|
# Sem essas variáveis, o padrão ./clientes cai dentro da pasta do clone, o
|
|
# compose cria o diretório VAZIO sem avisar e o primeiro upload morre com
|
|
# "Arquivo canônico ausente".
|
|
#
|
|
# Resto do painel: porta exposta 5000, réplicas 1 (ver o comentário de -w 1 no
|
|
# Dockerfile), e o domínio o Coolify publica via Traefik.
|
|
|
|
services:
|
|
exporta-sd:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
# Sem `ports:` de propósito: no Coolify o Traefik alcança o container pela
|
|
# rede interna. `expose` publica a porta só para dentro dessa rede.
|
|
# Para rodar fora do Coolify, troque por: ports: ["5000:5000"].
|
|
expose:
|
|
- "5000"
|
|
environment:
|
|
PORT: "5000"
|
|
volumes:
|
|
# OBRIGATÓRIO. O app lê clientes/ses-mg/contrato/itens.yaml a cada
|
|
# análise (e contrato/linhas-os.yaml, se existir, como fallback da linha
|
|
# de OS) e grava SD.md em clientes/ses-mg/projetos/. O caminho no
|
|
# container é fixo: caminhos.py resolve clientes/ a partir da raiz do
|
|
# código, que é o WORKDIR /app. Sem esta montagem, a tela inicial abre
|
|
# e o primeiro upload falha com "Arquivo canônico ausente".
|
|
- ${CLIENTES_DIR:-./clientes}:/app/clientes
|
|
# Saída da linha de comando (exporta_sd.py --dir _derivados/export).
|
|
# A aplicação web entrega o JSON pelo download, não por aqui.
|
|
- ${DERIVADOS_DIR:-./_derivados}:/app/_derivados
|
|
restart: unless-stopped
|
|
# Uma SD por vez, em memória de processo: reiniciar descarta a sessão
|
|
# aberta (o SD.md de origem no volume fica intacto).
|
|
stop_grace_period: 10s
|