# Feature Specification: Contracts Module (Contratos)

**Feature Branch**: `003-contratos-module`

**Created**: 2026-08-25

**Status**: Draft

**Input**: User description: Feature described by the documents in `local/scopes/CONTRATOS/` (`Contratos - Revisão de escopo.md`, `Contratos - Entregáveis.md`, `Contratos - Critérios de Aceite.md`) — a CRM module for registering, managing, and integrating contracts, including a new produto_marca-to-SO5 data link, a Classe classification, and the four contract-update actions (Renovar, Estender, Ampliar/Reduzir, Cancelar).

**Terminology note**: The CRM's "produto" (registered in Cadastro > Produto) corresponds to SO5's "marca" — this spec uses **produto_marca** for that entity. The CRM's "insumo" corresponds to SO5's "produto" — this spec uses **produto_insumo**. "Segmento" is the same concept and name in both systems. Only the contract-scoped segmento is covered here (not the separate prospect-scoped segmento).

## Clarifications

### Session 2026-08-25

- Q: If the SO5 integration is unreachable while a user is actively creating or editing a contract's produto_marca section (not just viewing an already-saved contract), should the contract be blocked from being finalized until SO5 responds, or should the user be allowed to save it in an incomplete state and fill in segmento/insumo later? → A: Block finalizing only that section — segmento/insumo stay required, "Finalizar" is blocked for that produto_marca section until SO5 responds, with a clear inline error scoped to the section; the rest of the form (dates, payment, signature, other produto_marca sections) stays usable while waiting.
- Q: In the Renovar (renewal) action, can the user change which segmentos are covered for a produto_marca, or is segmento fixed from the original contract with only produto_insumo marks editable within it? → A: Segmento is fixed from the original contract; Renovar only lets the user adjust which produto_insumo are marked within the segments already on the contract. Changing which segmentos are covered goes through Ampliar/Reduzir instead.

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Link a produto_marca to its SO5 record and classify it (Priority: P1)

An Admin maintaining the product catalog (Cadastro > Produto) needs to connect each produto_marca to its corresponding record in the SO5 system, and assign it a Classe (VHP, Plataforma, or Serviço Padrão), so that the Contracts module can later pull real segment and insumo data for that produto_marca and enforce the correct commercial classification.

**Why this priority**: Every downstream contract-creation capability depends on a produto_marca already carrying a valid SO5 link and Classe. Without this, contract creation would have nothing but stale mock data to offer.

**Independent Test**: Open an existing or new produto_marca in Cadastro > Produto, select a "Marca SO" value from the SO5-backed list, select a Classe, and save. Reopen the record and confirm both the SO5 link and Classe were persisted.

**Acceptance Scenarios**:

1. **Given** the Cadastro > Produto screen, **When** an Admin opens the "Marca SO" select, **Then** it lists the marcas available in SO5 (live data, not a fixed list).
2. **Given** a produto_marca with a "Marca SO" selected and saved, **When** the record is reopened, **Then** the same SO5 link is shown.
3. **Given** a produto_marca with no "Marca SO" link, **When** its segments or insumos are requested elsewhere in the system, **Then** the system returns an empty result without breaking the screen.
4. **Given** the Classe field on a produto_marca, **When** an Admin selects any subset of the three values (`VHP`, `Plataforma`, `Serviço Padrão`) as the options available for that produto_marca, **Then** the system saves them without enforcing any combination rule — this field configures which options a contract may later choose from; the mutual-exclusivity rule is enforced at contract time instead (see User Story 3).
5. **Given** the product catalog before this feature, **When** the one-time data migration runs, **Then** every previously existing produto_marca ends up with a valid Classe and a "Marca SO" link populated (using the sequential ID as the initial integration code), without manual entry.

---

### User Story 2 - View and access-control the contracts list (Priority: P2)

An Admin or Gestão user opens the contracts screen to see every contract on record at a glance — its number, value, products, key dates, and signed PDF — and to reach the actions available for each one. Any other user profile, including someone who tries a direct URL, must not be able to see this screen at all.

**Why this priority**: This is the entry point for every other contract workflow and the only place today's "Interações de sucesso" button needs to be removed from; it delivers value even before the full creation wizard exists (it can list contracts that already exist).

**Independent Test**: Log in as an Admin or Gestão user, open the contracts screen, and confirm the listing and action buttons appear. Log in as any other profile and confirm the screen and its data are unreachable, including via direct URL.

**Acceptance Scenarios**:

1. **Given** a logged-in Admin or Gestão user, **When** they open the contracts screen, **Then** every registered contract is listed with Número do Contrato, Valor (médio and total), lista de produtos, Início, Vencimento, and a link to download the signed PDF.
2. **Given** a logged-in user with any other profile, **When** they try to reach the contracts screen (menu or direct URL), **Then** access is denied.
3. **Given** the contracts list, **When** it renders, **Then** each contract shows buttons for Editar, Visualizar, Renovar, Estender, Ampliar/Reduzir, and Cancelar, and no "Interações de sucesso" button appears anywhere on the screen.
4. **Given** the contracts list, **When** an Admin/Gestão user starts a new contract, **Then** they can start as many new contracts as needed — there is no one-contract-at-a-time restriction.

---

### User Story 3 - Register a new contract (Priority: P3)

An Admin or Gestão user registers a brand-new contract: selecting one or more produto_marca, configuring each one's segments, insumos, class, platform type, and deliverables, then filling in the contract's dates, payment terms, and signature status, and finally saving the complete record.

**Why this priority**: This is the core value of the module — without it, nothing exists for the list or the update actions to operate on. It depends on Story 1 (accurate SO5-backed segment/insumo data and valid Classe values) and Story 2 (the screen it's launched from).

**Independent Test**: From the contracts screen, start a new contract, select one produto_marca, complete its segment/insumo/classe/platform/deliverables configuration, fill in dates, payment, and signature status, then save. Reopen the saved contract and confirm every entered value was persisted correctly.

**Acceptance Scenarios**:

1. **Given** the new-contract form, **When** the user selects one or more produto_marca, **Then** one collapsed, independently expandable section is created per selection, each showing a status indicator (not-started / incomplete / complete) that updates as its fields are filled in.
2. **Given** an expanded produto_marca section, **When** the user opens its segment selector, **Then** the available segments come from the SO5 integration for that specific produto_marca, not a fixed list.
3. **Given** an expanded produto_marca section, **When** the user opens "Configurar Insumos", **Then** a table appears with one row per SO5-sourced produto_insumo for that produto_marca and one column per segment selected, and each cell is a checkbox; marking a cell for one segment removes that insumo's marking in any other segment.
4. **Given** one or more Pacotes Padrão selected in a produto_marca section, **When** the user opens "Configurar Insumos", **Then** the insumos belonging to the selected pacotes are pre-marked under the first segment shown; changing the selected pacote resets those markings to match the new pacote.
5. **Given** the Classe field within a produto_marca section, **When** the user picks values, **Then** only the options that produto_marca was configured with (Story 1) are offered, and the system prevents selecting both `Plataforma` and `VHP` together, or `Serviço Padrão` without `Plataforma` also selected.
6. **Given** all produto_marca sections completed, **When** the user advances, **Then** they reach the contract Dates section (Início, Kick Off, Vencimento), where the contract term is auto-calculated (Vencimento − Início, in calendar days) and not manually editable; Vencimento must be on or after Início, and the system prevents saving otherwise.
7. **Given** the Dates section completed, **When** the user advances, **Then** they reach Payment (courtesy flag, main currency, reference PTAX, periodicity, value split method, computed monetary totals, NF-issuance day rule, payment terms, adjustment/reajuste rule, ponto focal and demais usuários), where all monetary conversions use the entered reference PTAX consistently.
8. **Given** the Payment section completed, **When** the user advances, **Then** they reach Signature, where answering "Contrato assinado = Não" reveals a "Contrato Regularizado?" question, and answering "Sim" to either question reveals a PDF-only, 10MB-max file upload.
9. **Given** all sections completed, **When** the user saves, **Then** the contract is created and immediately visible in the contracts list with the values entered.
10. **Given** a contract opened in "Visualizar" mode, **When** the user clicks "Editar Contrato", **Then** the form switches to editable mode with all previously saved data intact, and saving updates the same contract record.

---

### User Story 4 - Renew a contract (Priority: P4)

An Admin or Gestão user renews an existing contract — updating its products/insumos, term dates, and payment/signature terms — carrying it forward as the same logical contract.

**Why this priority**: Renewal is the most frequently expected lifecycle action on an existing contract once contracts exist; it depends on Story 3 (a contract must already exist).

**Independent Test**: Open an existing contract's "Renovar" action, change the term dates and at least one payment field, save, and confirm the contract's lineage carries forward correctly (previous record superseded/deactivated, new record active) and a history entry was recorded.

**Acceptance Scenarios**:

1. **Given** an existing contract, **When** the user opens "Renovar", **Then** the form shows produto_insumo per produto_marca (scoped to the segmentos already on the contract, which are not editable here), início, vencimento, all payment fields, and all signature fields — no other fields.
2. **Given** the Renovar form, **When** the user changes which produto_insumo are marked within an existing segmento, **Then** the change is accepted; there is no way to add or remove a segmento from this form.
3. **Given** a completed Renovar form, **When** the user saves, **Then** a new record is created for this contract carrying the renewed data forward, the previous record is deactivated (no longer shown as an active contract), and the contract's "Número do Contrato" changes to the new record's identity.
4. **Given** a saved renewal, **When** the contract's history is viewed, **Then** it shows the renewal action, date, user, and which fields changed relative to the previous record.

---

### User Story 5 - Extend a contract (Priority: P5)

An Admin or Gestão user extends an existing contract's term and related payment-timing fields without touching its products or values.

**Why this priority**: A narrower, lower-effort lifecycle action than renewal; independently useful once contracts exist.

**Independent Test**: Open an existing contract's "Estender" action, change the vencimento date, save, and confirm only the intended fields changed on the same record, with a history entry recorded.

**Acceptance Scenarios**:

1. **Given** an existing contract, **When** the user opens "Estender", **Then** the form shows only início, vencimento, prazo de pagamento, prazo de pagamento observação, and pagamento via.
2. **Given** a completed Estender form, **When** the user saves, **Then** only those fields change on the existing record, plus the contract's totals (which recompute from the new term at the unchanged per-period rate, since they're derived from prazo) — products and every other field remain untouched.
3. **Given** a saved extension, **When** the contract's history is viewed, **Then** it shows the extension action, date, user, and the changed fields.

---

### User Story 6 - Expand or reduce a contract (Priority: P6)

An Admin or Gestão user adjusts an existing contract's contracted products/insumos and monetary values — growing or shrinking its scope — while its Kick Off date stays fixed.

**Why this priority**: A full-scope edit action, more involved than renew/extend; still independently valuable once earlier actions exist.

**Independent Test**: Open an existing contract's "Ampliar/Reduzir" action, add or remove a produto_insumo and adjust a value, save, and confirm the contract's lineage carries the new products/insumos and values forward with a history entry, and that Kick Off was not editable.

**Acceptance Scenarios**:

1. **Given** an existing contract, **When** the user opens "Ampliar/Reduzir", **Then** the form shows every field from the full contract form except Kick Off date.
2. **Given** a completed Ampliar/Reduzir form, **When** the user saves, **Then** a new record is created carrying the new products/insumos and values forward, and the previous record is deactivated (no longer shown as an active contract).
3. **Given** a saved ampliação/redução, **When** the contract's history is viewed, **Then** it shows the action, date, user, and the changed fields.

---

### User Story 7 - Cancel a contract (Priority: P7)

An Admin or Gestão user cancels an existing contract, providing a justification and changing only its status.

**Why this priority**: The simplest lifecycle action by field count, but still gated behind a contract existing; lowest priority only because it's the narrowest change.

**Independent Test**: Open an existing contract's "Cancelar" action, enter a justification, confirm the cancellation, and verify the contract's status changed with no other field touched and a history entry recorded. Attempting to cancel without a justification is rejected.

**Acceptance Scenarios**:

1. **Given** an existing contract, **When** the user triggers "Cancelar", **Then** a justification field is required before the cancellation can be submitted.
2. **Given** a confirmed cancellation, **When** it completes, **Then** only the contract's status (and the recorded justification) changes — all other fields remain as they were.
3. **Given** a cancelled contract, **When** the contract's history is viewed, **Then** it shows the cancellation action, date, user, and the justification provided.

---

### Edge Cases

- A produto_marca with no "Marca SO" link yields an empty segment/insumo list in the contract form rather than an error.
- Início, Kick Off, and Vencimento can be saved in any chronological order — there is no order validation in this delivery.
- A produto_insumo can be marked under only one segment at a time; marking it elsewhere unmarks the previous segment.
- Changing the selected Pacote Padrão discards the current insumo markings and reapplies the new pacote's defaults.
- If the SO5 integration is temporarily unavailable, a contract that was already saved must still be viewable — the system shows a clear error for the unavailable data rather than failing the whole page.
- If the SO5 integration is temporarily unavailable while a user is creating or editing a produto_marca section, that section shows a clear inline error and cannot be marked complete or finalized until SO5 responds — the rest of the contract form (other sections, other produto_marca) remains usable in the meantime.
- Contracts created before the Classe/SO5 migration must remain openable and editable after the migration runs, with their segmento/produto_insumo data handled consistently (either mapped automatically or clearly flagged for manual review — either approach is acceptable as long as it doesn't break the record).
- The one-time migration must be safe to run more than once without duplicating or corrupting data.
- Switching "Contrato Assinado" from "Não" to "Sim" (or vice versa) after already answering "Contrato Regularizado?" must not leave stale/contradictory upload data behind.
- An upload rejected for wrong type or excess size must clearly explain why, without discarding the rest of the form's already-entered data.
- None of the four update actions require an approval workflow (no manager/alçada sign-off) at this stage — Cancelar's required justification is a free-text field the acting user fills in themselves, not an approval step.
- Renovar and Ampliar/Reduzir carry a contract forward as a new record and deactivate the previous one; the contract's "Número do Contrato" therefore changes on every renewal or ampliação/redução. Estender and Cancelar update the existing record in place and do not change it.

## Requirements *(mandatory)*

### Functional Requirements

**Access control**

- **FR-001**: System MUST restrict every contracts-module screen and action to users with Admin or Gestão profile, including blocking direct URL access for any other profile.

**produto_marca configuration (Cadastro > Produto)**

- **FR-002**: System MUST let an Admin link a produto_marca to a corresponding SO5 marca via a selector populated from live SO5 data, and persist the returned integration code.
- **FR-003**: System MUST let an Admin link a produto_marca to one or more of exactly three Classe values (`VHP`, `Plataforma`, `Serviço Padrão`) as the set of options available for that produto_marca — this is a configuration of available options, not a combination the Admin is choosing for use.
- **FR-004**: System MUST prevent a contract's produto_marca section from having both `Plataforma` and `VHP` selected at once, and MUST prevent `Serviço Padrão` from being selected without `Plataforma` — enforced when a Classe is chosen for a contract (Story 3), not as a restriction on which Classe values a produto_marca can be configured with in Cadastro > Produto.
- **FR-005**: ~~System MUST rename the existing "Serviço Padrão" classification to "Plataforma + Serviço Padrão" wherever it is displayed.~~ Reverted: the classification stays named "Serviço Padrão"; only the FR-004 dependency-on-Plataforma rule (a separate, id-based check) still applies to it.

**Contracts list**

- **FR-006**: System MUST list every registered contract, showing at minimum: Número do Contrato, Valor do Contrato (médio and total), lista de produtos, Início, Vencimento, and a link to download the signed PDF.
- **FR-007**: System MUST provide Editar, Visualizar, Renovar, Estender, Ampliar/Reduzir, and Cancelar actions for every listed contract.
- **FR-008**: System MUST remove the "Interações de sucesso" button/entry point from the contracts screen.
- **FR-009**: System MUST allow registering any number of new contracts, with no restriction limiting a company/record to a single contract.

**Contract creation — produto_marca / segmento / insumo / classe**

- **FR-010**: System MUST allow selecting one or more produto_marca per contract, each producing its own independently expandable configuration section that starts collapsed.
- **FR-011**: System MUST show a visual status indicator per produto_marca section reflecting whether it is not started, incomplete, or complete, updating as the user fills it in.
- **FR-012**: System MUST source the segmentos offered for a produto_marca from the SO5 integration for that specific produto_marca, not from a fixed/mocked list.
- **FR-013**: System MUST source the produto_insumo rows offered in the "Configurar Insumos" table from the SO5 integration for that specific produto_marca.
- **FR-014**: System MUST let the user select one or more Pacotes Padrão per produto_marca section; selecting a pacote MUST pre-mark its associated insumos under the first segment shown, and changing the pacote MUST reset those markings to the new pacote's defaults.
- **FR-015**: System MUST prevent a single produto_insumo from being marked under more than one segment simultaneously within the same produto_marca section.
- **FR-016**: System MUST scope the Classe choices offered within a produto_marca's contract-form section to only the Classe values linked to that produto_marca in Cadastro > Produto (per FR-003); FR-004's combination rule is then enforced against whichever of those are selected.
- **FR-017**: System MUST offer "Tipo de Plataforma" as a single choice between `Brasil` and `Estados Unidos` for every produto_marca.
- **FR-018**: System MUST offer the fixed list of Entregáveis (multi-select) for every produto_marca section.

**Contract creation — dates, payment, signature**

- **FR-019**: System MUST calculate the contract's prazo de contratação automatically as Vencimento − Início, in calendar days, and MUST NOT allow it to be edited directly.
- **FR-020**: System MUST accept Início, Kick Off, and Vencimento in any order without enforcing chronological validation.
- **FR-021**: System MUST convert every entered monetary value into whichever currency a given field requires, using a single reference PTAX applied consistently to every month of the contract, including under the "Personalizado" value split.
- **FR-022**: When the value split is "Uniforme", System MUST compute Valor 2 and Valor Mensal Tabela in the secondary currency, plus Valor Total and Valor Médio Mensal, from the entered values.
- **FR-023**: When the value split is "Personalizado", System MUST compute each month's converted value, the contract's Valor Total as the sum of monthly values, and Valor Médio Mensal as that total divided by the number of months.
- **FR-024**: System MUST label the NF-issuance day options using the word "Período" (never "Bimestre"), with a 1–30 range for the fixed-day option and a 1–22 range for the business-day option.
- **FR-025**: System MUST NOT reveal any additional field when "Personalizado" is selected under reajuste contratual's "Meses, conforme:".
- **FR-026**: System MUST exclude the professional already selected as "Ponto focal da contratação" from the "Demais usuários" options for the same contract.
- **FR-027**: System MUST require a "Contrato Regularizado?" answer whenever "Contrato Assinado" is "Não", and MUST require a file upload whenever either question is answered "Sim".
- **FR-028**: System MUST accept only PDF files up to 10MB for the contract's signature upload, rejecting any other type or any file above that size with a clear explanation.
- **FR-029**: System MUST persist a saved contract with all data entered across its produto_marca, dates, payment, and signature sections, and MUST make it retrievable via "Visualizar Contrato" afterward.
- **FR-029a**: System MUST block finalizing (saving) a produto_marca section, and thus the contract, while the SO5 integration is unreachable and that section's segmento/produto_insumo data cannot be loaded — showing a clear inline error scoped to that section, while leaving the rest of the contract form usable.
- **FR-030**: System MUST let a contract opened in "Visualizar Contrato" switch into edit mode via an explicit "Editar Contrato" action, without losing already-displayed data.

**Contract update actions**

- **FR-031**: System MUST update the existing contract record in place (never create a new one) for Estender and Cancelar. For Renovar and Ampliar/Reduzir, System MUST carry the contract forward as a new record representing the same logical contract, deactivating the previous record so it is no longer shown as an active contract.
- **FR-032**: System MUST record a history entry for every Renovar, Estender, Ampliar/Reduzir, or Cancelar action, capturing the action taken, date, user, and which fields changed relative to the prior state (the immediately-preceding record, for Renovar/Ampliar/Reduzir).
- **FR-033**: System MUST restrict the Renovar form to: produto_insumo per produto_marca, início, vencimento, all payment fields, and all signature fields — the segmentos already on the contract are shown but MUST NOT be addable or removable from this form; changing segmento coverage requires Ampliar/Reduzir.
- **FR-034**: System MUST restrict the Estender form to: início, vencimento, prazo de pagamento, prazo de pagamento observação, and pagamento via — and MUST leave every other field on the contract unchanged, except the contract's calculated totals (rstotal/rsmedmensal and their USD equivalents), which MUST recompute from the new prazo at the unchanged per-period rate.
- **FR-035**: System MUST allow the Ampliar/Reduzir form to edit every contract field except Kick Off.
- **FR-036**: System MUST require a justification (free-text) whenever Cancelar is executed, and MUST otherwise change only the contract's status.
- **FR-037**: System MUST NOT require an approval/alçada (manager sign-off) step for Renovar, Estender, Ampliar/Reduzir, or Cancelar in this delivery — Cancelar's justification (FR-036) is entered and submitted by the acting user alone.

**Data migration**

- **FR-038**: System MUST provide a one-time migration that assigns a valid Classe to every produto_marca that existed before this feature, based on its current classification data, without requiring manual review per record.
- **FR-039**: System MUST provide a one-time migration that populates the "Marca SO" link for every produto_marca that existed before this feature, using its sequential ID as the initial integration code.
- **FR-040**: System MUST ensure contracts registered before the migration remain viewable and editable afterward, handling their existing segmento/produto_insumo data without breaking the record.
- **FR-041**: The migration MUST be safe to re-run without duplicating or corrupting data.

### Key Entities

- **Contrato**: A commercial agreement tied to one company, holding one or more produto_marca configurations, contract dates, payment terms, signature status, current status (active/cancelled/etc.), and a change history.
- **Produto_marca**: The CRM's product record (Cadastro > Produto), extended with a link to its corresponding SO5 marca (integration code) and a Classe (VHP / Plataforma / Serviço Padrão).
- **Segmento (de contrato)**: A classification sourced from SO5, tied to a produto_marca, selected per contract; only its integration code and display-relevant fields are stored on the contract.
- **Produto_insumo**: An item sourced from SO5, tied to a produto_marca, assignable to exactly one selected segmento within a contract's produto_marca configuration.
- **Pacote Padrão**: A named, manually curated set of default produto_insumo selections per produto_marca/segmento, used to pre-fill the "Configurar Insumos" table.
- **Histórico de Contrato**: An append-only record of every Renovar, Estender, Ampliar/Reduzir, and Cancelar action taken on a contract, capturing action, date, user, and changed fields.
- **Profissional**: An existing CRM entity referenced by a contract as "Ponto focal da contratação" or "Demais usuários".

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: An Admin or Gestão user can register a complete new contract — products, dates, payment, and signature — in a single session without needing any tool outside the CRM.
- **SC-002**: 100% of registered contracts appear in the contracts list with correct Número, Valor (médio/total), produtos, datas, and PDF link.
- **SC-003**: 100% of access attempts to the contracts module by non-Admin/Gestão profiles are blocked, including direct-URL attempts.
- **SC-004**: For every produto_marca with a configured SO5 link, the segmentos and produto_insumo shown during contract creation match SO5's current data rather than the previous fixed/mocked list.
- **SC-005**: 100% of Renovar, Estender, Ampliar/Reduzir, and Cancelar actions produce a corresponding history entry with action, date, user, and changed fields. Estender and Cancelar update the original contract record; Renovar and Ampliar/Reduzir correctly carry the contract forward as a new active record with the previous one deactivated. 100% of Cancelar attempts made without a justification are rejected.
- **SC-006**: After the one-time migration runs, 100% of previously existing produto_marca records carry a valid Classe and a populated "Marca SO" link, and 100% of previously existing contracts remain viewable without error.
- **SC-007**: 100% of signature-upload attempts that are not a PDF or exceed 10MB are rejected with an explanatory message, and valid PDFs up to 10MB are accepted.

## Non-Functional Requirements *(optional)*

> Proposal — the source scope docs flagged these as a baseline for internal review, not yet validated with the team; numeric thresholds are adjustable. Carried into this spec because `plan.md`/`research.md`/`contracts/`/`tasks.md` already cite these IDs.

### Performance
- **CNF-01**: The contracts list loads within 3s at the current volume of registered contracts (adjust the threshold once real expected volume is known).
- **CNF-02**: Automatic value fields (USD, totals, averages) recalculate visibly in real time on every dependent field change, without a page reload.
- **CNF-03**: Segmento/insumo lookups via the SO5 integration in the "Configurar Insumos" modal load within 2s under normal network conditions.

### Security & Access Control
- **CNF-04**: Every write action (create, edit, renovar, estender, ampliar/reduzir, cancelar) validates the user's profile on the backend, not only in the interface.
- **CNF-05**: Uploaded signature files are accessible only to authorized users (Admin/Gestão).
- **CNF-06**: SO5 API credentials/tokens are never exposed client-side (browser).

### Auditability & Traceability
- **CNF-07**: Every relevant change to a contract — including via the summarized actions — is auditable: who, when, what changed. Nothing is overwritten without leaving a trace.
- **CNF-08**: The migration logs an execution record (what changed, when, how many records) for later audit or manual rollback.

### Reliability & Data Integrity
- **CNF-09**: Temporary SO5 API unavailability does not prevent viewing an already-saved contract — the system degrades in a controlled way (clear error message) without breaking the screen.
- **CNF-10**: The migration is idempotent, or has equivalent protection against accidental re-execution that would duplicate or corrupt data.
- **CNF-11**: Monetary calculations (PTAX conversion, totals, averages) use adequate precision, with no perceptible rounding error in the displayed final value.

### Usability
- **CNF-12**: Error messages (invalid upload, required field, etc.) explain what's wrong and how to fix it — never a generic error.
- **CNF-13**: The produto_marca session status indicator (gray/yellow/green) has sufficient contrast to read, without relying on color alone to be understood.
- **CNF-14**: The form preserves entered data when navigating between wizard sessions ("próximo"/back), without loss of information.

### Compatibility
- **CNF-15**: The module works on the same browsers/devices already officially supported by the rest of the CRM, with no additional requirement.

### Localization
- **CNF-16**: Monetary values display R$/US$ with Brazilian-standard separators (thousands dot, decimal comma).
- **CNF-17**: Dates display in dd/mm/yyyy format throughout the interface.

### Observability
- **CNF-18**: SO5 integration failures (unavailability, authentication error, timeout) are logged in an identifiable way for diagnosis.

## Assumptions

- The Contratos screen, its "Novo Contrato" button, and the produto/Cadastro > Produto screen already exist in the CRM; this feature extends and modifies them rather than building new screens from a blank state.
- The SO5 endpoints for segmento and produto_insumo (scoped to a marca) do not exist yet and are being built as part of this same delivery, alongside the CRM-side consumption — both sides are in scope.
- The exact algorithm for auto-assigning Classe to existing produto_marca during migration, and the exact strategy for handling old contracts' segmento/insumo data, are left to implementation discretion as long as the outcomes in FR-038–FR-041 hold; they are not open business decisions.
- The migration does not need to complete before the module goes live — migration and deploy may happen concomitantly.
- The Entregáveis multi-select list and the Pacotes Padrão content are fixed/manually curated reference data maintained outside this module (by Operação + Dev) — this spec covers presenting/using them, not a management screen for them; no such screen is in scope.
- There is no due-date or alert mechanism for contracts pending signature or regularização in this delivery.
- None of the four contract-update actions require a manager/alçada approval workflow in this delivery; Cancelar's required justification (FR-036) is a self-reported free-text field, not an approval gate.
- "Profissional" in the Ponto focal / Demais usuários fields refers to the CRM's existing Profissional entity, scoped to those active at the contract's company.
- Renovar and Ampliar/Reduzir carry the contract forward as a new record and deactivate the previous one, rather than updating a single record in place — this means a contract's "Número do Contrato" changes on every renewal or ampliação/redução. This is a deliberate choice to match how these two actions are already built and used today, made explicitly aware that it differs from a strict single-fixed-record model; if a stable, unchanging contract number across renewals/adjustments turns out to matter downstream (e.g. for external references, reporting), that would need to be revisited as a separate decision.
