# Business Rules

**PURPOSE:** Single authoritative source for all business constraints. Every "is this allowed?" question is answered here. This file defines WHAT must be true, not HOW it is enforced.

**STATUS:** This file is the supreme authority for business logic. If any implementation conflicts with these rules, the implementation is wrong.

**CROSS-REFERENCES:** 
- Referenced by: Algorithms (`../../05_ALGORITHMS/*`), API Endpoints (`../../06_API/*`), Acceptance Criteria (`../../02_REQUIREMENTS/03_ACCEPTANCE_CRITERIA.md`)
- Implementation mechanisms are defined in: `../../CONSTITUTIONS/*.md`

---

## BR-001: Client Entity Rules

### BR-001-1: Hard Immutability
Clients (regardless of role) CANNOT be deleted — neither soft delete nor hard delete. This applies even if the client has no contracts, no payments, and no other associations.

> **How to Enforce:** `../../CONSTITUTIONS/04_DATABASE_COMMUNICATION.md` → Schema Conventions & Entity Protection

### BR-001-2: Shared Data Structure
All human roles (Customer, Agent, Investor) share the same data structure with fields: name, phone, avatar, description.

### BR-001-3: Role Inference via Flags
Role determination uses a flags array. No separate type or role column exists.
**Valid Flag Values:** `customer`, `agent`, `investor`

### BR-001-4: Customer Flag Timing
The `customer` flag is added immediately upon client creation via API — it does not wait for contract creation.

### BR-001-5: Agent Flag Timing
The `agent` flag is added in two cases:
1. When a client is explicitly converted to agent via API with `client_id`
2. When a contract is created with this client as the referrer (safety measure)

### BR-001-6: Investor Flag Permanence
The `investor` flag is added when a client is designated as an investor and is **NEVER** removed, even if no shares were ever added or all shares are subsequently withdrawn. The person continues to appear in investor lists regardless of share balance.

### BR-001-7: Reference Number Format
Every customer receives a `reference_number` in format `CUS-XXXXXXXXXX` (10 digits, leading zeros). Generated automatically upon creation. Used only for paper documents, never as a foreign key.

### BR-001-8: Investor Creation Rules
Creating an investor assigns the `investor` flag to a client, following the same pattern as agent creation.

1. **Client Conversion:** If an existing client is being converted to investor:
   - The client must NOT already have the `investor` flag — request is rejected if flag exists.
   - The client may have any combination of `customer` and/or `agent` flags.
   - Provided fields (name, phone, description, avatar) are updated.
   - Existing flags and reference number are NOT modified.
2. **New Client Creation:** If no existing client is referenced:
   - A new client record is created with the provided data.
   - `investor` flag is added immediately.
   - Reference number is generated automatically.
3. **No Shares at Creation:** Shares are NOT required at creation time. Shares management is handled independently via the Shares domain.
4. **No Flag Removal:** Even if shares are later withdrawn, the `investor` flag remains (see BR-001-6).

---

## BR-002: Contract Rules

### BR-002-1: Initial Payment Bounds
Initial payment must be: $0 \le \text{initial\_payment} \le \text{purchase\_amount}$
- Zero is allowed
- Negative values are rejected

### BR-002-2: Maximum Installment Period
`months` must be between 1 and 60 (5 years maximum).

### BR-002-3: State Machine
Contracts follow explicit states: `draft` → `active` → `completed`
> **Full state transitions:** `../../03_ARCHITECTURE/02_STATE_MACHINES.md`

### BR-002-4: Signing Makes Immutable
Transitioning from `draft` to `active` (signing) makes all contract data non-modifiable. `signed_at` is set at this point.

### BR-002-5: Automatic Completion
When the last pending or overdue installment is paid, contract status automatically changes to `completed`.

### BR-002-6: Draft Deletion Rules
- Deletion is ONLY allowed when status = `draft`
- Deletion is hard delete (not soft)
- **CASCADE deletes:** installments, payments (including company_payout), payment audit logs
- No trace remains of the cancelled draft

### BR-002-7: Company Payout Recording
Upon ANY contract creation (even drafts), a payment record of type `company_payout` is automatically created:
- Amount equals `purchase_amount`
- Not linked to any installment
- Deleted only if draft contract is deleted (CASCADE)

### BR-002-8: Contract Reference Number
Format: `CTR-XXXXXXXXXX` (10 digits, leading zeros). Generated automatically upon creation.

---

## BR-003: Installment Rules

### BR-003-1: State Table Generation
Installments are generated in bulk at contract creation — not calculated dynamically on request.

### BR-003-2: Equal Amounts
All installments within a single contract have exactly the same amount (remaining balance after initial payment, divided equally by months).

### BR-003-3: Status Change Trigger
Installment status changes from pending/overdue to paid only when a payment matching its exact amount is received.

### BR-003-4: Completion Effect
When the last installment in a contract becomes paid, the contract status becomes `completed`.

### BR-003-5: Due Date Immutability
`due_date` for any installment never changes, even if earlier installments are paid early.

---

## BR-004: Payment Rules

### BR-004-1: Exact Match (IRON RULE)
Payment amount MUST exactly match the next due installment amount (by sequential order).
- Partial payments are prohibited
- Paying multiple installments in one request is prohibited

### BR-004-2: Explicit Linking
When recording an installment payment, the link to the specific installment MUST be stored. This is the ONLY source of truth for which payment settled which installment.
- Determining the link by guessing via amounts or dates is prohibited

### BR-004-3: Payment Sequencing
Installments MUST be paid in ascending sequential order.
- Skipping a pending/overdue installment to pay a later one is prohibited
- Early payment (before due date) is allowed — system advances to next installment

### BR-004-4: Amount Modification Prohibited
Modifying payment amount is completely prohibited because it violates the Exact Match rule.
- To correct amount: DELETE (LIFO) then CREATE new payment

### BR-004-5: Date/Notes Modification (LIFO)
Modifying `payment_date` or notes is only allowed for the most recent payment (LIFO).
- Must be logged in audit log with old and new values

### BR-004-6: LIFO Deletion Only
Deletion is only allowed for the most recent payment (Last-In, First-Out).
- Cannot delete an earlier payment if later payments exist

### BR-004-7: Deletion Contract Status
Payment deletion is only allowed when contract status is `active`.
- Cannot delete payments from completed contracts

### BR-004-8: Hard Delete with Direct Reversal
Payment deletion is hard delete (physical removal from the ledger).
- Reversal uses the stored installment link to directly restore that specific installment
- No complex redistribution logic

### BR-004-9: Narrative Independence
Narrative text in audit logs MUST be completely self-contained — it MUST NOT depend on the payments table for any data (because the payment link becomes null on deletion).
> **Narrative generation patterns:** `../../05_ALGORITHMS/05_NARRATIVE_GENERATION.md`

---

## BR-005: Agent & Investor Rules

### BR-005-1: Permanent Investor Status
See BR-001-6. Once the investor flag is assigned, the investor status is permanent regardless of share activity.

### BR-005-2: Share Value
Each share has a fixed value of $200.

### BR-005-3: Investor Profit Calculation (Dynamic)
Investor profit = Total Contract Margin from Agent's Contracts × 5%
- Contract Margin per contract = `total_after_profit - purchase_amount`
- Calculated only for contracts with status `active` or `completed`
- No stored profit value — always computed dynamically
> **Computed field formulas:** `../../05_ALGORITHMS/04_COMPUTED_FIELDS.md` → Section 5.1

### BR-005-4: Shares Balance Calculation
Balance = Sum of `active` status records only:
- `deposit` transactions: positive
- `withdraw` transactions: negative
- `deleted` status: excluded
> **Computed field formulas:** `../../05_ALGORITHMS/04_COMPUTED_FIELDS.md` → Section 5.2

**Examples:**

| Operation | Type | Count | Status | Effect on Balance |
|:---|:---|:---|:---|
| Deposit 10 | deposit | 10 | active | +10 |
| Deposit 5 | deposit | 5 | active | +5 |
| Withdraw 3 | withdraw | 3 | active | -3 |
| **Result** | | | | **+12** |

| Operation | Type | Count | Status | Effect on Balance |
|:---|:---|:---|:---|:---|
| Withdraw 3 | withdraw | 3 | **deleted** | **Excluded** |

### BR-005-5: Shares Lock Period
Deleting a share log entry is only allowed if:
- It is the most recently created record for the client AND has `active` status
- Less than 30 days have passed since the record creation date (NOT `acquisition_date`)

### BR-005-7: Logical Deletion
When deleting shares:
- Do NOT physically delete the record
- Change status to `deleted`
- Record remains for historical purposes

### BR-005-8: Negative Balance Prevention
A withdrawal request MUST be rejected if the resulting shares balance would be less than zero. The system calculates the projected balance BEFORE creating the share log row. If projected balance < 0, the request is rejected — no record is created.

### BR-005-9: Shares Endpoint Guard
All shares operations require the client to have the `investor` flag. A client without this flag cannot access shares operations — the operation simply does not exist for non-investors.

### BR-005-10: Acquisition Date Requirement
Every share log record must include `acquisition_date`:
- Required on creation (share additions/withdrawals)
- Represents when the investor acquired the shares — independent of the system record date
- Can be past, present, or future — no range restrictions
- NOT used for 30-day lock calculation (that uses the record creation date)

---

## BR-006: Financial Precision Rules

### BR-006-1: BCMath Requirement
ALL financial calculations MUST use arbitrary-precision arithmetic.

### BR-006-2: Float Prohibition
Floating point types are PROHIBITED in any financial calculation.

### BR-006-3: Rounding Direction
Rounding is always Half Up (standard commercial rounding).

### BR-006-4: Fractional Payment Prohibition
If `remaining_amount / months` produces a fractional result, the request MUST be rejected. The caller must absorb fractions into the initial payment before resubmitting.
> **Validation algorithm:** `../../05_ALGORITHMS/02_CONTRACT_MATH_VALIDATION.md`

---

## BR-007: Time Filtering Rules

### BR-007-1: Analytics Date Range Validation
Analytics date range must satisfy:
- `from_date` must be ≤ `to_date`