update: pemisahan

main
marszayn 2025-09-10 20:17:37 +07:00
parent 77b17978a4
commit e0fb72af83
21 changed files with 56 additions and 1343 deletions

55
.github/copilot-instructions.md vendored 100644
View File

@ -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.

View File

@ -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.

View File

@ -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 <token>`, `x-Gateway-APIKey: <key>`
## 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

View File

@ -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!**

View File

@ -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
```

View File

@ -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

View File

@ -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`

View File

@ -1,106 +0,0 @@
<?php
/**
* Dashboard Helper Functions
* File ini berisi function helper yang bisa digunakan langsung di view atau controller
*/
if (!function_exists('get_dashboard_status')) {
/**
* Mendapatkan status data untuk tipe izin tertentu
*/
function get_dashboard_status(string $type): array
{
return App\Helpers\DashboardHelper::getStatusDataByType($type);
}
}
if (!function_exists('get_dashboard_total')) {
/**
* Menambahkan total ke data statuses
*/
function get_dashboard_total(array $statuses): array
{
return App\Helpers\DashboardHelper::addTotalToStatuses($statuses);
}
}
if (!function_exists('dashboard_type_label')) {
/**
* Mendapatkan label untuk tipe izin
*/
function dashboard_type_label(string $type): string
{
return App\Helpers\DashboardHelper::getTypeLabel($type);
}
}
if (!function_exists('dashboard_status_icon')) {
/**
* Mendapatkan icon untuk status
*/
function dashboard_status_icon(string $statusId): string
{
return App\Helpers\DashboardHelper::getStatusIcon($statusId);
}
}
if (!function_exists('dashboard_card_background')) {
/**
* Mendapatkan background color untuk card
*/
function dashboard_card_background(string $statusId): string
{
return App\Helpers\DashboardHelper::getCardBackground($statusId);
}
}
if (!function_exists('dashboard_icon_circle_color')) {
/**
* Mendapatkan warna lingkaran icon
*/
function dashboard_icon_circle_color(string $statusId): string
{
return App\Helpers\DashboardHelper::getIconCircleColor($statusId);
}
}
if (!function_exists('dashboard_badge_color')) {
/**
* Mendapatkan badge color untuk tipe izin
*/
function dashboard_badge_color(string $type): string
{
return App\Helpers\DashboardHelper::getBadgeColor($type);
}
}
if (!function_exists('dashboard_percentage')) {
/**
* Menghitung persentase
*/
function dashboard_percentage(int $value, int $total): float
{
return App\Helpers\DashboardHelper::calculatePercentage($value, $total);
}
}
if (!function_exists('dashboard_trend')) {
/**
* Mendapatkan trend indicator
*/
function dashboard_trend(string $type, string $statusId): array
{
return App\Helpers\DashboardHelper::getTrendIndicator($type, $statusId);
}
}
if (!function_exists('dashboard_chart_data')) {
/**
* Mendapatkan data untuk chart
*/
function dashboard_chart_data(string $type): array
{
return App\Helpers\DashboardHelper::getChartData($type);
}
}

View File

@ -10,16 +10,12 @@ use App\Helpers\DashboardHelper;
class DashboardController extends Controller
{ public function index()
{
// Get all statistics for all types
$allStatistics = DashboardHelper::getAllStatistics();
// Get fastest data for types that have API endpoints
$allFastestData = DashboardHelper::getAllFastestData();
// Get terakhir terbit data for types that have API endpoints
$allTerakhirTerbitData = DashboardHelper::getAllTerakhirTerbitData();
// Default data for main view (PERTEK)
$statuses = DashboardHelper::getStatusDataByType('pertek');
$statuses = DashboardHelper::addTotalToStatuses($statuses);
$type = 'pertek';

View File

@ -1,77 +0,0 @@
#!/bin/bash
# Environment Check Script for Production Server
# Run this to verify server requirements
echo "🔍 Checking Production Environment..."
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Check PHP version
echo -e "\n${YELLOW}📋 PHP Version:${NC}"
php_version=$(php -v | head -n 1)
echo "$php_version"
# Check PHP extensions
echo -e "\n${YELLOW}📦 Required PHP Extensions:${NC}"
extensions=("curl" "json" "mbstring" "openssl" "pdo" "tokenizer" "xml" "zip")
for ext in "${extensions[@]}"; do
if php -m | grep -q "$ext"; then
echo -e "${GREEN}$ext${NC}"
else
echo -e "${RED}$ext (missing)${NC}"
fi
done
# Check Composer
echo -e "\n${YELLOW}🎵 Composer:${NC}"
if command -v composer &> /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}"

View File

@ -1,29 +0,0 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = require_once __DIR__ . '/bootstrap/app.php';
$app->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";

View File

@ -1,29 +0,0 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = require_once __DIR__ . '/bootstrap/app.php';
$app->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";

View File

@ -30,10 +30,7 @@
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
},
"files": [
"app/Helpers/dashboard_functions.php"
]
}
},
"autoload-dev": {
"psr-4": {

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,35 +0,0 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = require_once __DIR__ . '/bootstrap/app.php';
$app->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";
}

View File

@ -1,31 +0,0 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = require_once __DIR__ . '/bootstrap/app.php';
$app->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";
}