# Implementation Plan: USMS-DOJ Prison API

## Overview

Implementasi integrasi API antara USMS dan DOJ untuk sinkronisasi data tahanan. DOJ menyediakan RESTful endpoints (store, index, show) untuk Criminal Cases, dan USMS menggunakan `DojCriminalCaseService` untuk berkomunikasi dengan DOJ API. Implementasi menggunakan PHP/Laravel di kedua sisi, mengikuti pola existing (response format, middleware, service class pattern).

## Tasks

- [x] 1. DOJ: Implement CriminalCaseController with store endpoint
  - [x] 1.1 Create CriminalCaseController with store method and application number generation
    - Create `DOJ/app/Http/Controllers/Api/CriminalCaseController.php`
    - Implement `store(Request $request)` method with validation rules for all fields (cid_no, accused_name, accused_plea, bail_amount, bail_status, decision, status, judge_name, prosecutor_name, public_defender_name, date_of_hearing)
    - Implement `generateApplicationNo()` private method with format `CT-CR-{YEAR}-{XXXX}` (zero-padded, sequential per year)
    - Return 201 with `{"success": true, "message": "...", "data": {...}}` on success
    - Return 422 with `{"success": false, "message": "...", "errors": {...}}` on validation failure
    - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.6_

  - [x] 1.2 Register criminal-cases API routes in DOJ
    - Add routes to `DOJ/routes/api.php` under `api.key` middleware group
    - Register GET `/criminal-cases` → `index`, POST `/criminal-cases` → `store`, GET `/criminal-cases/{id}` → `show`
    - _Requirements: 1.1, 2.3, 4.1, 6.1_

- [x] 2. DOJ: Implement index and show endpoints
  - [x] 2.1 Implement index method with filters
    - Add `index(Request $request)` method to CriminalCaseController
    - Support query params: `cid_no` (partial, case-insensitive), `accused_name` (partial, case-insensitive), `status` (exact match)
    - Order results by `created_at` descending
    - Ignore invalid status filter values (return all results)
    - Return all Criminal Case fields in response array
    - _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7_

  - [x] 2.2 Implement show method with ID or cid_no lookup
    - Add `show(string $id)` method to CriminalCaseController
    - First attempt numeric ID lookup, then fallback to `cid_no` lookup
    - Return 404 with `{"success": false, "message": "Data tidak ditemukan.", "data": null}` if not found
    - Return full Criminal Case data on success
    - _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5_

- [x] 3. Checkpoint - DOJ API endpoints ready
  - Ensure all tests pass, ask the user if questions arise.

- [x] 4. USMS: Create DojCriminalCaseService
  - [x] 4.1 Create DojCriminalCaseService class
    - Create `usms/app/Services/DojCriminalCaseService.php`
    - Read `DOJ_API_URL` and `DOJ_API_KEY` from environment variables in constructor
    - Throw `RuntimeException` if either env var is missing or empty
    - Set HTTP timeout to 10 seconds
    - Implement `store(array $data): array` method — POST to `/api/criminal-cases`
    - Implement `index(array $filters = []): array` method — GET to `/api/criminal-cases`
    - Implement `show(string $id): array` method — GET to `/api/criminal-cases/{id}`
    - Include headers `Content-Type: application/json` and `X-API-Key` on every request
    - Throw exception on non-2xx responses (include status code and body)
    - Throw exception on connection timeout
    - _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6_

  - [x] 4.2 Implement static mapPrisonerToCase method
    - Add `public static function mapPrisonerToCase(UserPrison $prisoner): array` to DojCriminalCaseService
    - Map: `suspect.nama` → `accused_name`, `prison.cid` → `cid_no`, `bail_out` → `bail_amount`
    - Map: `penal_code[].name` → `decision` (comma-joined)
    - Derive `bail_status`: `bail_out > 0` → "paid", else → "not paid"
    - Set constants: `accused_plea` = "not guilty", `status` = "active", `judge_name` = "", `prosecutor_name` = ""
    - _Requirements: 3.2, 3.3, 3.4, 3.5, 3.6_

  - [x] 4.3 Add DOJ_API_URL and DOJ_API_KEY to USMS .env.example
    - Add `DOJ_API_URL=http://localhost:8001/api` and `DOJ_API_KEY=` entries to `usms/.env.example`
    - _Requirements: 5.2, 5.3_

- [x] 5. USMS: Modify PrisonController to call DOJ API
  - [x] 5.1 Integrate DojCriminalCaseService into PrisonController addPrisoner method
    - After `UserPrison::create(...)` succeeds, load the prisoner with suspect and prison relations
    - Check if `suspect.nama` is non-null and non-empty; if invalid, log and skip API call
    - Call `DojCriminalCaseService::mapPrisonerToCase()` then `$service->store()`
    - Wrap in try/catch: on any `\Throwable`, log error with `Log::error()` including prisoner_id, error message, and timestamp
    - Local save is always preserved regardless of API outcome
    - _Requirements: 3.1, 3.7, 3.8, 3.9_

- [x] 6. Checkpoint - Integration wired end-to-end
  - Ensure all tests pass, ask the user if questions arise.

- [x] 7. DOJ: Write tests for CriminalCase API
  - [x]* 7.1 Write property test: Store Round-Trip (Property 1)
    - **Property 1: Store Round-Trip**
    - Generate random valid payloads (100 iterations with Faker), POST each, assert 201 + `success: true` + all fields present in response including generated `application_no`
    - **Validates: Requirements 1.1, 1.3**

  - [x]* 7.2 Write property test: Application Number Format and Sequencing (Property 2)
    - **Property 2: Application Number Format and Sequencing**
    - Create N sequential cases, assert each `application_no` matches `CT-CR-{YYYY}-{XXXX}` and increments by 1
    - **Validates: Requirements 1.2**

  - [x]* 7.3 Write property test: Validation Rejection (Property 3)
    - **Property 3: Validation Rejection**
    - Generate random invalid payloads (missing required, exceeding max length, invalid enum, negative bail, malformed date), assert 422 + `success: false` + `errors` object
    - **Validates: Requirements 1.4, 1.6**

  - [x]* 7.4 Write property test: Index Ordering (Property 6)
    - **Property 6: Index Ordering**
    - Insert random cases with varying timestamps, GET index, assert results ordered by `created_at` descending
    - **Validates: Requirements 4.1**

  - [x]* 7.5 Write property test: Filter by cid_no partial match (Property 7)
    - **Property 7: Filter by cid_no (Partial, Case-Insensitive)**
    - Insert cases with random cid_no values, filter with substring, assert all results contain the filter value (case-insensitive)
    - **Validates: Requirements 4.2**

  - [x]* 7.6 Write property test: Filter by accused_name partial match (Property 8)
    - **Property 8: Filter by accused_name (Partial, Case-Insensitive)**
    - Insert cases with random names, filter with substring, assert all results contain the filter value (case-insensitive)
    - **Validates: Requirements 4.3**

  - [x]* 7.7 Write property test: Filter by status exact match (Property 9)
    - **Property 9: Filter by status (Exact Match)**
    - Insert cases with various statuses, filter by one valid status, assert all results have that exact status
    - **Validates: Requirements 4.4**

  - [x]* 7.8 Write property test: Show Lookup by ID or cid_no (Property 10)
    - **Property 10: Show Lookup by ID or cid_no**
    - Create random cases, lookup by numeric ID and by cid_no, assert both return the same complete data
    - **Validates: Requirements 6.1, 6.2**

  - [x]* 7.9 Write unit tests for auth middleware and edge cases
    - Test: no API key → 401
    - Test: wrong API key → 401
    - Test: valid API key → passes through
    - Test: show non-existent ID → 404
    - Test: invalid status filter → returns all results
    - **Validates: Requirements 2.1, 2.2, 2.3, 4.7, 6.3**

- [x] 8. USMS: Write tests for DojCriminalCaseService and PrisonController integration
  - [x]* 8.1 Write property test: Data Mapping Transformation (Property 4)
    - **Property 4: Data Mapping Transformation**
    - Generate random UserPrison records with suspects and prisons, assert mapping produces correct `accused_name`, `cid_no`, `bail_amount`, and `decision`
    - **Validates: Requirements 3.2**

  - [x]* 8.2 Write property test: Bail Status Derivation (Property 5)
    - **Property 5: Bail Status Derivation**
    - Generate random `bail_out` values (0, null, positive), assert `bail_status` is "paid" when > 0, "not paid" otherwise
    - **Validates: Requirements 3.3**

  - [x]* 8.3 Write property test: Non-2xx Response Throws Exception (Property 11)
    - **Property 11: Non-2xx Response Throws Exception**
    - Mock DOJ API with random 4xx/5xx status codes, assert `DojCriminalCaseService` throws exception with status code and body
    - **Validates: Requirements 5.5**

  - [x]* 8.4 Write unit tests for service configuration and PrisonController integration
    - Test: missing DOJ_API_URL → RuntimeException
    - Test: missing DOJ_API_KEY → RuntimeException
    - Test: API failure (mock 500) → local UserPrison data preserved
    - Test: API timeout (mock) → local UserPrison data preserved
    - Test: null suspect name → no HTTP request sent, log written
    - Test: default values (accused_plea, status, judge_name) set correctly
    - **Validates: Requirements 5.2, 5.3, 3.7, 3.8, 3.9, 3.4, 3.5, 3.6**

- [x] 9. Final checkpoint - All tests pass
  - Ensure all tests pass, ask the user if questions arise.

## Notes

- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- Unit tests validate specific examples and edge cases
- DOJ test file: `DOJ/tests/Feature/Api/CriminalCaseApiTest.php`
- USMS test files: `usms/tests/Unit/Services/DojCriminalCaseServiceTest.php` and `usms/tests/Feature/PrisonControllerDojIntegrationTest.php`
- The existing `ApiKeyMiddleware` in DOJ handles all auth logic — no changes needed there
- The existing `DojChargeService` in USMS serves as a pattern reference for the new service class

## Task Dependency Graph

```json
{
  "waves": [
    { "id": 0, "tasks": ["1.1", "4.3"] },
    { "id": 1, "tasks": ["1.2", "4.1"] },
    { "id": 2, "tasks": ["2.1", "2.2", "4.2"] },
    { "id": 3, "tasks": ["5.1"] },
    { "id": 4, "tasks": ["7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.1", "8.2", "8.3", "8.4"] }
  ]
}
```
