diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..252de12 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,55 @@ +# Copilot Instructions for AI Agents + +## Project Overview + +- This is a Laravel-based web application for managing perizinan (permits), with a normalized database structure and dashboard analytics. +- Key entities: `Kategori`, `DashboardPerizinan`, `TerakhirTerbit`, `IzinTercepat`, with relations enforced via foreign keys and PascalCase field names. +- Data flows from database to dashboard/API endpoints, with helpers mapping string names to KategoriID and providing DB fallback. + +## Architecture & Data Flow + +- **Controllers** (e.g., `app/Http/Controllers/DashboardController.php`): Handle API/dashboard requests, use helpers for data formatting, always query DB (no static arrays). +- **Helpers** (e.g., `app/Helpers/DashboardHelper.php`): Accept string kategori, map to KategoriID, query DB for fallback, output in PascalCase. +- **Models** (e.g., `app/Models/Kategori.php`): Eloquent models with explicit relations; always use PascalCase for DB fields. +- **Migrations** (e.g., `database/migrations/`): Define normalized schema, foreign keys, and PascalCase columns. +- **Seeders** (e.g., `database/seeders/DatabaseSeeder.php`): Populate Kategori and other reference tables. + +## Developer Workflows + +- **Build/Serve**: Use `php artisan serve` for local dev; assets via Vite (`npm run dev`). +- **Sync Data**: Run `php artisan perizinan:sync --all` to sync all permit data (used in cronjobs). +- **Testing**: Use `php artisan test` for PHPUnit tests in `tests/Feature` and `tests/Unit`. +- **Cronjob**: On server, set up cron to run sync command regularly (see shell script in docs). + +## Conventions & Patterns + +- **PascalCase**: All DB fields, model properties, and API outputs use PascalCase. +- **String-to-ID Mapping**: Helpers accept string kategori, map to KategoriID, fallback to DB if not found. +- **No Static Arrays**: All dashboard/API data must come from DB, not hardcoded arrays. +- **Frontend Data Import**: Use window variables for initial chart data, AJAX for dynamic updates (see `resources/js/homeOneChart.js`). + +## Integration Points + +- **External**: Uses Laravel packages (see `composer.json`), e.g., `barryvdh/laravel-dompdf` for PDF generation. +- **Frontend**: Blade templates in `resources/views/`, JS in `resources/js/`. +- **Database**: SQLite for local dev (`database/database.sqlite`). + +## Key Files & Directories + +- `app/Helpers/DashboardHelper.php`: Helper logic for dashboard data +- `app/Http/Controllers/DashboardController.php`: Main dashboard/API controller +- `app/Models/Kategori.php`: Kategori model (ensure correct namespace) +- `database/migrations/`: All migration files +- `database/seeders/DatabaseSeeder.php`: Seeder logic +- `resources/js/homeOneChart.js`: Frontend chart integration +- `routes/web.php`: Route definitions + +## Example Patterns + +- Helper usage: `DashboardHelper::getSummaryByKategori('Pertek')` (maps to KategoriID, queries DB) +- Controller usage: `$data = DashboardHelper::getSummaryByKategori($kategoriString);` +- Cronjob: `* * * * * cd /path/to/project && php artisan perizinan:sync --all >> /dev/null 2>&1` + +--- + +If any conventions or workflows are unclear, please ask for clarification or examples from the codebase. diff --git a/CHANGES_TERAKHIR_TERBIT.md b/CHANGES_TERAKHIR_TERBIT.md deleted file mode 100644 index 543ac81..0000000 --- a/CHANGES_TERAKHIR_TERBIT.md +++ /dev/null @@ -1,75 +0,0 @@ -# PERUBAHAN SISTEM TERAKHIR TERBIT - -## Masalah yang Diperbaiki - -- Menghapus kolom `rank_order` yang statis dan akan bermasalah ketika ada data baru -- Mengubah sistem ordering menggunakan `tanggal_terbit` yang lebih dinamis dan logis - -## Perubahan Yang Dilakukan - -### 1. Database Migration (2025_07_14_033547_create_terakhir_terbit_table.php) - -- ❌ Dihapus: `rank_order` column -- ❌ Dihapus: unique constraint berdasarkan rank_order -- ✅ Ditambah: index pada `kategori` dan `tanggal_terbit` -- ✅ Ditambah: index pada `kategori` dan `sync_date` - -### 2. Model TerakhirTerbit (app/Models/TerakhirTerbit.php) - -- ❌ Dihapus: `rank_order` dari fillable dan casts -- ✅ Diubah: Query method `getLatestByKategori()` menggunakan `ORDER BY tanggal_terbit DESC` + `LIMIT 5` -- ✅ Diubah: Query method `getByKategoriAndDate()` menggunakan `ORDER BY tanggal_terbit DESC` + `LIMIT 5` - -### 3. API Service (app/Services/PerizinanApiService.php) - -- ❌ Dihapus: Logic penambahan `rank_order` dalam `syncTerakhirTerbitToDatabase()` -- ✅ Simplified: Data disimpan tanpa manual ranking, biarkan database yang mengurutkan - -### 4. Dashboard Helper (app/Helpers/DashboardHelper.php) - -- ✅ Diubah: Generate `rank_order` secara dinamis hanya untuk display (tidak disimpan di DB) -- ✅ Data tetap diurutkan berdasarkan `tanggal_terbit` terbaru dari database - -## Keuntungan Sistem Baru - -### ✅ Dinamis - -- Data selalu diurutkan berdasarkan tanggal terbit terbaru -- Tidak ada masalah ketika ada data baru - -### ✅ Consistent - -- Urutan data konsisten berdasarkan logical field (`tanggal_terbit`) -- Tidak bergantung pada urutan API response - -### ✅ Scalable - -- Bisa handle unlimited data tanpa konflik ranking -- Index database optimal untuk performa query - -### ✅ Maintainable - -- Code lebih sederhana tanpa logic manual ranking -- Ranking hanya untuk display purpose - -## Contoh Output Sistem Baru - -``` -PERTEK - Top 5 Terakhir Terbit: -#1: SUMANTO TJAHAJA (02 Jul 2025) ← Terbaru -#2: Eka Ferdiyus Supatmo (16 Jun 2025) ← Kedua terbaru -#3: Adrian Mara Maulana (13 Jun 2025) ← Ketiga terbaru -#4: AHMAD SYARIF (04 Jun 2025) ← Keempat terbaru -#5: drg. WWM Diah Arimbi (28 May 2025) ← Kelima terbaru -``` - -## Migration Command - -```bash -php artisan migrate:fresh # ← Sudah dijalankan -php artisan perizinan:sync --all # ← Test dengan data baru -``` - -## Status: ✅ COMPLETED - -Sistem terakhir terbit sekarang menggunakan ordering dinamis berdasarkan tanggal terbit terbaru. diff --git a/FASTEST_INTEGRATION.md b/FASTEST_INTEGRATION.md deleted file mode 100644 index 5a7ee2d..0000000 --- a/FASTEST_INTEGRATION.md +++ /dev/null @@ -1,150 +0,0 @@ -# Fastest Permohonan API Integration - -## Overview - -Integration telah selesai untuk endpoint fastest permohonan API Jakarta: - -- **URL**: `https://wsdev.jakarta.go.id/gateway/DataPerizinanLingkungan/1.0/fastest_permohonan` -- **Parameters**: `kategori` (pertek/amdal), `limit` (default: 5) -- **Headers**: `Authorization: Bearer `, `x-Gateway-APIKey: ` - -## Database Schema - -### Table: `fastest_permohonan` - -```sql -- id (bigint, primary key) -- kategori (varchar) - pertek, amdal -- nama (varchar) - nama izin dari API -- total (integer) - jumlah total izin -- durasi_pemohon (varchar) - durasi rata-rata pemohon -- durasi_petugas (varchar) - durasi rata-rata petugas -- rank_order (integer) - urutan ranking 1-5 -- api_last_updated (datetime) - dari field API last_updated -- sync_date (date) - tanggal sync data -- created_at, updated_at (timestamps) -``` - -**Indexes:** - -- `(kategori, sync_date, rank_order)` -- Unique: `(kategori, rank_order, sync_date)` - -## API Response Structure - -```json -{ - "success": 1, - "message": "Fastest permohonan retrieved successfully.", - "data": [ - { - "nama": "SURAT PERNYATAAN PENGELOLAAN LINGKUNGAN (SPPL)", - "total": 7174, - "durasi_pemohon": "5 Hari 06 Jam 09 Menit 01 Detik", - "durasi_petugas": "4 Hari 03 Jam 12 Menit 18 Detik" - } - ], - "last_updated": "2025-07-14 09:50:07" -} -``` - -## Files Modified/Created - -### New Files: - -1. `database/migrations/2025_07_14_024445_create_fastest_permohonan_table.php` -2. `app/Models/FastestPermohonan.php` - -### Modified Files: - -1. `app/Services/PerizinanApiService.php` - - - Added `fetchFastestPermohonan()` method - - Added `syncFastestDataToDatabase()` method - - Modified `syncAllCategories()` to include fastest data - -2. `app/Console/Commands/SyncPerizinanData.php` - - - Added `--fastest` option - - Updated to sync both status and fastest data - -3. `routes/console.php` - - - Updated schedule to include `--fastest` flag - -4. `app/Helpers/DashboardHelper.php` - - Added `getFastestPermohonanByType()` method - - Added `getAllFastestData()` method - - Added helper methods for formatting and display - -## Commands - -### Sync Status Data Only: - -```bash -php artisan perizinan:sync # All categories -php artisan perizinan:sync pertek # Specific category -``` - -### Sync Status + Fastest Data: - -```bash -php artisan perizinan:sync --fastest # All categories -php artisan perizinan:sync pertek --fastest # Specific category -``` - -### Check Data: - -```bash -php artisan perizinan:check -``` - -## Scheduled Tasks - -Daily at midnight (00:00 WIB): - -```bash -php artisan perizinan:sync --fastest -``` - -## Data Access Examples - -### Using DashboardHelper: - -```php -// Get fastest data for dashboard -$fastestData = DashboardHelper::getAllFastestData(); - -// Get fastest data for specific type -$pertekFastest = DashboardHelper::getFastestPermohonanByType('pertek'); -``` - -### Using Model Directly: - -```php -// Get today's data for PERTEK -$pertek = FastestPermohonan::getLatestByKategori('pertek'); - -// Get data for specific date -$data = FastestPermohonan::getByKategoriAndDate('amdal', '2025-07-14'); -``` - -## Data Flow - -1. **API Call**: Service fetches data from Jakarta API -2. **Data Validation**: Check API response success -3. **Database Sync**: - - Delete existing data for today (to ensure fresh ranking) - - Insert new data with ranking based on API order -4. **Dashboard Display**: Helper methods format data for frontend - -## Production Deployment - -Data akan tersync otomatis setiap hari jam 12 malam melalui Laravel Scheduler di production server. - -## Notes - -- Data di-refresh setiap hari untuk memastikan ranking terbaru -- Ranking ditentukan berdasarkan urutan dari API response -- Fallback data tersedia jika API tidak tersedia -- Support untuk kategori 'pertek' dan 'amdal' sesuai endpoint yang tersedia diff --git a/FINAL_OPTIMIZATION_SUMMARY.md b/FINAL_OPTIMIZATION_SUMMARY.md deleted file mode 100644 index 30cf0e2..0000000 --- a/FINAL_OPTIMIZATION_SUMMARY.md +++ /dev/null @@ -1,191 +0,0 @@ -# FINAL SYSTEM IMPROVEMENTS - SEMUA TABEL SUDAH OPTIMAL - -## Ringkasan Perubahan - -✅ **FASTEST_PERMOHONAN** - Dihapus rank_order, gunakan API ordering -✅ **TERAKHIR_TERBIT** - Dihapus rank_order, gunakan tanggal_terbit ordering -✅ **PERIZINAN_STATUS** - Sudah optimal (tidak perlu rank_order) - -## 1. FASTEST_PERMOHONAN Table - -### ❌ Masalah Sebelumnya: - -```php -// MASALAH: rank_order statis, konflik saat ada data baru -'rank_order' => $index + 1 // Static ranking! -``` - -### ✅ Solusi Sekarang: - -```php -// OPTIMAL: Simpan data tanpa ranking, biarkan API order alami -FastestPermohonan::create([ - 'kategori' => $kategori, - 'nama' => $item['nama'], - 'total' => $item['total'], - 'durasi_pemohon' => $item['durasi_pemohon'], - 'durasi_petugas' => $item['durasi_petugas', - // ❌ DIHAPUS: 'rank_order' => $index + 1 - 'api_last_updated' => $apiLastUpdated, - 'sync_date' => $syncDate -]); - -// Query menggunakan insertion order (id) untuk preserve API order -->orderBy('id')->limit(5) -``` - -### 🎯 Keuntungan: - -- **API Order Preserved**: Data tetap sesuai urutan tercepat dari API -- **No Conflicts**: Tidak ada masalah ranking duplicate -- **Dynamic Display**: Ranking (#1-#5) generate saat display - -## 2. TERAKHIR_TERBIT Table - -### ❌ Masalah Sebelumnya: - -```php -// MASALAH: rank_order berdasarkan API response, bukan tanggal terbaru -'rank_order' => $index + 1 // Static dari API! -``` - -### ✅ Solusi Sekarang: - -```php -// OPTIMAL: Urutkan berdasarkan tanggal terbit terbaru -TerakhirTerbit::create([ - 'kategori' => $kategori, - 'nama_izin' => $item['nama_izin'], - 'pemohon' => $item['pemohon'], - 'tanggal_terbit' => Carbon::parse($item['tanggal_terbit']), - // ❌ DIHAPUS: 'rank_order' => $index + 1 - 'api_last_updated' => $apiLastUpdated, - 'sync_date' => $syncDate -]); - -// Query menggunakan logical order (tanggal terbaru) -->orderBy('tanggal_terbit', 'desc')->limit(5) -``` - -### 🎯 Keuntungan: - -- **Always Latest**: Selalu tampilkan izin dengan tanggal terbit terbaru -- **Logical Order**: Urutan berdasarkan field yang relevan (tanggal_terbit) -- **Future Proof**: Data baru otomatis masuk urutan yang benar - -## 3. PERIZINAN_STATUS Table - -### ✅ Sudah Optimal: - -```php -// BAGUS: Cek existing data untuk hari yang sama, no deletion -$exists = PerizinanStatus::where('kategori', $kategori) - ->where('status_id', $item['id']) - ->whereDate('sync_date', $syncDate) - ->exists(); - -if (!$exists) { - // Simpan data baru -} -``` - -### 🎯 Tidak Perlu Perubahan: - -- **Smart Duplication Check**: Hanya cegah data duplicate untuk hari yang sama -- **Historical Data**: Simpan semua data historis untuk analisis -- **No Ranking**: Status data tidak perlu ranking system - -## Database Schema Changes - -### FASTEST_PERMOHONAN Migration: - -```php -// ❌ DIHAPUS: -$table->integer('rank_order'); -$table->unique(['kategori', 'rank_order', 'sync_date']); - -// ✅ DITAMBAH: -$table->index(['kategori', 'total']); // untuk sorting performance -``` - -### TERAKHIR_TERBIT Migration: - -```php -// ❌ DIHAPUS: -$table->integer('rank_order'); -$table->unique(['kategori', 'rank_order', 'sync_date']); - -// ✅ DITAMBAH: -$table->index(['kategori', 'tanggal_terbit']); // untuk sorting performance -``` - -## Model Changes - -### FastestPermohonan Model: - -```php -// ✅ Query Method: -public static function getLatestByKategori($kategori) -{ - return self::where('kategori', $kategori) - ->whereDate('sync_date', Carbon::today()) - ->orderBy('id') // Preserve API order - ->limit(5) - ->get(); -} -``` - -### TerakhirTerbit Model: - -```php -// ✅ Query Method: -public static function getLatestByKategori($kategori) -{ - return self::where('kategori', $kategori) - ->whereDate('sync_date', Carbon::today()) - ->orderBy('tanggal_terbit', 'desc') // Latest first - ->limit(5) - ->get(); -} -``` - -## Dashboard Helper Changes - -### Dynamic Ranking Generation: - -```php -// ✅ Generate ranking hanya untuk display -$index = 1; -foreach ($dbData as $item) { - $data[] = [ - 'nama' => $item->nama, - // ...data lainnya... - 'rank_order' => $index++ // Dynamic display ranking - ]; -} -``` - -## Hasil Test Final - -``` -FASTEST DATA (API ORDER): -#1: SPPL UNTUK KEPENTINGAN BANGUNAN MILIK PEMERINTAH (6 total, 3j54m) ← Tercepat -#2: SPPL (7,174 total, 5h6j9m) ← Kedua tercepat -#3: Izin Tempat Uji Emisi (592 total, 5h1j57m) ← Ketiga tercepat - -TERAKHIR TERBIT (TANGGAL TERBARU): -#1: SUMANTO TJAHAJA (02 Jul 2025) ← Terbaru -#2: Eka Ferdiyus Supatmo (16 Jun 2025) ← Kedua terbaru -#3: Adrian Mara Maulana (13 Jun 2025) ← Ketiga terbaru -``` - -## ✅ STATUS: SYSTEM FULLY OPTIMIZED - -Semua tabel sekarang menggunakan: - -- **NO Static rank_order** yang bermasalah -- **Logical ordering** berdasarkan data relevance -- **Dynamic ranking** untuk display purposes -- **Scalable architecture** untuk data masa depan - -🎉 **System ready for production!** diff --git a/PERIZINAN_API_SETUP.md b/PERIZINAN_API_SETUP.md deleted file mode 100644 index 6cdfd69..0000000 --- a/PERIZINAN_API_SETUP.md +++ /dev/null @@ -1,164 +0,0 @@ -# Setup Perizinan API Integration - -## Overview - -Sistem ini mengintegrasikan data perizinan dari API Jakarta dengan database lokal menggunakan cron job yang berjalan setiap hari pada jam 12 malam. - -## Setup Instructions - -### 1. Environment Configuration - -Update file `.env` dengan credentials API: - -```env -# Perizinan API Configuration -PERIZINAN_API_BASE_URL=https://wsdev.jakarta.go.id/gateway/DataPerizinanLingkungan/1.0 -PERIZINAN_API_BEARER_TOKEN=your_actual_bearer_token -PERIZINAN_API_KEY=your_actual_api_key -``` - -### 2. Database Migration - -Jalankan migration untuk membuat tabel: - -```bash -php artisan migrate -``` - -### 3. Manual Sync (Testing) - -Untuk test sync manual: - -```bash -# Sync semua kategori -php artisan perizinan:sync - -# Sync kategori tertentu -php artisan perizinan:sync pertek -php artisan perizinan:sync amdal -``` - -### 4. Cron Job Setup (Linux Production Server) - -Sistem sudah dikonfigurasi untuk berjalan otomatis setiap hari jam 12 malam. Untuk aktivasi cron job di server Linux: - -#### Opsi 1: Laravel Scheduler (Recommended) - -```bash -# Edit crontab -crontab -e - -# Add this line (runs every minute): -* * * * * cd /var/www/perling && ./run-scheduler.sh >/dev/null 2>&1 -``` - -#### Opsi 2: Direct Sync - -```bash -# Edit crontab -crontab -e - -# Add this line (runs daily at midnight): -0 0 * * * cd /var/www/perling && ./sync-perizinan.sh >/dev/null 2>&1 -``` - -### 5. Production Deployment - -Untuk deployment ke production server, lihat file `PRODUCTION_DEPLOY.md` untuk panduan lengkap. - -### 6. Monitoring - -Cek log file untuk monitoring sync process: - -```bash -# Application logs -tail -f storage/logs/laravel.log - -# Cron job logs -tail -f storage/logs/cron.log - -# Scheduler logs (if using Laravel Scheduler) -tail -f storage/logs/scheduler.log - -# Check cron service status -sudo systemctl status cron - -# View cron job list -crontab -l -``` - -## API Response Format - -```json -{ - "success": true, - "message": "Summary by status retrieved successfully.", - "data": [ - { - "id": "ditolak", - "label": "Izin Ditolak", - "value": 1443 - }, - { - "id": "selesai", - "label": "Izin Selesai", - "value": 8379 - }, - { - "id": "proses", - "label": "Dalam Proses", - "value": 143 - }, - { - "id": "total", - "label": "Total Pengajuan", - "value": 9965 - } - ], - "last_updated": "2025-07-14 08:55:04" -} -``` - -## Database Schema - -Table: `perizinan_status` - -- `id` - Primary key -- `kategori` - Category (pertek, amdal) -- `status_id` - Status ID (ditolak, selesai, proses, total) -- `label` - Human readable label -- `value` - Count value -- `api_last_updated` - Last updated timestamp from API -- `sync_date` - Date when data was synced -- `created_at` / `updated_at` - Laravel timestamps - -## Features - -- ✅ Daily automatic sync at midnight -- ✅ Duplicate prevention (same data per day) -- ✅ Comprehensive logging -- ✅ Fallback to static data if API fails -- ✅ Manual sync commands for testing -- ✅ Database storage with indexing for performance - -## Troubleshooting - -### Command not found - -```bash -php artisan optimize:clear -composer dump-autoload -``` - -### API Connection Issues - -1. Verify credentials in `.env` -2. Check network connectivity -3. Review logs for detailed error messages - -### Database Issues - -```bash -php artisan migrate:fresh -php artisan migrate -``` diff --git a/PRODUCTION_DEPLOY.md b/PRODUCTION_DEPLOY.md deleted file mode 100644 index d71bec5..0000000 --- a/PRODUCTION_DEPLOY.md +++ /dev/null @@ -1,191 +0,0 @@ -# Production Deployment Guide - Perizinan API Integration - -## 🚀 Quick Deployment - -### 1. Upload Files to Server - -Upload semua files ke server Linux di directory `/var/www/perling` (atau sesuai setup Anda). - -### 2. Run Deployment Script - -```bash -cd /var/www/perling -chmod +x deploy-production.sh -./deploy-production.sh -``` - -### 3. Update Environment Variables - -Edit file `.env` dan update: - -```env -APP_ENV=production -APP_DEBUG=false - -# Database production -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=perling_production -DB_USERNAME=your_db_user -DB_PASSWORD=your_db_password - -# API Credentials (yang sudah ada) -PERIZINAN_API_BEARER_TOKEN=f633c4f8e8a84708895bf31c0afdfa68c9079613d18d4edfb1fc6a0019b5f832 -PERIZINAN_API_KEY=b06c8ef1-06db-443d-996b-80e8c3374923 -``` - -### 4. Setup Cron Job - -#### Option 1: Laravel Scheduler (Recommended) - -```bash -# Edit crontab -sudo crontab -e - -# Add this line (runs every minute): -* * * * * cd /var/www/perling && ./run-scheduler.sh >/dev/null 2>&1 -``` - -#### Option 2: Direct Sync - -```bash -# Edit crontab -sudo crontab -e - -# Add this line (runs daily at midnight): -0 0 * * * cd /var/www/perling && ./sync-perizinan.sh >/dev/null 2>&1 -``` - -## 🔧 Manual Commands - -### Test API Connection - -```bash -cd /var/www/perling -php artisan perizinan:sync pertek -``` - -### Check Synced Data - -```bash -php artisan perizinan:check -``` - -### View Logs - -```bash -# Cron logs -tail -f storage/logs/cron.log - -# Laravel application logs -tail -f storage/logs/laravel.log - -# Scheduler logs (if using Option 1) -tail -f storage/logs/scheduler.log -``` - -### View Cron Job Status - -```bash -# View current crontab -crontab -l - -# View cron service logs -sudo journalctl -u cron -f -``` - -## 🐛 Troubleshooting - -### Permission Issues - -```bash -# Fix storage permissions -sudo chown -R www-data:www-data storage/ -sudo chmod -R 775 storage/ - -# Fix cache permissions -sudo chown -R www-data:www-data bootstrap/cache/ -sudo chmod -R 775 bootstrap/cache/ -``` - -### Database Issues - -```bash -# Clear config cache -php artisan config:clear - -# Run migrations -php artisan migrate --force - -# Check database connection -php artisan tinker --execute="DB::connection()->getPdo();" -``` - -### API Connection Issues - -```bash -# Test API manually -curl -X GET "https://wsdev.jakarta.go.id/gateway/DataPerizinanLingkungan/1.0/summary_by_status?kategori=pertek" \ - -H "Authorization: Bearer f633c4f8e8a84708895bf31c0afdfa68c9079613d18d4edfb1fc6a0019b5f832" \ - -H "x-Gateway-APIKey: b06c8ef1-06db-443d-996b-80e8c3374923" -``` - -### Cron Job Not Running - -```bash -# Check if cron service is running -sudo systemctl status cron - -# Start cron service if stopped -sudo systemctl start cron - -# Check cron logs -sudo tail -f /var/log/cron.log -``` - -## 📊 Monitoring - -### Daily Health Check - -```bash -# Check if data was synced today -php artisan perizinan:check - -# Check latest logs -tail -20 storage/logs/cron.log -``` - -### Weekly Review - -```bash -# Check database records count -php artisan tinker --execute="echo App\Models\PerizinanStatus::count() . ' total records';" - -# Check logs for errors -grep -i error storage/logs/laravel.log | tail -10 -``` - -## 🔐 Security Notes - -1. **File Permissions**: Ensure proper permissions for Laravel -2. **Database**: Use strong password and limit access -3. **API Keys**: Keep credentials secure, don't commit to version control -4. **Logs**: Regularly rotate and clean up log files -5. **SSL**: Use HTTPS in production - -## 📈 Performance Tips - -1. **Database Indexing**: Already added in migration -2. **Log Rotation**: Setup logrotate for Laravel logs -3. **Caching**: Enable OPcache for PHP -4. **Queue**: Consider using Redis for Laravel queues if needed - -## 🎯 Success Criteria - -✅ Cron job runs without errors -✅ Data syncs daily at midnight -✅ Dashboard shows real API data -✅ Logs are clean without errors -✅ Database grows with daily records -✅ API connection is stable diff --git a/TASK_SCHEDULER_SETUP.md b/TASK_SCHEDULER_SETUP.md deleted file mode 100644 index 0dd1197..0000000 --- a/TASK_SCHEDULER_SETUP.md +++ /dev/null @@ -1,73 +0,0 @@ -# Manual Task Scheduler Setup Instructions - -## Cara Setup Task Scheduler Manual di Windows - -### Langkah 1: Buka Task Scheduler - -1. Tekan `Win + R` -2. Ketik `taskschd.msc` dan tekan Enter -3. Atau search "Task Scheduler" di Start Menu - -### Langkah 2: Create Basic Task - -1. Di panel kanan, klik **"Create Basic Task..."** -2. **Name**: `PerizinanDataSync` -3. **Description**: `Daily sync of perizinan data from Jakarta API at midnight` -4. Klik **Next** - -### Langkah 3: Trigger (Kapan berjalan) - -1. Pilih **"Daily"** -2. Klik **Next** -3. **Start date**: Hari ini -4. **Start time**: `12:00:00 AM` (midnight) -5. **Recur every**: `1 days` -6. Klik **Next** - -### Langkah 4: Action (Apa yang dijalankan) - -1. Pilih **"Start a program"** -2. Klik **Next** -3. **Program/script**: `C:\laragon\www\perling\sync-perizinan.bat` -4. **Start in**: `C:\laragon\www\perling` -5. Klik **Next** - -### Langkah 5: Finish - -1. Review semua setting -2. ✅ Centang **"Open the Properties dialog for this task when I click Finish"** -3. Klik **Finish** - -### Langkah 6: Advanced Settings (Optional) - -Di Properties dialog: - -1. Tab **General**: - - - ✅ Centang "Run whether user is logged on or not" - - ✅ Centang "Run with highest privileges" - -2. Tab **Conditions**: - - - ❌ Uncheck "Start the task only if the computer is on AC power" - -3. Tab **Settings**: - - - ✅ Centang "Allow task to be run on demand" - - ✅ Centang "Run task as soon as possible after a scheduled start is missed" - -4. Klik **OK** - -## Test Task - -Untuk test task manual: - -1. Klik kanan pada task **"PerizinanDataSync"** -2. Pilih **"Run"** -3. Check log di: `C:\laragon\www\perling\storage\logs\cron.log` - -## Monitoring - -- Task history bisa dilihat di tab **History** pada task properties -- Log aplikasi di: `storage\logs\cron.log` -- Log Laravel di: `storage\logs\laravel.log` diff --git a/app/Helpers/DashboardHelper.blade.php b/app/Helpers/DashboardHelper.blade.php deleted file mode 100644 index e69de29..0000000 diff --git a/app/Helpers/dashboard_functions.php b/app/Helpers/dashboard_functions.php deleted file mode 100644 index 58ecd91..0000000 --- a/app/Helpers/dashboard_functions.php +++ /dev/null @@ -1,106 +0,0 @@ - /dev/null; then - composer_version=$(composer --version) - echo -e "${GREEN}✅ $composer_version${NC}" -else - echo -e "${RED}❌ Composer not found${NC}" -fi - -# Check cron service -echo -e "\n${YELLOW}⏰ Cron Service:${NC}" -if systemctl is-active --quiet cron; then - echo -e "${GREEN}✅ Cron service is running${NC}" -else - echo -e "${RED}❌ Cron service is not running${NC}" -fi - -# Check disk space -echo -e "\n${YELLOW}💾 Disk Space:${NC}" -df -h | head -n 1 -df -h | grep -E '^/dev/' - -# Check memory -echo -e "\n${YELLOW}🧠 Memory:${NC}" -free -h - -# Check network connectivity to API -echo -e "\n${YELLOW}🌐 API Connectivity:${NC}" -if curl -s --connect-timeout 5 https://wsdev.jakarta.go.id > /dev/null; then - echo -e "${GREEN}✅ Can reach Jakarta API${NC}" -else - echo -e "${RED}❌ Cannot reach Jakarta API${NC}" -fi - -# Check write permissions -echo -e "\n${YELLOW}🔐 Directory Permissions:${NC}" -dirs=("storage" "storage/logs" "bootstrap/cache") - -for dir in "${dirs[@]}"; do - if [ -w "$dir" ]; then - echo -e "${GREEN}✅ $dir is writable${NC}" - else - echo -e "${RED}❌ $dir is not writable${NC}" - fi -done - -echo -e "\n${GREEN}🏁 Environment check completed!${NC}" diff --git a/check_fastest_data.php b/check_fastest_data.php deleted file mode 100644 index bd6c758..0000000 --- a/check_fastest_data.php +++ /dev/null @@ -1,29 +0,0 @@ -make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); - -use App\Models\FastestPermohonan; - -echo "=== FASTEST PERMOHONAN DATA ===\n\n"; - -echo "PERTEK Category:\n"; -$pertekData = FastestPermohonan::where('kategori', 'pertek')->orderBy('rank_order')->get(); -foreach ($pertekData as $item) { - echo "#{$item->rank_order}: {$item->nama}\n"; - echo " Total: {$item->total}, Durasi Pemohon: {$item->durasi_pemohon}\n"; - echo " Durasi Petugas: {$item->durasi_petugas}\n\n"; -} - -echo "\nAMDAL Category:\n"; -$amdalData = FastestPermohonan::where('kategori', 'amdal')->orderBy('rank_order')->get(); -foreach ($amdalData as $item) { - echo "#{$item->rank_order}: {$item->nama}\n"; - echo " Total: {$item->total}, Durasi Pemohon: {$item->durasi_pemohon}\n"; - echo " Durasi Petugas: {$item->durasi_petugas}\n\n"; -} - -echo "Total Records: " . FastestPermohonan::count() . "\n"; diff --git a/check_terakhir_terbit.php b/check_terakhir_terbit.php deleted file mode 100644 index dce9370..0000000 --- a/check_terakhir_terbit.php +++ /dev/null @@ -1,29 +0,0 @@ -make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); - -use App\Models\TerakhirTerbit; - -echo "=== TERAKHIR TERBIT DATA ===\n\n"; - -echo "PERTEK Category:\n"; -$pertekData = TerakhirTerbit::where('kategori', 'pertek')->orderBy('rank_order')->get(); -foreach ($pertekData as $item) { - echo "#{$item->rank_order}: {$item->nama_izin}\n"; - echo " Pemohon: {$item->pemohon}\n"; - echo " Tanggal Terbit: {$item->tanggal_terbit->format('d M Y')}\n\n"; -} - -echo "\nAMDAL Category:\n"; -$amdalData = TerakhirTerbit::where('kategori', 'amdal')->orderBy('rank_order')->get(); -foreach ($amdalData as $item) { - echo "#{$item->rank_order}: {$item->nama_izin}\n"; - echo " Pemohon: {$item->pemohon}\n"; - echo " Tanggal Terbit: {$item->tanggal_terbit->format('d M Y')}\n\n"; -} - -echo "Total Records: " . TerakhirTerbit::count() . "\n"; diff --git a/composer.json b/composer.json index 062b9e4..8aa96f1 100644 --- a/composer.json +++ b/composer.json @@ -30,10 +30,7 @@ "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" - }, - "files": [ - "app/Helpers/dashboard_functions.php" - ] + } }, "autoload-dev": { "psr-4": { diff --git a/deploy-production.sh b/deploy-production.sh deleted file mode 100644 index 3ccab31..0000000 --- a/deploy-production.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/bash - -# Production Deployment Script for Perizinan System -# Run this script after deploying to production server - -echo "🚀 Setting up Perizinan API Integration for Production..." - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Get current directory -CURRENT_DIR=$(pwd) -echo -e "${BLUE}Current directory: $CURRENT_DIR${NC}" - -# Check if we're in Laravel project -if [ ! -f "artisan" ]; then - echo -e "${RED}❌ Error: artisan file not found. Make sure you're in Laravel project directory.${NC}" - exit 1 -fi - -# 1. Make shell scripts executable -echo -e "${YELLOW}📁 Making shell scripts executable...${NC}" -chmod +x sync-perizinan.sh -chmod +x run-scheduler.sh -echo -e "${GREEN}✅ Shell scripts are now executable${NC}" - -# 2. Create log directories if they don't exist -echo -e "${YELLOW}📁 Creating log directories...${NC}" -mkdir -p storage/logs -echo -e "${GREEN}✅ Log directories created${NC}" - -# 3. Set proper permissions -echo -e "${YELLOW}🔐 Setting proper permissions...${NC}" -chmod -R 775 storage/ -chmod -R 775 bootstrap/cache/ -echo -e "${GREEN}✅ Permissions set${NC}" - -# 4. Update .env for production -echo -e "${YELLOW}⚙️ Checking .env configuration...${NC}" -if [ ! -f ".env" ]; then - echo -e "${RED}❌ .env file not found. Please create it first.${NC}" - exit 1 -fi - -# Check if API credentials are set -if grep -q "PERIZINAN_API_BEARER_TOKEN=your_actual_bearer_token" .env; then - echo -e "${RED}⚠️ Warning: Please update PERIZINAN_API_BEARER_TOKEN in .env${NC}" -fi - -if grep -q "PERIZINAN_API_KEY=your_actual_api_key" .env; then - echo -e "${RED}⚠️ Warning: Please update PERIZINAN_API_KEY in .env${NC}" -fi - -# 5. Run database migrations -echo -e "${YELLOW}🗄️ Running database migrations...${NC}" -php artisan migrate --force -echo -e "${GREEN}✅ Database migrations completed${NC}" - -# 6. Test API connection -echo -e "${YELLOW}🌐 Testing API connection...${NC}" -php artisan perizinan:sync pertek -if [ $? -eq 0 ]; then - echo -e "${GREEN}✅ API connection test successful${NC}" -else - echo -e "${RED}❌ API connection test failed. Please check your credentials.${NC}" -fi - -# 7. Setup cron job options -echo "" -echo -e "${BLUE}📅 Cron Job Setup Options:${NC}" -echo "" -echo -e "${YELLOW}Option 1: Laravel Scheduler (Recommended)${NC}" -echo "Add this line to crontab (crontab -e):" -echo -e "${GREEN}* * * * * cd $CURRENT_DIR && ./run-scheduler.sh >/dev/null 2>&1${NC}" -echo "" -echo -e "${YELLOW}Option 2: Direct Sync${NC}" -echo "Add this line to crontab (crontab -e):" -echo -e "${GREEN}0 0 * * * cd $CURRENT_DIR && ./sync-perizinan.sh >/dev/null 2>&1${NC}" -echo "" - -# 8. Show commands for manual setup -echo -e "${BLUE}📋 Manual Commands:${NC}" -echo "" -echo "To edit crontab:" -echo -e "${GREEN}sudo crontab -e${NC}" -echo "" -echo "To view current crontab:" -echo -e "${GREEN}crontab -l${NC}" -echo "" -echo "To test sync manually:" -echo -e "${GREEN}php artisan perizinan:sync${NC}" -echo "" -echo "To check synced data:" -echo -e "${GREEN}php artisan perizinan:check${NC}" -echo "" -echo "To view logs:" -echo -e "${GREEN}tail -f storage/logs/cron.log${NC}" -echo -e "${GREEN}tail -f storage/logs/laravel.log${NC}" -echo "" - -echo -e "${GREEN}🎉 Production setup completed!${NC}" -echo -e "${YELLOW}📝 Don't forget to:${NC}" -echo "1. Update API credentials in .env" -echo "2. Setup cron job using one of the options above" -echo "3. Monitor logs after deployment" diff --git a/run-scheduler.bat b/run-scheduler.bat deleted file mode 100644 index 7934e55..0000000 --- a/run-scheduler.bat +++ /dev/null @@ -1,8 +0,0 @@ -@echo off -REM Laravel Scheduler Runner -REM This should run every minute via Task Scheduler - -cd /d "C:\laragon\www\perling" - -REM Run Laravel scheduler -php artisan schedule:run >> storage\logs\scheduler.log 2>&1 diff --git a/setup-task-scheduler.ps1 b/setup-task-scheduler.ps1 deleted file mode 100644 index ffc28f9..0000000 --- a/setup-task-scheduler.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -# PowerShell Script to Create Windows Task Scheduler for Perizinan Data Sync -# Run this script as Administrator - -$TaskName = "PerizinanDataSync" -$TaskDescription = "Daily sync of perizinan data from Jakarta API at midnight" -$ScriptPath = "C:\laragon\www\perling\sync-perizinan.bat" -$LogPath = "C:\laragon\www\perling\storage\logs\task-scheduler.log" - -Write-Host "Creating Windows Task Scheduler for Perizinan Data Sync..." -ForegroundColor Green - -# Check if task already exists -$ExistingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue - -if ($ExistingTask) { - Write-Host "Task '$TaskName' already exists. Removing old task..." -ForegroundColor Yellow - Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -} - -try { - # Create Task Action - $Action = New-ScheduledTaskAction -Execute $ScriptPath - - # Create Task Trigger (Daily at midnight) - $Trigger = New-ScheduledTaskTrigger -Daily -At "00:00" - - # Create Task Settings - $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable - - # Create Task Principal (Run with highest privileges) - $Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest - - # Register the Task - Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -Principal $Principal -Description $TaskDescription - - Write-Host "✅ Task Scheduler created successfully!" -ForegroundColor Green - Write-Host "Task Name: $TaskName" -ForegroundColor Cyan - Write-Host "Schedule: Daily at 00:00 (midnight)" -ForegroundColor Cyan - Write-Host "Script Path: $ScriptPath" -ForegroundColor Cyan - - # Show task info - Get-ScheduledTask -TaskName $TaskName | Format-Table -AutoSize - -} catch { - Write-Host "❌ Error creating task scheduler: $($_.Exception.Message)" -ForegroundColor Red - Write-Host "Please run this script as Administrator" -ForegroundColor Yellow -} - -Write-Host "`nTo manually run the task, use:" -ForegroundColor Cyan -Write-Host "Start-ScheduledTask -TaskName '$TaskName'" -ForegroundColor White - -Write-Host "`nTo view task history:" -ForegroundColor Cyan -Write-Host "Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-TaskScheduler/Operational'; ID=102}" -ForegroundColor White diff --git a/sync-perizinan.bat b/sync-perizinan.bat deleted file mode 100644 index fe51021..0000000 --- a/sync-perizinan.bat +++ /dev/null @@ -1,15 +0,0 @@ -@echo off -REM Perizinan Data Sync Script -REM Runs daily at midnight to sync data from API - -cd /d "C:\laragon\www\perling" - -REM Log start time -echo [%date% %time%] Starting perizinan data sync >> storage\logs\cron.log - -REM Run the sync command -php artisan perizinan:sync >> storage\logs\cron.log 2>&1 - -REM Log completion -echo [%date% %time%] Perizinan data sync completed >> storage\logs\cron.log -echo. >> storage\logs\cron.log diff --git a/test_all_tables.php b/test_all_tables.php deleted file mode 100644 index f5220eb..0000000 --- a/test_all_tables.php +++ /dev/null @@ -1,35 +0,0 @@ -make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); - -use App\Helpers\DashboardHelper; - -echo "=== TESTING ALL DATA TABLES AFTER RANK_ORDER REMOVAL ===\n\n"; - -// Test fastest data -echo "FASTEST DATA (API ORDER WITHOUT RANK_ORDER):\n"; -$fastestData = DashboardHelper::getAllFastestData(); -foreach ($fastestData as $type => $data) { - echo "{$data['label']} - Top 5 Tercepat:\n"; - foreach ($data['data'] as $item) { - echo " #{$item['rank_order']}: {$item['nama']}\n"; - echo " Total: " . number_format($item['total']) . ", Durasi Pemohon: {$item['durasi_pemohon']}\n"; - } - echo "\n"; -} - -// Test terakhir terbit data -echo "TERAKHIR TERBIT DATA (ORDERED BY tanggal_terbit):\n"; -$terakhirTerbitData = DashboardHelper::getAllTerakhirTerbitData(); -foreach ($terakhirTerbitData as $type => $data) { - echo "{$data['label']} - Top 5 Terakhir Terbit:\n"; - foreach ($data['data'] as $item) { - echo " #{$item['rank_order']}: {$item['nama_izin']}\n"; - echo " Pemohon: {$item['pemohon']}, Tanggal: " . DashboardHelper::formatTanggalTerbit($item['tanggal_terbit']) . "\n"; - } - echo "\n"; -} diff --git a/test_dashboard_helper.php b/test_dashboard_helper.php deleted file mode 100644 index e69de29..0000000 diff --git a/test_terakhir_terbit.php b/test_terakhir_terbit.php deleted file mode 100644 index f3fdf8f..0000000 --- a/test_terakhir_terbit.php +++ /dev/null @@ -1,31 +0,0 @@ -make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); - -use App\Models\TerakhirTerbit; - -echo "=== TERAKHIR TERBIT DATA (ORDERED BY tanggal_terbit DESC) ===\n\n"; - -echo "PERTEK:\n"; -$pertekData = TerakhirTerbit::getLatestByKategori('pertek'); -foreach ($pertekData as $index => $item) { - $no = $index + 1; - echo " {$no}. {$item->nama_izin}\n"; - echo " Pemohon: {$item->pemohon}\n"; - echo " Tanggal Terbit: {$item->tanggal_terbit->format('d M Y')}\n"; - echo " Sync Date: {$item->sync_date->format('Y-m-d')}\n\n"; -} - -echo "AMDAL:\n"; -$amdalData = TerakhirTerbit::getLatestByKategori('amdal'); -foreach ($amdalData as $index => $item) { - $no = $index + 1; - echo " {$no}. {$item->nama_izin}\n"; - echo " Pemohon: {$item->pemohon}\n"; - echo " Tanggal Terbit: {$item->tanggal_terbit->format('d M Y')}\n"; - echo " Sync Date: {$item->sync_date->format('Y-m-d')}\n\n"; -}