diff --git a/README.md b/README.md index 6851ea9..d699447 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,360 @@ -
+# Asset Management System - + -## About Laravel +Sistem Manajemen Aset berbasis Laravel untuk pencatatan aset fisik end-to-end: **registrasi aset + identifikasi (QR/RFID/NFC), movement, disposal + reverse, maintenance, audit/stocktake, approval workflow, laporan (Excel/PDF), changelog, dan pengaturan sistem berbasis database**. -Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: +Project ini dibuat dengan fokus pada **best practice**, **clean code**, dan siap untuk dikembangkan menjadi open-source. -- [Simple, fast routing engine](https://laravel.com/docs/routing). -- [Powerful dependency injection container](https://laravel.com/docs/container). -- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. -- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). -- Database agnostic [schema migrations](https://laravel.com/docs/migrations). -- [Robust background job processing](https://laravel.com/docs/queues). -- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). +## Daftar Isi -Laravel is accessible, powerful, and provides tools required for large, robust applications. +- [Fitur Utama](#fitur-utama) +- [Arsitektur Singkat](#arsitektur-singkat) +- [Kebutuhan Sistem](#kebutuhan-sistem) +- [Quick Start (Local Development)](#quick-start-local-development) +- [Setup Wizard (First Run)](#setup-wizard-first-run) +- [Akun Default (Sample Data)](#akun-default-sample-data) +- [RBAC (Role & Permission)](#rbac-role--permission) +- [System Settings (Database-driven)](#system-settings-database-driven) +- [Identifikasi Aset (QR/RFID/NFC)](#identifikasi-aset-qrrfidnfc) +- [Transaksi Aset](#transaksi-aset) +- [Approval Workflow](#approval-workflow) +- [Authentication, 2FA, Session Timeout](#authentication-2fa-session-timeout) +- [Audit Trail & Logging](#audit-trail--logging) +- [Import/Export Aset](#importexport-aset) +- [Laporan (Excel & PDF)](#laporan-excel--pdf) +- [Landing Page & Public Asset View (QR Scan)](#landing-page--public-asset-view-qr-scan) +- [Notifikasi Email (SMTP)](#notifikasi-email-smtp) +- [Notifikasi Terjadwal (Command)](#notifikasi-terjadwal-command) +- [Maintenance Mode (Read-only)](#maintenance-mode-read-only) +- [Testing](#testing) +- [Deployment Notes](#deployment-notes) +- [Contributing](#contributing) -## Learning Laravel +## Fitur Utama -Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. +**1) User Management + RBAC (Spatie Permission)** +- Role & permission berbasis UUID +- Pembatasan akses per modul melalui middleware `permission:*` -You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. +**2) Master Data** +- Status Aset, Kelas Aset, Unit, Departemen, Person in Charge, Pengguna Aset, Kategori, Lokasi, Warranty, Vendor Contract -If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. +**3) Manajemen Aset** +- Registrasi aset dengan kode otomatis +- Foto/thumbnail aset (multi foto) tersimpan di storage +- QR code otomatis menuju halaman publik detail aset (tanpa login) +- RFID/NFC tag (opsional + bisa auto-generate via setting) +- Arsip/retensi + soft delete + restore -## Laravel Sponsors +**4) Transaksi Aset** +- Movement (mutasi lokasi/departemen/user) +- Disposal + Reverse Disposal +- Audit/Stocktake +- Maintenance (planned/in_progress/completed + dukungan flow approval `pending`) -We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). +**5) Approval Workflow** +- Permintaan approval untuk movement/disposal/maintenance (pending/approved/rejected) +- Halaman approvals untuk approver -### Premium Partners +**6) Laporan** +- Export Excel (multi sheet) + PDF untuk aset dan transaksi +- Filter laporan (date range, lokasi, dsb.) sesuai halaman laporan -- **[Vehikl](https://vehikl.com/)** -- **[Tighten Co.](https://tighten.co)** -- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** -- **[64 Robots](https://64robots.com)** -- **[Curotec](https://www.curotec.com/services/technologies/laravel/)** -- **[DevSquad](https://devsquad.com/hire-laravel-developers)** -- **[Redberry](https://redberry.international/laravel-development/)** -- **[Active Logic](https://activelogic.com)** +**7) Landing & Dokumentasi** +- Landing one-page untuk memperkenalkan sistem +- Public asset view untuk QR scan: `GET /asset-view/{asset}` +- Dokumentasi API internal app: `GET /api-docs` + +## Arsitektur Singkat + +- **Framework:** Laravel +- **Template UI:** Vyzor (Bootstrap) +- **Settings:** disimpan di tabel `settings` dan diakses melalui `App\Services\System\SystemSettingService` +- **Audit log:** file log khusus channel `asset_activity` (bukan database) +- **UUID:** hampir seluruh tabel inti menggunakan UUID sebagai primary key + +Folder penting: +- `app/Services/` → business logic (tanpa repository pattern) +- `app/Http/Controllers/` → controller tipis, delegasi ke service +- `database/seeders/` → sample data +- `resources/views/` → Blade UI + +## Kebutuhan Sistem + +- PHP 8.2+ (sesuaikan dengan `composer.json`) +- Composer +- Node.js + NPM (Vite build) +- Database: MySQL/MariaDB (production) / SQLite (testing) +- (Opsional) Laragon untuk dev di Windows + +## Quick Start (Local Development) + +1) Install dependency PHP & JS +```bash +composer install +npm install +``` + +2) Siapkan `.env` +```bash +cp .env.example .env +php artisan key:generate +``` + +3) Jalankan Vite +```bash +npm run dev +``` + +4) Jalankan aplikasi +```bash +php artisan serve +``` + +5) Buat symbolic link storage (wajib untuk foto aset & QR) +```bash +php artisan storage:link +``` + +## Setup Wizard (First Run) + +Saat aplikasi pertama kali dijalankan dan **koneksi database belum siap**, middleware akan mengarahkan ke wizard: +- `GET /setup` + +Wizard terdiri dari 2 tahap besar: + +1) **Database Setup** +- Aplikasi akan menampilkan panduan mengisi `.env` (DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD) +- Tombol migrasi tersedia: + - `Migrate & Seed Minimal (RBAC)` → seed `RbacSeeder` + `SettingSeeder` + - `Migrate + Sample Data (Full Seed)` → seed `DatabaseSeeder` + +2) **Wizard Aplikasi (4 langkah)** +- Step 1: buat user admin +- Step 2: isi nilai setting (form dibentuk dari data di tabel `settings`) +- Step 3: buat master data dasar +- Step 4: buat aset pertama (sample) + +## Akun Default (Sample Data) + +Jika memilih **Full Seed**, akun admin default dibuat oleh `database/seeders/RbacSeeder.php`: +- Email: `admin@example.com` +- Password: `password123` + +## RBAC (Role & Permission) + +RBAC memakai `spatie/laravel-permission` yang sudah disesuaikan untuk UUID: +- Primary key role/permission: `uuid` +- Pivot model: `model_uuid` (lihat `config/permission.php`) + +Permission dasar (seed): +- `settings.manage` +- `users.manage`, `roles.manage`, `permissions.manage` +- `assets.view`, `assets.manage` +- `movements.manage`, `disposals.manage`, `audits.manage`, `maintenance.manage` +- `reports.view`, `approvals.manage` + +Role dasar (seed): +- `super-admin`, `asset-manager`, `auditor`, `maintenance`, `viewer` + +Catatan scoping data: +- Model `Asset` memiliki `scopeForUser()` dan `isVisibleTo()` untuk pembatasan berbasis departemen/lokasi. +- (Opsional) Permission `assets.view_all` dapat ditambahkan untuk bypass scoping (lihat `app/Models/Asset.php`). + +## System Settings (Database-driven) + +Setting disimpan di tabel `settings` dan dapat dikelola lewat: +- Dashboard: `GET /dashboard/settings` +- Setup Wizard step 2: `GET /setup?step=2` + +Setting dibaca via `App\Services\System\SystemSettingService`: +- Default berasal dari `config/system.php` +- Nilai DB akan override default + +Contoh setting penting (lihat `database/seeders/SettingSeeder.php`): +- `asset.code_prefix`, `asset.qr_enabled`, `asset.qr_format`, `asset.qr_size` +- `asset.rfid_enabled`, `asset.nfc_enabled`, `asset.rfid_auto_generate`, `asset.nfc_auto_generate` +- `maintenance.readonly_mode` +- `security.audit_log`, `security.session_idle_minutes`, `security.two_factor_enforced` +- `integration.api_key`, `integration.webhook_*` +- `asset.import_*` (import limit/dedupe/default lookup) + +## Identifikasi Aset (QR/RFID/NFC) + +**QR Code** +- Dibuat otomatis saat aset dibuat/di-update (jika `asset.qr_enabled = true`) +- Tersimpan di `storage/app/public/qr/` +- Isi QR mengarah ke public asset view: `route('assets.public.show')` (`/asset-view/{asset}`) + +**RFID/NFC** +- Disimpan sebagai `rfid_tag` dan `nfc_tag` di tabel `assets` +- Bisa diwajibkan (`asset.rfid_required` / `asset.nfc_required`) dan/atau auto-generate (`asset.rfid_auto_generate` / `asset.nfc_auto_generate`) oleh `AssetService`. + +## Transaksi Aset + +1) **Movement** +- Membuat record `asset_movements` +- Jika auto-approve aktif, aset akan ikut berubah: lokasi/departemen/user + +2) **Disposal** +- Membuat record `asset_disposals` +- Jika approved, aset diarahkan ke status `DISPOSED` (jika status ini ada) +- Reverse disposal mengembalikan status/lokasi/departemen sebelumnya + +3) **Audit/Stocktake** +- Membuat record `asset_audits` (matched/missing/damaged) + +4) **Maintenance** +- Membuat record `asset_maintenances` +- Flow status: `pending` (menunggu approval) → `planned` → `in_progress` → `completed` + +## Approval Workflow + +Approval disimpan di tabel `asset_approval_requests` (morph ke movement/disposal/maintenance): +- Status: `pending`, `approved`, `rejected` + +Halaman approvals: +- `GET /dashboard/approvals` (butuh permission `approvals.manage`) + +## Authentication, 2FA, Session Timeout + +**Login/Register** +- Login: `GET /login` / `POST /login` +- Register: `GET /register` / `POST /register` +- Logout: `POST /logout` + +**2FA (TOTP 6 digit)** +- User dapat mengaktifkan 2FA dari menu profile: + - `GET /dashboard/profile` +- Flow login: + - Jika `two_factor_enabled = true`, setelah password benar user akan diarahkan ke: + - `GET /two-factor-challenge` + - User memasukkan 6 digit dari aplikasi authenticator (Google Authenticator/1Password/Authy) melalui: + - `POST /two-factor-challenge` + +**Session Timeout (idle timeout)** +- Middleware `session.timeout` memaksa logout ketika tidak ada aktivitas selama X menit. +- Setting terkait: + - `security.session_idle_minutes` + +## Audit Trail & Logging + +**1) Request Audit (End-to-end)** +- Middleware `audit.request` mencatat request non-GET beserta durasi response. +- Disimpan via `ActivityLogger::audit()`. + +**2) Log Aktivitas Domain** +- Helper: + - `asset_activity_log(...)` + - `asset_request_log(...)` +- Service: `app/Services/Logging/ActivityLogger.php` + +**Output log** +- Channel: `asset_activity` +- Lokasi: `storage/logs/asset-activity.log` (daily rotation) +- ENV yang relevan: + - `ASSET_LOG_FILE`, `ASSET_LOG_LEVEL`, `ASSET_LOG_DAYS` + +## Import/Export Aset + +**Import** +- UI import ada di halaman daftar aset (`/dashboard/assets`) +- Mendukung: + - `Preview` (tanpa menyimpan) + ringkasan create/update/invalid + - `Import` langsung (create/update) + - Gambar dari: + - URL (`image_url`) *(jika `asset.import_allow_remote_images = true`)* + - ZIP upload (`images_zip`) dengan mapping nama file (`image_file`) + +Sample file import tersedia: +- `public/samples/assets_import_sample.csv` + +**Export** +- CSV export (limit 2000 rows) tersedia via route: + - `GET /dashboard/assets-export` + +## Laporan (Excel & PDF) + +Menu laporan: +- `GET /dashboard/reports/assets` +- `GET /dashboard/reports/movements` +- `GET /dashboard/reports/disposals` +- `GET /dashboard/reports/audits` + +Export: +- Excel: multi-sheet (termasuk relasi utama) +- PDF: layout khusus report + +## Landing Page & Public Asset View (QR Scan) + +Landing: +- `GET /` atau `GET /landing` + +Public asset view (tanpa login): +- `GET /asset-view/{asset}` + +Transaksi dari halaman public (wajib login + permission terkait): +- Movement: `POST /asset-view/{asset}/movement` +- Disposal: `POST /asset-view/{asset}/disposal` +- Maintenance: `POST /asset-view/{asset}/maintenance` + +## Notifikasi Email (SMTP) + +Notifikasi saat approval menggunakan **Laravel Notifications** (channel `mail`): +- Approver menerima email “approval requested” +- Requester menerima email “approval approved/rejected” + +Agar email terkirim, konfigurasi SMTP pada `.env` (contoh): +```env +MAIL_MAILER=smtp +MAIL_HOST=smtp.mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=your_username +MAIL_PASSWORD=your_password +MAIL_ENCRYPTION=tls +MAIL_FROM_ADDRESS="noreply@example.com" +MAIL_FROM_NAME="Asset Management System" +``` + +## Notifikasi Terjadwal (Command) + +Tersedia command untuk reminder sederhana (mencatat ke log `asset_activity`): +```bash +php artisan asset:notify-due +``` + +Anda bisa menjadwalkannya via cron (contoh setiap hari jam 08:00): +```cron +0 8 * * * cd /path/to/project && php artisan asset:notify-due >> /dev/null 2>&1 +``` + +## Maintenance Mode (Read-only) + +Jika setting `maintenance.readonly_mode = true`: +- Middleware `maintenance.readonly` akan memblokir aksi tulis. +- Dashboard menampilkan badge “Mode Read-only Aktif”. + +## Testing + +Menjalankan test (SQLite): +```bash +php artisan test +``` + +## Deployment Notes + +Checklist singkat production: +- `APP_ENV=production`, `APP_DEBUG=false`, `APP_KEY` sudah terisi +- `php artisan migrate --force` +- `php artisan storage:link` +- `npm run build` (atau gunakan build artifact yang sudah ada di `public/build`) +- Pastikan permission folder: + - `storage/` dan `bootstrap/cache/` writable ## Contributing -Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). - -## Code of Conduct - -In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). - -## Security Vulnerabilities - -If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. - -## License - -The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +Kontribusi sangat diterima. +- Gunakan style & struktur yang sudah ada (controller tipis, logic di service) +- Tambahkan test untuk fitur baru bila memungkinkan +- Buat PR kecil dan fokus per fitur diff --git a/app/Http/Middleware/SessionTimeout.php b/app/Http/Middleware/SessionTimeout.php index 0f1da43..38af48e 100644 --- a/app/Http/Middleware/SessionTimeout.php +++ b/app/Http/Middleware/SessionTimeout.php @@ -11,7 +11,10 @@ class SessionTimeout public function handle(Request $request, Closure $next): Response { if ($request->user()) { - $timeout = config('system.security.session_idle_timeout_minutes', 30); + // Mengikuti key setting yang disimpan di database (`security.session_idle_minutes`). + // Fallback ke key lama jika ada, agar backward compatible. + $timeout = (int) (config('system.security.session_idle_minutes') + ?? config('system.security.session_idle_timeout_minutes', 30)); $last = session('last_active_at'); if ($last && now()->diffInMinutes($last) >= $timeout) {