# API Design - Laporan Keuangan Masjid

Base URL: `/api/masjid/{masjid_id}/laporan`

---

## 1. Ringkasan Keuangan
    
**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/ringkasan`

**Query Parameters:**
- `periode` (optional): YYYY-MM (default: bulan ini)

**Response Codes:**
- `200 OK` - Sukses
- `400 Bad Request` - Format periode invalid
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "ringkasan_keuangan",
  "data": {
    "periode": "2026-02",
    "total_pemasukan": 15000000,
    "total_pengeluaran": 8500000,
    "saldo_akhir": 6500000,
    "jumlah_transaksi": 45
  }
}
```

**Error Response (404):**
```json
{
  "type": "error",
  "message": "Masjid tidak ditemukan",
  "code": "MASJID_NOT_FOUND"
}
```

---

## 2. List Transaksi (dengan Pagination)

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/transaksi`

**Query Parameters:**
- `page` (optional): default 1
- `per_page` (optional): 1-100 (default: 20)
- `tanggal_mulai` (optional): YYYY-MM-DD
- `tanggal_selesai` (optional): YYYY-MM-DD
- `jenis` (optional): pemasukan|pengeluaran
- `kategori_id` (optional): filter by kategori
- `sort_by` (optional): tanggal|nominal (default: tanggal)
- `sort_order` (optional): asc|desc (default: desc)

**Response Codes:**
- `200 OK` - Sukses
- `400 Bad Request` - Query parameter invalid
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "list_transaksi",
  "data": [
    {
      "id": 1,
      "tanggal": "2026-02-07",
      "jenis": "pemasukan",
      "kategori": {
        "id": 5,
        "nama": "Infaq Jumat"
      },
      "nominal": 500000,
      "keterangan": "Infaq Jumat minggu pertama"
    },
    {
      "id": 2,
      "tanggal": "2026-02-06",
      "jenis": "pengeluaran",
      "kategori": {
        "id": 3,
        "nama": "Listrik"
      },
      "nominal": 350000,
      "keterangan": "Bayar listrik bulan Januari"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 45,
    "last_page": 3
  }
}
```

**Error Response (400):**
```json
{
  "type": "error",
  "message": "Parameter sort_by tidak valid",
  "code": "INVALID_SORT_PARAMETER"
}
```

---

## 3. Detail Transaksi

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/transaksi/{id}`

**Response Codes:**
- `200 OK` - Sukses
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Transaksi atau masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "detail_transaksi",
  "data": {
    "id": 1,
    "tanggal": "2026-02-07",
    "jenis": "pemasukan",
    "kategori": {
      "id": 5,
      "nama": "Infaq Jumat"
    },
    "nominal": 500000,
    "keterangan": "Infaq Jumat minggu pertama",
    "bukti_url": "https://example.com/storage/bukti/001.jpg",
    "dibuat_oleh": "Ahmad Takmir",
    "dibuat_pada": "2026-02-07T10:30:00Z",
    "diperbarui_pada": "2026-02-07T10:30:00Z"
  }
}
```

**Error Response (404):**
```json
{
  "type": "error",
  "message": "Transaksi tidak ditemukan",
  "code": "TRANSAKSI_NOT_FOUND"
}
```

---

## 4. Rekap Bulanan

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/rekap-bulanan`

**Query Parameters:**
- `tahun` (optional): YYYY (default: tahun ini)

**Response Codes:**
- `200 OK` - Sukses
- `400 Bad Request` - Format tahun invalid
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "rekap_bulanan",
  "data": {
    "tahun": 2026,
    "bulan": [
      {
        "bulan": 1,
        "nama_bulan": "Januari",
        "total_pemasukan": 12000000,
        "total_pengeluaran": 7500000,
        "saldo": 4500000
      },
      {
        "bulan": 2,
        "nama_bulan": "Februari",
        "total_pemasukan": 15000000,
        "total_pengeluaran": 8500000,
        "saldo": 6500000
      }
    ],
    "total_tahun": {
      "total_pemasukan": 27000000,
      "total_pengeluaran": 16000000,
      "saldo_akhir": 11000000
    }
  }
}
```

**Error Response (400):**
```json
{
  "type": "error",
  "message": "Format tahun tidak valid",
  "code": "INVALID_YEAR_FORMAT"
}
```

---

## 5. Saldo Terkini

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/saldo`

**Response Codes:**
- `200 OK` - Sukses
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "saldo_terkini",
  "data": {
    "saldo_kas": 6500000,
    "saldo_bank": 15000000,
    "total_saldo": 21500000,
    "terakhir_diperbarui": "2026-02-07T14:30:00Z"
  }
}
```

**Error Response (404):**
```json
{
  "type": "error",
  "message": "Masjid tidak ditemukan",
  "code": "MASJID_NOT_FOUND"
}
```

---

## 6. List Kategori

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/kategori`

**Query Parameters:**
- `jenis` (optional): pemasukan|pengeluaran
- `sort_by` (optional): nama|total_nominal (default: nama)
- `sort_order` (optional): asc|desc (default: asc)

**Response Codes:**
- `200 OK` - Sukses
- `400 Bad Request` - Query parameter invalid
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "list_kategori",
  "data": [
    {
      "id": 1,
      "nama": "Infaq Jumat",
      "jenis": "pemasukan",
      "total_transaksi": 8,
      "total_nominal": 4000000
    },
    {
      "id": 2,
      "nama": "Donasi",
      "jenis": "pemasukan",
      "total_transaksi": 15,
      "total_nominal": 7500000
    },
    {
      "id": 3,
      "nama": "Listrik",
      "jenis": "pengeluaran",
      "total_transaksi": 1,
      "total_nominal": 350000
    },
    {
      "id": 4,
      "nama": "Air",
      "jenis": "pengeluaran",
      "total_transaksi": 1,
      "total_nominal": 150000
    }
  ]
}
```

**Error Response (400):**
```json
{
  "type": "error",
  "message": "Parameter jenis tidak valid",
  "code": "INVALID_JENIS_PARAMETER"
}
```

---

## Bonus: Export Laporan

**Endpoint:** `GET /api/masjid/{masjid_id}/laporan/export`

**Query Parameters:**
- `format`: pdf|excel (required)
- `tanggal_mulai`: YYYY-MM-DD (required)
- `tanggal_selesai`: YYYY-MM-DD (required)
- `jenis` (optional): pemasukan|pengeluaran

**Response Codes:**
- `200 OK` - Sukses
- `400 Bad Request` - Query parameter invalid
- `401 Unauthorized` - Token tidak valid
- `403 Forbidden` - Tidak punya akses ke masjid ini
- `404 Not Found` - Masjid tidak ditemukan
- `422 Unprocessable Entity` - Validasi parameter gagal
- `500 Internal Server Error` - Server error

**Success Response (200):**
```json
{
  "type": "export_laporan",
  "data": {
    "file_url": "https://example.com/storage/exports/laporan_2026-02.pdf",
    "file_name": "laporan_keuangan_2026-02.pdf",
    "expires_at": "2026-02-08T14:30:00Z"
  }
}
```

**Error Response (422):**
```json
{
  "type": "error",
  "message": "Tanggal mulai harus lebih kecil dari tanggal selesai",
  "code": "INVALID_DATE_RANGE"
}
```

---

## HTTP Status Codes

Semua endpoint menggunakan status code standar:

| Code | Status | Keterangan |
|------|--------|------------|
| 200 | OK | Request berhasil |
| 400 | Bad Request | Query parameter invalid |
| 401 | Unauthorized | Token tidak valid atau expired |
| 403 | Forbidden | User tidak punya akses ke resource |
| 404 | Not Found | Resource tidak ditemukan |
| 422 | Unprocessable Entity | Validasi data gagal |
| 500 | Internal Server Error | Error di server |

---

## Error Response Format

Semua error menggunakan format konsisten:

```json
{
  "type": "error",
  "message": "Deskripsi error yang human-readable",
  "code": "ERROR_CODE_UPPERCASE"
}
```

**Error Codes:**
- `MASJID_NOT_FOUND` - Masjid tidak ditemukan
- `TRANSAKSI_NOT_FOUND` - Transaksi tidak ditemukan
- `INVALID_SORT_PARAMETER` - Parameter sort tidak valid
- `INVALID_JENIS_PARAMETER` - Parameter jenis tidak valid
- `INVALID_YEAR_FORMAT` - Format tahun tidak valid
- `INVALID_DATE_RANGE` - Range tanggal tidak valid
- `UNAUTHORIZED_ACCESS` - Tidak punya akses
- `INVALID_TOKEN` - Token tidak valid

---

## Notes

1. Semua endpoint memerlukan autentikasi (Bearer Token)
2. User harus punya akses ke masjid yang diminta
3. Tanggal menggunakan format ISO 8601 (YYYY-MM-DD)
4. Timestamp menggunakan format ISO 8601 dengan timezone UTC (YYYY-MM-DDTHH:mm:ssZ)
5. Untuk keperluan display, konversi timezone ke Asia/Jakarta (UTC+7)
6. Nominal dalam satuan Rupiah (IDR) tanpa desimal
7. Semua nilai nominal adalah integer positif
8. Pagination default: 20 items per page, maksimal 100 items per page
9. Transaksi menggunakan soft delete untuk menjaga integritas data historis
10. Semua perubahan transaksi dicatat di audit log untuk keperluan audit keuangan
