# Product Requirements Document (PRD) - Sistem Keuangan Warung

**Version:** 1.0.0  
**Status:** Approved for MVP Development  
**Author:** Senior Product Manager & Software Architect  
**Target Platform:** Web Application (PHP Vanilla MVC + Tailwind CSS + MySQL)  

---

## 1. Project Overview

### 1.1 Latar Belakang
Warung atau usaha mikro-kecil seringkali mengalami kesulitan dalam merekap keuangan harian secara rapi, memisahkan modal belanja dari keuntungan, serta menghitung pembagian keuntungan (bagi hasil) secara akurat antara pemilik modal (investor/pemilik saham) dan operator (penjual). Pencatatan manual bertumpu pada kertas berisiko hilang, salah hitung, dan tidak transparan. 

Oleh karena itu, dibutuhkan sebuah aplikasi web keuangan warung yang sederhana, intuitif, dan otomatis. Sistem ini memungkinkan admin hanya perlu mencatat data transaksi harian, sedangkan seluruh kalkulasi rekap bulanan hingga pembagian keuntungan dihitung otomatis oleh sistem.

### 1.2 Tujuan Aplikasi
- Menyediakan platform pencatatan transaksi (Pemasukan, Belanja Barang, Pengeluaran Operasional) yang cepat dan responsif.
- Mengotomatisasi kalkulasi keuangan: **Keuntungan Bersih = Total Pemasukan - (Total Belanja + Tips) - Pengeluaran Lainnya**.
- Menyediakan rekapitulasi otomatis secara harian, bulanan, dan tahunan.
- Mengelola pembagian keuntungan transparan berbasis persentase bagi hasil yang fleksibel.
- Menyediakan fitur ekspor laporan keuangan ke format Excel (.xlsx / .csv) dan PDF.

### 1.3 Target Pengguna & Role-Based Access Control (RBAC)

| Role | Deskripsi Hak Akses | Akses Fitur |
| :--- | :--- | :--- |
| **Admin** | Pengelola utama warung / Kasir | Full Access (CRUD transaksi, upload bukti bon, kelola stakeholder, atur persentase bagi hasil, ekspor laporan). |
| **View** | Pemilik Saham / Investor / Auditor | Read-Only Access (Melihat Dashboard, Grafik Rekap, Laporan Bulanan, dan Rincian Nominal Pembagian Keuntungan). |

---

## 2. Core Features (MVP)

Sistem dirancang mengutamakan kemudahan operasional. Admin hanya berfokus pada **Input Data Transaksi**, sementara seluruh kalkulasi dan agregasi dieksekusi secara otomatis oleh engine backend.

### 2.1 Modul Input Transaksi (Admin Only)

#### A. Pemasukan Harian
Pencatatan total omzet / penjualan harian warung.
- **Form Fields:**
  - Tanggal (`date`, default: hari ini)
  - Jumlah Pemasukan (`decimal/currency`, wajib, > 0)
  - Keterangan (`text`, opsional)

#### B. Belanja Barang
Pencatatan pengeluaran modal belanja stok barang warung.
- **Form Fields:**
  - Tanggal (`date`, default: hari ini)
  - Nilai Belanja (`decimal/currency`, wajib, > 0)
  - Tips (`decimal/currency`, opsional, default: 0) - *Catatan: Tips dihitung sebagai penambah biaya belanja/operasional.*
  - Upload Bukti Bon (`file`: JPG, PNG, PDF; Max size: 2MB)
  - Keterangan (`text`, opsional)

#### C. Pengeluaran Lainnya
Pencatatan biaya operasional non-stok (misal: listrik, air, retribusi kebersihan, sewa tempat, perbaikan alat).
- **Form Fields:**
  - Tanggal (`date`, default: hari ini)
  - Kategori (`dropdown`: Listrik & Air, Kebersihan & Retribusi, Perbaikan/Maintenance, Lain-lain)
  - Nominal (`decimal/currency`, wajib, > 0)
  - Upload Bukti (`file`: JPG, PNG, PDF; Max size: 2MB; opsional)
  - Keterangan (`text`, opsional)

---

### 2.2 Automasi Perhitungan & Logic Bisnis

Sistem secara otomatis mengeksekusi agregasi real-time:

$$	ext{Keuntungan Bersih} = 	ext{Total Pemasukan} - (	ext{Total Belanja} + 	ext{Total Tips}) - 	ext{Total Pengeluaran Lainnya}$$

#### Alur Data Utama (System Data Flow):
```text
[ Input Pemasukan Harian ] ──┐
[ Input Belanja Barang   ] ──┼─► [ Agregasi Rekap Harian/Bulanan ] ─► [ Kalkulasi Keuntungan Bersih ] ─► [ Pembagian Bagi Hasil (100%) ] ─► [ Dashboard & Laporan (PDF/Excel) ]
[ Input Pengeluaran Lain ] ──┘
```

---

### 2.3 Modul Pengaturan Bagi Hasil (CRUD Stakeholder)
Sistem pembagian keuntungan mengalokasikan Keuntungan Bersih bulanan berdasarkan persentase yang dikonfigurasi pada menu **Pengaturan**.

- **Entitas Stakeholder:**
  - Nama Stakeholder (misal: "Bapak Ahmad (Pemilik Saham)", "Budi (Operator)")
  - Peran (`enum`: Pemilik Saham / Operator Penjualan)
  - Persentase Bagi Hasil (`decimal`, 0.00% - 100.00%)
- **Aturan Validasi Pengaturan:**
  - Total persentase dari **seluruh stakeholder aktif WAJIB tepat 100%**.
  - Jika total persentase $
eq 100\%$, sistem akan menolak penyimpanan form dan menampilkan pesan error.

---

### 2.4 Dashboard (Admin & View)
Tampilan visual utama yang menyajikan ringkasan keuangan terkini (Bulan Berjalan):
1. **Summary Cards Metrics:**
   - Total Pemasukan
   - Total Belanja (termasuk Tips)
   - Total Pengeluaran Lainnya
   - **Keuntungan Bersih** (Highlight hijau jika positif, merah jika defisit)
2. **Tabel & Grafik Ringkasan:**
   - Bar Chart / Trend Line: Pemasukan vs Pengeluaran 30 hari terakhir.
   - Pie Chart: Breakdown Pengeluaran per Kategori.
3. **Tabel Pembagian Keuntungan (Bagi Hasil):**
   - Menampilkan daftar nama stakeholder, persentase hak, dan **nominal Rupiah yang didapat** dari Keuntungan Bersih bulan berjalan.

---

### 2.5 Modul Laporan & Ekspor (Admin & View)
- **Filter Periode:** Rentang Tanggal (Start Date - End Date), Month-Year Picker, Quick Presets (Bulan Ini, Bulan Lalu, Tahun Ini).
- **Rekapitulasi Tabel:** Rincian pemasukan, pengeluaran, belanja, serta histori bukti transaksi (link preview image/PDF).
- **Fitur Ekspor:**
  - **Export to Excel (.xlsx/.csv):** Spreadsheet rapi berisi sheet rekap transaksi dan sheet rincian pembagian hasil.
  - **Export to PDF:** Laporan cetak format A4 dengan tata letak bersih dan profesional.

---

## 3. Tech Stack & Server Configuration

### 3.1 Technology Stack
- **Backend:** PHP Vanilla (PHP 8.1+) - Native MVC Architecture tanpa heavy framework (Laravel/CodeIgniter).
- **Frontend:** HTML5, Tailwind CSS (via CDN atau compiled CLI), Vanilla JavaScript / Alpine.js (untuk interaktivitas ringan modal/dropdown).
- **Database:** MySQL 8.0+ / MariaDB (Driver: **PDO** dengan Prepared Statements mandatory).
- **Web Server:** Apache (menggunakan `mod_rewrite` diaktifkan).

---

### 3.2 Web Server & Routing Configuration (`.htaccess`)

Aplikasi menerapkan arsitektur **Front Controller Pattern** di mana seluruh HTTP request diteruskan ke `public/index.php`.

#### 1. File Root `.htaccess` (`/.htaccess`)
Mengarahkan traffic dari root domain/subfolder langsung ke folder `/public`.

```apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^$ public/ [L]
    RewriteRule (.*) public/$1 [L]
</IfModule>
```

#### 2. File Public `.htaccess` (`/public/.htaccess`)
Menangani URL bersih (*Clean URLs*), mengarahkan request ke `index.php?url=$1`, dan menerapkan proteksi keamanan server-side.

```apache
<IfModule mod_rewrite.c>
    Options -Indexes
    RewriteEngine On

    # Prevent access to hidden files (.env, .git, etc.)
    RewriteRule ^\.(.*)$ - [F,L]

    # Serve static assets directly if file or directory exists
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # Route all requests to Front Controller
    RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

# Security Headers
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "SAMEORIGIN"
    Header set X-XSS-Protection "1; mode=block"
</IfModule>
```

---

### 3.3 Database Configuration (`config/database.php`)

Spesifikasi file koneksi PDO yang aman, mengacu pada skema tabel di `database.sql`.

```php
<?php
/**
 * Database Connection Configuration (PDO Native)
 */

class Database {
    private string $host = "localhost";
    private string $db_name = "warung_keuangan";
    private string $username = "root";
    private string $password = "";
    private string $charset = "utf8mb4";
    private ?PDO $conn = null;

    public function getConnection(): ?PDO {
        if ($this->conn !== null) {
            return $this->conn;
        }

        $dsn = "mysql:host={$this->host};dbname={$this->db_name};charset={$this->charset}";
        $options = [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false, // Mandatory for security against SQL Injection
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES {$this->charset}"
        ];

        try {
            $this->conn = new PDO($dsn, $this->username, $this->password, $options);
        } catch (PDOException $e) {
            error_log("Database Connection Error: " . $e->getMessage());
            die(json_encode([
                'status' => false,
                'message' => 'Gagal terhubung ke database. Silakan periksa konfigurasi server.'
            ]));
        }

        return $this->conn;
    }
}
```

---

## 4. Architecture, Folder Structure & Data Flow

### 4.1 Directory & Folder Structure

```text
warung-keuangan/
├── app/
│   ├── Controllers/          # Controller Classes (Handles Requests & Business Logic)
│   │   ├── AuthController.php
│   │   ├── DashboardController.php
│   │   ├── PemasukanController.php
│   │   ├── BelanjaController.php
│   │   ├── PengeluaranController.php
│   │   ├── StakeholderController.php
│   │   ├── SettingsController.php
│   │   └── ReportController.php
│   ├── Models/               # Model Classes (Database Queries via PDO)
│   │   ├── User.php
│   │   ├── Pemasukan.php
│   │   ├── Belanja.php
│   │   ├── Pengeluaran.php
│   │   └── Stakeholder.php
│   ├── Views/                # UI Templates (HTML + Tailwind CSS)
│   │   ├── layouts/
│   │   │   ├── header.php
│   │   │   ├── footer.php
│   │   │   └── sidebar.php
│   │   ├── auth/
│   │   │   └── login.php
│   │   ├── dashboard/
│   │   │   └── index.php
│   │   ├── pemasukan/
│   │   ├── belanja/
│   │   ├── pengeluaran/
│   │   ├── stakeholder/
│   │   └── report/
│   ├── Core/                 # System Core Framework
│   │   ├── App.php           # Router Parsing URL
│   │   ├── Controller.php    # Base Controller
│   │   ├── Database.php      # Base DB Access Wrapper
│   │   └── Router.php        # Route Definitions
│   └── Helpers/              # Security & Utility Functions
│       ├── AuthHelper.php    # Session & RBAC verification
│       ├── SecurityHelper.php# CSRF & XSS sanitization
│       └── FormatHelper.php  # Currency & Date Formatters
├── config/
│   └── database.php          # Database Parameters
├── public/
│   ├── assets/
│   │   ├── css/
│   │   │   └── style.css
│   │   └── js/
│   │       └── main.js
│   ├── uploads/              # Storage Bukti Bon (Bon Belanja / Pengeluaran)
│   │   └── .htaccess         # Prevent execution of scripts in uploads
│   ├── .htaccess             # Public Rewrite Rules
│   └── index.php             # Front Controller Entry Point
├── .htaccess                 # Root Redirect to /public
├── database.sql              # Database Schema & Initial Data
└── PRD.md                    # Product Requirements Document
```

---

### 4.2 Data Flow Logic

1. **User Request:** User membuka URL `/belanja/store` via form submit (`POST`).
2. **Front Controller:** `public/index.php` menangkap request dan menginisialisasi `app/Core/App.php`.
3. **Routing:** Router memetakan URL `/belanja/store` ke `BelanjaController->store()`.
4. **Middleware Security Check:**
   - `AuthHelper::requireAdmin()` memeriksa apakah user terautentikasi dan ber-role Admin.
   - `SecurityHelper::validateCSRF()` memvalidasi token CSRF dari form submit.
5. **Business Logic & Validation:** `BelanjaController` melakukan validasi server-side input (tanggal, nominal, sanitize text, upload file bon).
6. **Model Execution:** `BelanjaController` memanggil `BelanjaModel->create($data)` yang mengeksekusi `PDO Prepared Statement`.
7. **Response / Redirect:** Controller menetapkan `flash_message` dan meredirect browser kembali ke `/belanja` (View).

---

## 5. Design & UI/UX Guidelines

Sistem menggunakan desain clean, intuitif, dan *mobile-first responsive* agar nyaman diakses melalui smartphone kasir/admin maupun laptop pemilik warung.

### 5.1 Color Palette
- **Primary Base White:** `#FFFFFF` (Latar belakang utama, card surface, kebersihan visual).
- **Primary Accent Teal:** `#34A99D` (Tombol utama, badge positif, toggle aktif, highlight visual).
- **Deep Teal Header/Sidebar:** `#007979` (Topbar, Sidebar navigation, Header tabel, aksen kontras tinggi).
- **Text & Neutral Colors:**
  - Dark Text: `#1E293B` (Slate-800 - Keterbacaan teks utama)
  - Muted Text: `#64748B` (Slate-500 - Label & sub-informasi)
  - Card Background: `#F8FAFC` (Slate-50 - Background sekunder)
- **Status Indicators:**
  - Success/Profit: `#10B981` (Green-500)
  - Danger/Expense: `#EF4444` (Red-500)
  - Warning/Alert: `#F59E0B` (Amber-500)

### 5.2 Responsive Layout Structure
- **Mobile View (< 768px):** Sidebar disembunyikan dalam tombol *Hamburger Menu*. Card ringkasan disusun 1 kolom secara vertikal. Tabel dilengkapi *horizontal overflow scroll*.
- **Desktop View (≥ 768px):** Fixed Sidebar kiri (Warna `#007979`), Topbar untuk profil user, dan Grid 4 kolom untuk Summary Cards Dashboard.

---

## 6. Security Requirements

Sistem WAJIB mematuhi standar keamanan aplikasi web berikut:

### 6.1 Autentikasi & Authorization (RBAC)
- Password disimpan dengan hashing kuat menggunakan `password_hash($password, PASSWORD_ARGON2ID)` atau `PASSWORD_BCRYPT`.
- Sesi dikelola dengan aman: `session_start()` dengan opsi `cookie_httponly = true`, `cookie_samesite = 'Lax'`.
- Penjagaan Route: User dengan role `View` secara otomatis ditolak jika mencoba mengakses URI mutasi data (POST/PUT/DELETE) via HTTP status `403 Forbidden`.

### 6.2 SQL Injection Prevention
- Dilarang keras melakukan penggabungan string (concatenation) variabel user pada query SQL.
- Seluruh query database harus menggunakan PDO Prepared Statements:
```php
$stmt = $pdo->prepare("INSERT INTO belanja (tanggal, nilai_belanja, tips, keterangan) VALUES (:tanggal, :nilai, :tips, :keterangan)");
$stmt->execute([
    ':tanggal'    => $clean_tanggal,
    ':nilai'      => $clean_nilai,
    ':tips'       => $clean_tips,
    ':keterangan' => $clean_keterangan
]);
```

### 6.3 Cross-Site Scripting (XSS) Prevention
- Setiap variabel yang dicetak pada file View wajib di-escape menggunakan helper function `e()`:
```php
function e($value) {
    return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8');
}
```

### 6.4 Cross-Site Request Forgery (CSRF) Prevention
- Setiap form HTML yang melakukan mutasi data (`POST`) wajib menyertakan input hidden token CSRF:
```html
<input type="hidden" name="csrf_token" value="<?php echo SecurityHelper::generateCSRFToken(); ?>">
```
- Server wajib memvalidasi token sebelum memproses request `POST`.

### 6.5 Safe File Uploads (Bukti Bon)
- Sanitasi nama file menggunakan `bin2hex(random_bytes(16))` + ekstensi asli.
- Restriksi MIME type: `image/jpeg`, `image/png`, `application/pdf`.
- Blokir eksekusi script di folder `/public/uploads/` dengan menambahkan file `.htaccess`:
```apache
<FilesMatch "\.(php|php5|phtml|sh|cgi)$">
    Order allow,deny
    Deny from all
</FilesMatch>
```

---

## 7. Out of Scope (Non-MVP)

Fitur-fitur berikut berada **di luar ruang lingkup (Out of Scope)** pengkodean MVP saat ini:
- Sistem Kasir / Point of Sale (POS) dengan pemindaian barcode item per item.
- Inventarisasi Stok Barang (Stock In / Stock Out / Opname Barang).
- Integrasi Printer Thermal / Cetak Struk Belanja.
- Penggajian Karyawan / Payroll Kompleks.
- Multi-Cabang / Multi-Tenant Database.
- Integrasi Payment Gateway & Notifikasi WhatsApp/Email API.