﻿# Arquitetura técnica — REP-P e PTRP (Fase 3)

**Sistema:** Registro Pro (`ponto-saas`)  
**Data:** 29/07/2026  
**Base:** `docs/auditoria-conformidade-rep-p.md`  
**Escopo desta fase:** projeto técnico mínimo — **sem implementação de código**.

> Este documento define o desenho seguro para adequação à Portaria MTP 671/2021. Não declara conformidade jurídica.

---

## 1. Princípios de desenho

1. **Não destruir o operacional atual** — app, facial Control-iD, espelho e ajuste RH continuam funcionando.
2. **Camada paralela** — registros oficiais REP-P em tabelas novas imutáveis; `time_punches` permanece o motor operacional/PTRP de curto prazo.
3. **Feature flag** — nada oficial é emitido sem `rep_p_enabled` + INPI + certificado válidos.
4. **Sem NSR retroativo automático** — históricos sem NSR ficam inventariados; cutover a partir de data D.
5. **PTRP nunca gera AFD** — AFD só lê store REP-P; AEJ/espelho leem originais + tratamentos.
6. **Assinaturas de ponto ≠ holerite** — `BackendPdfDigitalSigner` (HMAC/RSA solto) **não** serve como PAdES/CAdES; novos módulos dedicados.
7. **Estabelecimento para NSR** = CNPJ/CPF do empregador em `tenant_companies` (não o condomínio). Condomínio = local de prestação / evidência.

---

## 2. Separação lógica (mesmo repositório)

```
┌─────────────────────────────────────────────────────────────────┐
│                        Registro Pro (monólito)                   │
├──────────────────────────────┬──────────────────────────────────┤
│  Módulo REP-P                │  Módulo PTRP                      │
│  (desktop/src/RepP/*)        │  (desktop/src/Ptrp/* + Point/*)   │
├──────────────────────────────┼──────────────────────────────────┤
│ • Captura original           │ • Espelho / cálculos              │
│ • NSR atômico                │ • Tratamentos (append-only)       │
│ • Hash SHA-256 encadeado     │ • Inclusão / desconsideração      │
│ • Comprovante + PAdES        │ • Pré-assinalação (config)        │
│ • AFD + CAdES (.p7s)         │ • AEJ + CAdES (.p7s)              │
│ • Eventos sensíveis          │ • Banco de horas / ausências      │
│ • Store imutável             │ • Nunca UPDATE no store REP-P     │
└──────────────────────────────┴──────────────────────────────────┘
                │ dual-write (flag) │
                ▼                   ▼
     rep_p_marks (imutável)    time_punches (operacional)
                │                   │
                └─────────┬─────────┘
                          ▼
              ptrp_treatments → Espelho / AEJ
```

**Não é obrigatório** separar em dois repositórios Git. A separação exigida é **lógica, rastreável e auditável**.

---

## 3. Fluxo de batida (alvo)

### 3.1 Online (app / web / facial)

1. Validar identidade, tenant, empregado, estabelecimento (`employees.tenant_company_id` → `tenant_companies`).
2. Capturar `marked_at` (hora da marcação) e `recorded_at` (hora do servidor).
3. Mapear coletor: `01` app, `02` navegador, `03` desktop, `04` dispositivo (Control-iD), `05` outro.
4. Se flag REP-P ativa **e** estabelecimento elegível:
   - Transação: `SELECT … FOR UPDATE` em `rep_p_nsr_counters` → NSR+1.
   - Inserir `rep_p_marks` (imutável) com hash encadeado.
   - Gerar comprovante (assíncrono ou síncrono curto) + PAdES se certificado ok.
5. **Sempre** (compatibilidade): INSERT em `time_punches` como hoje (event_code, GPS, foto, canal).
6. Vincular `time_punches.rep_p_mark_id` (nullable) quando houver original oficial.

### 3.2 Off-line (fase posterior do produto)

- Fila local no app com UUID; sync idempotente; NSR/hash **somente no servidor** na consolidação.
- Não implementar na primeira entrega se o app ainda não tiver fila; documentar como backlog.

### 3.3 Tentativa bloqueada (tolerância / GPS / método)

- **Hoje:** rejeição sem registro oficial (`PunchToleranceValidator`).
- **Projeto:** tabela `rep_p_punch_attempts` (imutável) com motivo; feature flag jurídica:
  - `block` (comportamento atual) **ou**
  - `allow_and_flag` (registra original + alerta RH).
- **Não remover bloqueios na Fase 4 sem decisão explícita** — só infraestrutura + flag `pending_legal_review`.

---

## 4. Modelo de dados proposto (migrations novas)

Prefixo sugerido: `desktop/database/50_rep_p_*.sql` … `59_ptrp_*.sql`.  
Reversíveis via scripts `*_down.sql` ou comentários de rollback. **Não dropar** tabelas/colunas existentes.

### 4.1 Configuração

| Tabela | Função |
|--------|--------|
| `rep_p_program_config` | Número INPI (só dígitos), versão software, razão social desenvolvedor, histórico via audit |
| `rep_p_establishment_settings` | Por `tenant_company_id`: enabled, timezone, cutover_at, collector defaults |
| `rep_p_certificates` | Metadados (fingerprint, validade, ambiente, purpose=`REP_P`\|`PTRP`); path criptografado fora do webroot — **nunca** chave no Git |

### 4.2 REP-P

| Tabela | Função |
|--------|--------|
| `rep_p_nsr_counters` | `(establishment_key, last_nsr)` — UNIQUE; lock de linha |
| `rep_p_marks` | Marcação original tipo 7: NSR, CPF, marked_at, recorded_at, collector_id, online_offline, sha256, prev_sha256, tenant_id, company_id, employee_id, local_uuid, source_punch_id opcional |
| `rep_p_events` | Eventos sensíveis (indisponibilidade etc.) com NSR próprio na mesma sequência do estabelecimento |
| `rep_p_punch_attempts` | Tentativas rejeitadas / sync fail |
| `rep_p_receipts` | Comprovantes gerados (path PDF, status assinatura, emitido_em) |
| `rep_p_exports` | Log de geração AFD (período, hash arquivo, usuário, path) |

**Constraints obrigatórias:**

- `UNIQUE (establishment_id, nsr)`
- Sem `UPDATE` de campos oficiais em `rep_p_marks` (app layer + trigger opcional `BEFORE UPDATE` que sinaliza erro)
- Sem `DELETE` físico de marks (proibido na API)

**Chave de estabelecimento:** `tenant_companies.id` com CNPJ/CPF normalizado snapshotado na linha do mark (para AFD mesmo se cadastro mudar depois).

### 4.3 PTRP

| Tabela | Função |
|--------|--------|
| `ptrp_treatments` | Inclusão, desconsideração, pré-assinalação, justificativa — **nunca** apaga `rep_p_marks` |
| `ptrp_pre_assinalacao_config` | Por empresa/empregado; default off |
| `ptrp_exports` | Log AEJ |
| `ptrp_espelho_snapshots` (opcional) | Cache de coerência AEJ×espelho |

Campos mínimos de tratamento: id, tenant, company, employee, tipo, motivo, justificativa, user_id, cpf_responsável, solicitado_em, aprovado_em, status, evidência, valor_anterior, valor_tratado, ip, device, `rep_p_mark_id` nullable, `time_punch_id` nullable.

### 4.4 Auditoria

| Tabela | Função |
|--------|--------|
| `compliance_audit_log` | Append-only: ação, entidade, ids, before/after JSON (sem segredos), IP, user, resultado |

### 4.5 Alteração mínima em tabelas existentes

```sql
-- time_punches: vínculo opcional (não muda comportamento se NULL)
ALTER TABLE time_punches
  ADD COLUMN rep_p_mark_id BIGINT UNSIGNED NULL,
  ADD KEY idx_tp_rep_p_mark (rep_p_mark_id);
-- FK opcional após criar rep_p_marks
```

**Proibido na Fase 4:** DROP de colunas; DELETE em massa; renumerar IDs; backfill NSR.

---

## 5. Módulos PHP (arquivos a criar na Fase 4)

```
desktop/src/RepP/
  NsrAllocator.php          # transação + FOR UPDATE
  MarkHasher.php            # SHA-256 leiaute oficial
  MarkRecorder.php          # grava rep_p_marks
  CollectorMapper.php       # canal → 01..05
  AfdBuilder.php
  AfdValidator.php
  AfdCrc16.php              # KERMIT; teste 123456789 → 2189
  ReceiptBuilder.php
  PadesSigner.php           # novo; não reutilizar HMAC
  CadesSigner.php           # .p7s destacado
  ChainAuditor.php
  ComplianceStatus.php

desktop/src/Ptrp/
  TreatmentService.php      # append-only
  AejBuilder.php
  AejValidator.php
  EspelhoLegalView.php      # legendas + coerência (wrapper EspelhoPontoService)
  PreAssinalacaoService.php

desktop/src/Compliance/
  InpiConfig.php
  CertificateVault.php      # path + env senha; alerta vencimento
  AuditLogger.php
  TechnicalAttestation.php  # Anexo VII (gera PDF p/ assinatura PF)
  ValidatorCli.php

desktop/bin/
  validar_conformidade_rep_p.php
```

**Pontos de integração (hooks, sem reescrita):**

| Arquivo atual | Mudança mínima |
|---------------|----------------|
| `punch_button_register.php` | Após INSERT operacional, chamar `MarkRecorder` se flag |
| Control-iD import | Idem; coletor `04` |
| `ajuste_ponto_save.php` | Com flag: **bloquear** UPDATE/DELETE de punches com `rep_p_mark_id`; criar `ptrp_treatments`; manter UPDATE legado se flag off |
| `EspelhoPontoService.php` | Extensão de legenda (origem); não gerar AFD |
| Nav / home | Link painel conformidade (nova página) |

---

## 6. APIs e rotas

| Rota (proposta) | ACL | Função |
|-----------------|-----|--------|
| `GET /api/employee/punch_receipt.php` | próprio empregado | Comprovante 48h+ |
| `GET /web/conformidade.php` | admin | Painel status |
| `POST /web/afd_export.php` | ACL restrita AFD | Gera AFD+p7s ZIP |
| `POST /web/aej_export.php` | ACL AEJ | Gera AEJ+p7s ZIP |
| `GET/POST /web/atestado_tecnico.php` | admin | Anexo VII |
| Manter APIs app existentes | — | Retrocompatíveis |

---

## 7. Hash, CRC, datas (contratos técnicos)

### 7.1 SHA-256 tipo 7

Implementar em `MarkHasher` **somente** após conferência do leiaute oficial vigente (Anexo IX / AFD). Ordem canônica:

1. NSR  
2. Tipo registro (`7`)  
3. Data/hora marcação  
4. CPF  
5. Data/hora gravação  
6. Coletor  
7. On/off  
8. Hash anterior (ou vazio no primeiro)

Saída: 64 hex; capitalização conforme leiaute; CPF só dígitos; segundos `00` onde o leiaute exigir; timezone do estabelecimento.

### 7.2 CRC-16

`AfdCrc16`: CCITT-TRUE / KERMIT; vetor `123456789` → `2189`; 4 hex sem `0x`.

### 7.3 Formato data

Exportações oficiais: `AAAA-MM-DDThh:mm:00±HHMM` (ex.: `-0300`). Fonte de gravação = relógio do servidor; marcação off-line preserva captura do device.

---

## 8. Assinaturas digitais

| Artefato | Padrão | Signatário | Módulo |
|----------|--------|------------|--------|
| Comprovante PDF | PAdES (qualificada) | Certificado ICP-Brasil da **desenvolvedora do REP-P** | `PadesSigner` |
| AFD | CAdES detached `.p7s` | Desenvolvedora REP-P | `CadesSigner` |
| AEJ | CAdES detached `.p7s` | Desenvolvedora PTRP | `CadesSigner` (purpose=PTRP) |
| Atestado VII | Qualificada PF | Responsável legal + técnico | Fluxo manual/upload |

Env (exemplo — **não** versionar valores):

```
REP_P_A1_PFX_PATH=
REP_P_A1_PFX_PASSWORD=
PTRP_A1_PFX_PATH=
PTRP_A1_PFX_PASSWORD=
REP_P_SIGNING_ENV=dev|prod   # prod exige ICP-Brasil; dev permite teste rotulado
```

Reutilizar apenas a **ideia** de path+senha do `BackendPdfDigitalSigner`; **não** reutilizar o método HMAC como “assinado” para ponto.

Trailer AFD/AEJ: literal `ASSINATURA_DIGITAL_EM_ARQUIVO_P7S` conforme tamanho do leiaute.

---

## 9. Feature flags e cutover

| Flag | Default | Efeito |
|------|---------|--------|
| `rep_p_dual_write` | off | Grava `rep_p_marks` + `time_punches` |
| `rep_p_official_export` | off | Permite AFD oficial (exige INPI+cert) |
| `ptrp_treatments_only` | off | Ajuste RH não UPDATE/DELETE originais vinculados |
| `punch_block_mode` | `legacy` | `legacy`\|`allow_and_flag`\|`log_only` |
| `establishment.cutover_at` | null | Antes: só operacional; depois: dual-write |

**Cutover recomendado:**

1. Migrar schema (vazio).  
2. Configurar INPI (mesmo pendente).  
3. Certificado de teste em `dev`.  
4. Ativar dual-write em tenant piloto.  
5. Validar cadeia + AFD teste.  
6. Ativar `ptrp_treatments_only` no piloto.  
7. Só então `rep_p_official_export` em produção (com INPI real + cert produção).

---

## 10. Compatibilidade e riscos

| Risco | Mitigação |
|-------|-----------|
| Quebra app | APIs de batida inalteradas no contrato; dual-write após sucesso operacional |
| RH perde “editar horário” | Feature `ptrp_treatments_only` gradual; UI de tratamento nova |
| NSR duplicado | UNIQUE + FOR UPDATE |
| Mistura tenants | Sempre filtrar `tenant_id` + `company_id`; testes isolamento |
| Hash errado | Fixture vetorial + CLI; sem recalcular marks |
| Legado sem NSR | Relatório; exclusão do AFD oficial |
| Cert/HMAC confusão | Status painel: “não PAdES” se só HMAC |
| Bloqueio tolerância | Flag jurídica; tentativa logada |

---

## 11. Ordem de implementação (Fase 4 — proposta)

1. Migrations + `compliance_audit_log`  
2. `NsrAllocator` + `MarkHasher` + `AfdCrc16` + testes  
3. Dual-write em `punch_button_register` + facial  
4. Comprovante (PDF sem PAdES → com PAdES)  
5. AFD builder + validator + CAdES  
6. `ptrp_treatments` + adaptar `ajuste_ponto_save` sob flag  
7. AEJ + espelho legendado  
8. Painel conformidade + CLI  
9. Atestado VII (geração; assinatura PF externa)  
10. Off-line (se produto exigir)

---

## 12. Dependências externas (não substituíveis por código)

| Item | Responsável |
|------|-------------|
| Registro do programa no INPI | Administrativo / jurídico |
| Certificado A1/A3 ICP-Brasil REP-P | Desenvolvedora |
| Certificado ICP-Brasil PTRP | Desenvolvedora (pode ser o mesmo CNPJ se mesma empresa, contexts separados) |
| Assinatura PF atestado | Responsável legal + técnico |
| Revisão jurídica dos bloqueios de batida | Advogado trabalhista |
| Validação contábil/folha do AEJ/espelho | Contador / DP |

---

## 13. Critério de “pronto para Fase 4”

- [x] Auditoria publicada  
- [x] Este documento de arquitetura  
- [x] Specs AFD/AEJ/assinaturas/INPI/atestado/migração/checklist  
- [ ] Autorização explícita do produto para iniciar migrations e dual-write  

**Próximo passo após autorização:** Fase 4 item 1–3 (schema + NSR/hash/CRC + dual-write piloto), sem exportação oficial até INPI/cert.
