update: pemisahan
parent
77b17978a4
commit
e0fb72af83
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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!**
|
|
@ -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
|
||||
```
|
|
@ -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
|
|
@ -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`
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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}"
|
|
@ -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";
|
|
@ -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";
|
|
@ -30,10 +30,7 @@
|
|||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
},
|
||||
"files": [
|
||||
"app/Helpers/dashboard_functions.php"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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";
|
||||
}
|
|
@ -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";
|
||||
}
|
Loading…
Reference in New Issue