IDR COMANDAS 0.3.0 — CENTRAL ONLINE

ENTREGA E SITUAÇÃO
Este diretório contém o serviço real de catálogo, licenciamento e painel do
proprietário. Não há domínio configurado, servidor publicado ou mensalidades
integradas a banco nesta entrega.
O ZIP completo inclui Catalogo\catalogue.sqlite3, separado dos dados privados
das lojas, com 2.537.446 códigos e descrições, sem preços de venda da padaria.
Os testes funcionais usam lojas isoladas. O catálogo real também foi consultado
pela API HTTP local: 100 consultas exatas, percentil 95 de aproximadamente
78,2 ms em localhost. Isso não homologa hospedagem, internet nem concorrência
de múltiplos clientes. A capacidade do servidor escolhido precisa ser medida.

HOSPEDAGEM
Python 3.11 ou superior, SQLite local em disco persistente e a biblioteca
cryptography são necessários. Recomenda-se VPS com proxy HTTPS (Nginx/Caddy),
backup e controle operacional. Esta aplicação Python não é um pacote PHP para
hospedagem compartilhada HostGator. Não basta enviar o executável Windows ao site.
Os exemplos de domínio são marcadores: substitua-os pelo domínio contratado.

EXECUTAR LOCALMENTE
1. No diretório raiz do projeto, instale:
   python -m pip install -r central/requirements.txt
2. Inicialize uma pasta privada:
   python -m central.server --data work/central-data init --login administrador
   Informe uma senha própria no prompt. Não existe senha padrão.
3. Inicie:
   python -m central.server --data work/central-data serve
4. Abra http://127.0.0.1:8765. Entre como Administração IDR.
5. Cadastre a loja, o acesso do proprietário e a data paga. Copie o identificador,
   token de ativação (exibido uma única vez) e chave PÚBLICA para o PDV.
6. No PDV, informe URL, loja, token, chave pública e valide. A primeira validação
   vincula a instalação. O identificador local é estável e deve ser preservado.

A chave PRIVADA license-private.pem fica somente no servidor. Não envie a chave
privada ao cliente, não a inclua no executável e não a publique no domínio.
No Linux, a pasta e a chave recebem permissões restritas. No Windows de teste,
use uma pasta acessível somente à conta administradora. Faça backup protegido da
base e da chave. Perder ou trocar essa chave invalida as assinaturas existentes.

VPS / SERVIÇO
- Crie usuário de serviço sem privilégios, diretório /opt/idr-comandas e ambiente
  virtual. Instale os requisitos e copie o projeto preservando central/assets.
- Inicialize /var/lib/idr-central como o usuário de serviço, nunca no document root.
- Adapte IDR-Central.service.example e nginx.conf.example.
- Sirva o Python em 127.0.0.1:8765. Exponha somente o proxy HTTPS com certificado
  válido. --public-origin deve ser exatamente o endereço público HTTPS.
- Os cookies usam Secure em produção, HttpOnly, SameSite=Strict e CSRF por sessão.
- Há limites de corpo, tempo, lote e tentativas de login. Aplique também limites
  no proxy. O servidor HTTP local não deve ficar exposto diretamente à internet.
- Configure backup consistente da base com SQLite backup API ou parada controlada;
  não copie só central.sqlite3 enquanto WAL estiver ativo e ignore os demais dados.
- Execute com apenas uma instância do serviço por diretório SQLite. Não use NFS.

DOCKER (ALTERNATIVA)
A partir da raiz:
docker build -f central/Dockerfile -t idr-central:0.3 .
docker volume create idr-central-data
docker run --rm -it -v idr-central-data:/data idr-central:0.3 init --login administrador
docker run -d --name idr-central --restart unless-stopped -p 127.0.0.1:8765:8765 \
  -v idr-central-data:/data idr-central:0.3 serve --host 0.0.0.0 --port 8765 \
  --public-origin https://central.SEUDOMINIO.com.br
O exemplo usa diretório persistente; configure o proxy e seus certificados.
Não foi realizado build de imagem Docker nem deploy nesta entrega.

LICENCIAMENTO
- A central assina licenças com Ed25519. O desktop só possui a chave pública.
- Validade = menor prazo entre limite offline (1 a 72 horas) e fim da tolerância
  financeira. Pago até e tolerância usam o fim do dia em Brasília (UTC-3).
- Ao suspender manualmente, a próxima validação recebe uma licença assinada
  suspensa, sem renovação de tempo offline. O PDV precisa guardar essa resposta.
- Sem internet, o prazo já assinado continua até expirar. Não há bloqueio remoto
  instantâneo offline. Alterações de relógio são detectadas dentro dos limites
  do histórico de horário confiável; não há proteção absoluta contra o dono do PC.
- Para liberar, atualize situação e pago até. A baixa financeira começa manual.
- Troca de computador: liberar vínculo e, se necessário, trocar o token. Licenças
  emitidas anteriormente continuam até seu vencimento; não podem ser revogadas
  remotamente enquanto a instalação antiga estiver desconectada.
- Painel do proprietário e envio de eventos já gravados permanecem disponíveis
  para não esconder dados nem impedir reconciliação durante uma suspensão.

CATÁLOGO
CSV UTF-8 (também permite --encoding), coluna de código como texto. Não converta
EAN para número, notação científica ou planilha que remova zeros à esquerda.
python -m central.server --data /var/lib/idr-central import-catalogue /caminho/base.csv \
  --barcode-column CODIGO --description-column DESCRICAO --delimiter ";"
Leitura por streaming, transações de 1.000 linhas, chave primária no código.
Códigos existentes com outra descrição são registrados em catalogue_conflicts;
a descrição anterior é preservada para revisão, mas o código fica com conflicted=1
e não é devolvido no preenchimento automático. Consulte os conflitos na central. A revisão e
correção da base original precedem uma nova importação; não há escolha automática.
Linhas inválidas contam no resultado. Os lotes anteriores ficam gravados se uma
importação for interrompida. Repetir não duplica os produtos.

CATÁLOGO EM ARQUIVO SEPARADO
Para usar a base incluída no ZIP completo, informe o caminho real do arquivo
Catalogo\catalogue.sqlite3 em --catalogue-db. No desktop, a mesma base pode ser
selecionada em Ajustes > Catálogo local, sem necessidade de servidor online.
Também é possível usar --catalogue-db /dados/catalogue.sqlite3 antes do comando
serve ou import-catalogue. Nesse caso o catálogo compartilhado não fica misturado
à base privada de clientes, licenças e relatórios. O arquivo deve conter as tabelas
catalogue(barcode TEXT PRIMARY KEY,description TEXT NOT NULL,updated_at TEXT NOT NULL,
conflicted INTEGER NOT NULL DEFAULT 0)
e catalogue_conflicts(id INTEGER PRIMARY KEY,barcode TEXT NOT NULL,existing TEXT NOT NULL,
incoming TEXT NOT NULL,at TEXT NOT NULL). Nunca exponha o arquivo SQLite por URL.

API / SINCRONIZAÇÃO
Authorization: Bearer <token da loja>, sempre por HTTPS em rede.
POST /api/v1/license: {store_id, installation_id}
GET /api/v1/catalogue?store_id=...&installation_id=...&barcode=...
POST /api/v1/sync: {store_id, installation_id, events:[], snapshot:{generated_at,...}}
- Eventos têm event_id (ou id) textual único e conteúdo imutável, até 500 por lote.
- Reenvio idêntico retorna o mesmo acknowledgement; conflito de conteúdo aborta
  a transação inteira. A chave de unicidade inclui a loja autenticada.
- Resumo com generated_at anterior não substitui resumo mais recente.
- O painel sempre mostra hora do resumo e hora de recebimento UTC. Dados offline
  não são apresentados como atualização em tempo real.
- Nenhuma senha, token ou chave privada deve fazer parte dos eventos/snapshots.
- A sincronização é unidirecional para acompanhamento de um terminal por loja;
  não oferece múltiplos caixas concorrentes nem substitui cópia de segurança.

PIX / IMPRESSÃO
O QR estático usa BR Code e CRC16 conforme o manual do Banco Central:
https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf
O recebimento exige confirmação manual: mostrar QR não prova pagamento.
A impressão usa Qt/driver padrão Windows. Sucesso significa aceitação pela fila
do sistema operacional, não leitura de sensor de papel da impressora.
Valide bobina 58/80 mm e margens na impressora física antes da homologação.

TESTES
Com dependências do aplicativo instaladas e raiz/src no PYTHONPATH:
python -m unittest discover -s tests -p test_hybrid.py -v
python -m unittest discover -s tests -p test_pix.py -v
Os testes cobrem assinatura/tamper, isolamento, suspensão, relógio, duplicidade,
conflitos, catálogo, sessão/CSRF, vetor oficial CRC, QR PNG e impressão PDF.

PUBLICAR ATUALIZAÇÕES DO PDV — 0.6.0

O PDV 0.6.0 tem atualizador incorporado. A primeira instalação vem do ZIP completo.
1. Compile e teste a versão nova, incrementando src/idr_comandas/__init__.py.
2. Gere o pacote somente do aplicativo:
   python scripts/create_update.py --app Aplicativo --output IDR-Flow-X.Y.Z-Atualizacao.zip
3. Na Administração IDR, abra Atualizações, informe a mesma versão do pacote,
   descreva as novidades e envie o ZIP Atualizacao. Não envie o ZIP completo.
4. A central verifica o pacote e assina o manifesto com sua chave privada.
   A publicação exige versão superior à última; o arquivo publicado é imutável.
5. PDVs autenticados consultam a central a cada minuto. O cliente escolhe Atualizar
   com o caixa fechado. O catálogo e dados comerciais não são baixados novamente.
6. Confira a atualização em uma instalação de homologação antes de disponibilizar
   aos demais clientes. Esta versão não oferece grupos de implantação ou rollback
   remoto; para uma correção posterior, publique uma versão superior.

APIs autenticadas por token da loja e vínculo da instalação:
POST /api/v1/update, com store_id e installation_id.
GET /api/v1/update/package?store_id=...&installation_id=...&file=...
O manifesto usa assinatura Ed25519, SHA-256, tamanho e versão; o cliente recusa
pacotes alterados e caminhos inválidos. A chave privada permanece na central.
O administrador usa sessão/CSRF/origem verificada para publicar.

Configure o proxy para upload de até 250.000.000 bytes em /admin/releases/upload,
com limite de tempo suficiente. O nginx.conf.example inclui a rota específica.
Mantenha espaço para os pacotes anteriores e backup da pasta releases e da chave.
Não apague pacotes ainda em download. O diretório privado não pode ser servido
diretamente por URL: os downloads passam pela autenticação do serviço.

O instalador preserva programa anterior e backup, valida a nova inicialização e
tenta recuperar ambos em falha. Os registros result.json ficam nas pastas
.idr-flow-update-* ao lado do Aplicativo. A recuperação não substitui backups
externos nem a homologação de migrações em cada nova versão.

Sem domínio e serviço configurados, o PDV mostra Central não configurada.
O indicador verde é contato recente confirmado; falhas mostram Central offline.
Os testes desta entrega são locais; a implantação HostGator ainda está pendente.
