# SPECIFICATIONS/02_REQUIREMENTS/01_FUNCTIONAL.md

**PURPOSE:** Defines WHAT the system must do — the observable behavior from the user's perspective. Implementation details are referenced, not embedded.

**CONSTRAINT:** All requirements are bounded by Business Rules in `../01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md`. If a requirement appears to conflict with a business rule, the business rule wins.

> **API-level specifications (inputs, outputs, error codes):** `../06_API/06_0X_*.md`
> **Algorithm-level specifications (step-by-step logic):** `../05_ALGORITHMS/05_0X_*.md`
> **How to build the endpoints that fulfill these requirements:** `../../CONSTITUTIONS/07_BOUNDARY_LAYERS.md`

---

## Module 1: Authentication & RBAC

### FR-1.1: Admin Login
- Accept email and password credentials
- Validate provided credentials are correct
- Return a bearer token and admin profile data
- Reject after 5 failed attempts per minute per IP address

### FR-1.2: Admin Logout
- Invalidate the current bearer token (permanent deletion, not temporary)

### FR-1.3: View Current User
- Return the authenticated admin's profile including assigned roles and permissions

### FR-1.4: Create Role
- Accept a unique role name and an array of permission identifiers
- Create the role and attach all specified permissions must all succeed or all fail together without partial state
- Require `roles.create` permission

---

## Module 2: Customer Management

### FR-2.1: Create Customer
- Accept name, phone, optional description, optional avatar image
- Create a client record with `customer` status assigned immediately
- Generate a unique reference number automatically
- If avatar provided: store securely and return a full URL (never the raw storage path)
- Return customer data including an empty financial summary
- Phone must follow Syrian format and be unique across all clients

### FR-2.2: List Customers
- Return a paginated list of customers sorted by nearest due installment
- Customers without active installments must always appear last regardless of sort direction
- Support the following filters:
  - Text search by name or phone
  - Time range based on the customer's first contract date
  - Status categories: overdue, due this month, fully paid, no installments
- Support reverse sorting
- When primary sort values are equal, use a stable secondary sort to prevent pagination drift
- Do not return `client_type_flags` or `reference_number` in the list response

### FR-2.3: View Customer Details
- Return customer profile with a computed financial summary covering all active and completed contracts:
  - Total installment amount
  - Total collected amount
  - Total remaining amount
  - Count of pending installments
  - Count of overdue installments
  - Count of received payments
  - Total number of installments
- Do not return `client_type_flags` or `reference_number` in the detail response

### FR-2.4: Update Customer
- Accept optional name, phone, description, avatar
- If new avatar provided: delete the old file securely and store the new one
- Allowed even if the customer has active contracts
- Never modify `client_type_flags` or `reference_number`
- At least one field must be provided
- Return updated customer data with computed financial summary

### FR-2.5: Export Customers
- Accept date range and format (Excel or PDF)
- Export must not block the API response (must execute asynchronously)

> **Note:** Customer deletion endpoint does NOT exist.

---

## Module 3: Agent Management

### FR-3.1: List Agents
- Return a paginated list of agents sorted alphabetically by name
- Support text search by name
- Return financial summary per agent: total installments, total collected, total remaining via agent's contracts

### FR-3.2: Create Agent
- Accept optional `client_id` to convert an existing client, or omit to create a new client
- If `client_id` provided: update provided fields and assign agent status (do not modify existing flags or reference number)
- If no `client_id`: create new client with agent status assigned
- Accept optional name, phone, description, avatar
- Do not handle shares in this operation
- Do not return `client_type_flags` in the response

### FR-3.3: View Agent Details
- Return agent profile with financial summary (total installments, collected, remaining via agent's contracts)
- Return a list of referred customers with their individual financial summaries
- If the client does not have agent status, return 404

### FR-3.4: Update Agent
- Accept optional name, phone, description, avatar
- If new avatar provided: delete the old file securely and store the new one
- Never modify `client_type_flags`, `reference_number`, or shares
- At least one field must be provided

> **Note:** Agent deletion endpoint does NOT exist.

---

## Module 4: Shares Management

> **Balance and lock algorithms:** `../05_ALGORITHMS/04_COMPUTED_FIELDS.md` → Section 5.2
> **Business rules:** `../01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-005-*

### FR-4.1: Add or Withdraw Shares
- Accept transaction type (deposit or withdraw), share count (minimum 1), and acquisition date
- If transaction type is `withdraw`: reject if the resulting balance would be negative
- On first deposit for any client: assign investor status permanently
- Create a share log record with `active` status
- Reject if the client does not have investor status (return 404)

### FR-4.2: Delete Share Log (Logical)
- Only allowed for the most recently created record for the client AND it must have `active` status
- Only allowed within 30 days of the record creation date
- Set status to `deleted` — the record must not be physically removed

### FR-4.3: View Shares Log
- Return a reverse-chronological paginated list of all share log records for the client
- Include all statuses (active, deleted)
- Reject if the client does not have investor status (return 404)

---

## Module 5: Contract & Installment Management

> **Math validation algorithm:** `../05_ALGORITHMS/02_CONTRACT_MATH_VALIDATION.md`
> **Payment engine algorithms:** `../05_ALGORITHMS/03_PAYMENT_ENGINE.md`
> **State machine transitions:** `../03_ARCHITECTURE/02_STATE_MACHINES.md`

### FR-5.1: Create Contract
- Accept customer, optional agent, product details, financial figures, and start date
- Validate that all financial figures are mathematically consistent (no fractions allowed)
- Generate installments automatically based on the provided figures and start date
- Generate a `company_payout` record automatically (amount equals purchase price, not linked to any installment)
- If initial payment is greater than zero: generate an `initial_payment` record with an audit log entry
- Assign default `draft` status
- Generate a unique reference number automatically
- Assign `customer` status to the customer and `agent` status to the agent (if provided) must all succeed or all fail together without partial state
- Due dates must correctly handle varying month lengths and leap years

### FR-5.2: View Contract Details
- Return contract data, status, reference number, and all installments with their statuses
- Return a unified transaction timeline combining actual payments and deleted payment records (inferred from audit logs)
- Include the customer's total remaining amount across ALL their active and completed contracts (not just the viewed contract)
- Deleted transactions must indicate their deleted state and show the amount

### FR-5.3: Sign Contract
- Only allowed when status is `draft`
- Transition status to `active` and record the signing timestamp
- The contract becomes immutable after this action

### FR-5.4: Delete Contract (Draft Only)
- Only allowed when status is `draft`
- Permanently remove the contract and all related records
- No trace of the cancelled draft must remain in the system

### FR-5.5: List Customer Contracts
- Return all active and completed contracts for a given customer
- For each contract, show the due date of the first pending or overdue installment (null if all paid)
- Sort by urgency: overdue contracts first (earliest overdue first), then upcoming (nearest due first), then completed
- No pagination — return all matching contracts

---

## Module 6: Payment Engine

> **Full algorithms:** `../05_ALGORITHMS/03_PAYMENT_ENGINE.md`
> **Narrative generation:** `../05_ALGORITHMS/05_NARRATIVE_GENERATION.md`

### FR-6.1: Record Payment
- Only allowed when contract status is `active`
- Find the next due installment by sequential order
- Payment amount must exactly match the installment amount — reject any mismatch
- Reject if there is an overdue or pending installment earlier in sequence
- Create a payment record with an explicit link to the settled installment
- Create an independent audit log entry with self-contained narrative text
- Update the installment status to `paid`
- If no pending or overdue installments remain: automatically transition contract to `completed`

### FR-6.2: Modify Payment (Limited)
- Only allowed for the most recent payment (LIFO)
- Only `payment_date` and `notes` can be modified — amount modification is prohibited
- Record the change in an audit log with old and new values

### FR-6.3: Delete Payment (LIFO)
- Only allowed when contract status is `active`
- Only allowed for the most recent payment
- Create an audit log entry before deletion (capturing the amount in the narrative)
- Physically remove the payment record
- Restore the linked installment to `pending` or `overdue` (based on whether its due date has passed)

---

## Module 7: Financial Analytics

> **Performance strategy and caching:** `../03_ARCHITECTURE/03_PERFORMANCE_STRATEGY.md`

### FR-7.1: KPIs Report
- Accept a primary date range (from_date, to_date) and a comparison date range (comparison_from_date, comparison_to_date)
- Return executive KPIs with comparison data:
  - Contract signing count with change percentage, direction, status, and sparkline
  - Active investments value with change percentage, direction, status, and sparkline
  - Average days late with change percentage, direction, status, and sparkline
- Return operational KPIs (no comparison):
  - Payments due within 7 days
  - Payments due within 15 days
  - Payments due within 30 days
- Results cached with TTL-based expiration
- Data sourced from daily snapshot tables (up to 24 hours stale)

### FR-7.2: Charts Report
- Accept a date range (from_date, to_date)
- Return installments status distribution: pending, collected, overdue, and scheduled amounts with percentages
- Return overdue aging analysis grouped into time buckets
- Return collection trend: daily collected and overdue amounts
- Data is computed live from actual database tables (real-time)
- No caching

---

## Module 8: Notification Templates

### FR-8.1: List Templates
- Return all stored notification templates with their type and body template

### FR-8.2: Create Template
- Accept a unique type identifier and a body template with variable placeholders
- Reject if the type already exists

### FR-8.3: Update Template
- Accept a new body template for an existing template
- Type identifier must not change

### FR-8.4: Generate Notification Text
- Accept a client and an installment
- Determine the appropriate template type automatically based on the due date vs. today
- Replace all variable placeholders with actual data
- Return the final generated text (no sending occurs)

---

## Module 9: Investor Management

> **Business rules:** `../01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-001-6, BR-001-8, BR-005-*

### FR-9.1: List Investors
- Return a paginated list of clients who have the investor flag
- Search by name and phone (partial match)
- Sorted alphabetically by name
- Include the current active shares balance for each investor

### FR-9.2: Create Investor
- Accept optional `client_id` to convert an existing client, or omit to create a new client
- If `client_id` provided:
  - Reject if the client already has the `investor` flag
  - Update provided fields (name, phone, description, avatar)
  - Do not modify existing flags or reference number
- If no `client_id`: create a new client with the provided data
- Assign `investor` flag permanently to the client
- Shares are NOT handled in this operation — shares are added independently via the Shares Management module
- Do not return `client_type_flags` in the response

### FR-9.3: View Investor Details
- Return investor profile with current active shares balance
- Return total calculated investor profit (5% of contract margin from contracts where this person is the agent and contract is active/completed)
- Return a list of referred customers — customers who have contracts where this person is the `agent_id` — with:
  - Customer id, name, avatar_url, description
  - Contract margin from that customer's active/completed contracts via this investor
  - Investor profit (5% of that contract margin)
- If the client does not have investor status, return 404
- If no contracts exist where this person is the `agent_id`: investor profit is "0.00" and referred_customers is an empty array

### FR-9.4: Update Investor
- Accept optional name, phone, description, avatar
- If new avatar provided: delete the old file securely and store the new one
- Never modify `client_type_flags`, `reference_number`, or shares (shares are managed via the Shares Management module)
- At least one field must be provided

> **Note:** Investor deletion endpoint does NOT exist. Share withdrawal is handled by the Shares Management module.