# ARCHITECTURE & DEVELOPER GUIDE

## 🏗️ Sistem Architecture

### High-Level Architecture Diagram
```
┌─────────────────────────────────────────────────────────────────────┐
│                        End User Browser                             │
│                 (Public / Admin / Pegawai Client)                    │
└───────────────────────────┬─────────────────────────────────────────┘
                            │
           ┌────────────────┼────────────────┐
           │                │                │
   ┌───────▼────────┐ ┌────▼─────────┐ ┌────▼──────────────┐
   │  Public Forms  │ │   Pegawai    │ │  Admin Dashboard  │
   │  (Kode Akses)  │ │   Portal     │ │  (Multi-Role)     │
   │                │ │ (Auth: pegawai)│ │  (Auth: admin/    │
   │ • Landing Page │ │              │ │   super_admin)    │
   │ • Office Code  │ │ • Dashboard  │ │                   │
   │ • Pendataan    │ │ • Assessment │ │ • Dashboard       │
   │ • Correction   │ │ • Password   │ │ • Pegawai CRUD    │
   └───────┬────────┘ └──────┬───────┘ │ • Jabatan         │
           │                 │         │ • Unit Kerja       │
           │                 │         │ • Assessment       │
           │                 │         │ • Kode Akses       │
           │                 │         │ • Admin Users      │
           │                 │         │ • Validation Log   │
           │                 │         └────────┬───────────┘
           │                 │                  │
   ┌───────▼─────────────────▼──────────────────▼─────────────────┐
   │                  Laravel 11 Application                       │
   │                                                               │
   │  ┌───────────────────────────────────────────────────────┐   │
   │  │              Web Routes & Controllers                  │   │
   │  │                                                       │   │
   │  │  • PegawaiFormController (Public - Kode Akses)        │   │
   │  │  • PegawaiController (Admin - CRUD + Validasi)        │   │
   │  │  • JabatanFungsionalController (Super Admin - CRUD)   │   │
   │  │  • DashboardController (Admin - Analytics)            │   │
   │  │  • UnitKerjaController (Super Admin - CRUD)           │   │
   │  │  • AdminUserController (Super Admin - CRUD)           │   │
   │  │  • PegawaiDashboardController (Pegawai - Portal)      │   │
   │  │  • PegawaiAccountController (Admin - Akun Pegawai)    │   │
   │  │  • PegawaiAssessmentKompetensiController (Pegawai)    │   │
   │  │  • AdminAssessmentKompetensiController (Admin)        │   │
   │  │  • AssessmentKompetensiMasterController (Super Admin) │   │
   │  │  • KodeAksesKantorController (Admin)                  │   │
   │  │  • ValidationHistoryController (Super Admin)          │   │
   │  │  • AuthenticatedSessionController (Login)             │   │
   │  └───────────────────────────────────────────────────────┘   │
   │                                                               │
   │  ┌──────────────┐  ┌──────────────┐  ┌────────────────────┐  │
   │  │  Middleware   │  │   Services   │  │     Support        │  │
   │  │              │  │              │  │                    │  │
   │  │ • Auth       │  │ • PegawaiEmail│  │ • PegawaiOptions  │  │
   │  │ • Admin      │  │   Service    │  │ • PerencanaanSuk- │  │
   │  │ • SuperAdmin │  │ • Assessment │  │   sesiOptions     │  │
   │  │ • Pegawai    │  │   Kompetensi │  │                    │  │
   │  │ • CSRF       │  │   Service    │  │                    │  │
   │  └──────────────┘  └──────────────┘  └────────────────────┘  │
   │                                                               │
   │  ┌──────────────────────────────────────────────────────────┐ │
   │  │                    Models (15)                            │ │
   │  │                                                          │ │
   │  │  User · Pegawai · JabatanFungsional · JenjangJabatan    │ │
   │  │  PegawaiFile · UnitKerja · KodeAksesKantor              │ │
   │  │  PegawaiValidationHistory · PegawaiJabatanHistory       │ │
   │  │  Kompetensi · IndikatorKompetensi                       │ │
   │  │  StandarKompetensiJabatan · AssessmentKompetensi        │ │
   │  │  AssessmentPengembangan · RekomendasiPelatihan          │ │
   │  └──────────────────────────────────────────────────────────┘ │
   │                                                               │
   │  ┌──────────────────────────────────────────────────────────┐ │
   │  │           Mail & Email Notifications                      │ │
   │  │  • PendataanPegawaiSubmitted (Mailable)                  │ │
   │  │  • Signed URL Correction Links                           │ │
   │  │  • Login Account Credentials                             │ │
   │  └──────────────────────────────────────────────────────────┘ │
   │                                                               │
   │  ┌──────────────────────────────────────────────────────────┐ │
   │  │            Blade Templates & Views                        │ │
   │  │  • Layouts (app, admin)                                  │ │
   │  │  • Public (landing, office-code, form, success)          │ │
   │  │  • Admin (dashboard, pegawai, jabatan, unit-kerja,       │ │
   │  │    admin-users, assessment, kode-akses, validation-log)  │ │
   │  │  • Pegawai (dashboard, assessment, change-password)      │ │
   │  │  • Auth (login) · Emails (pendataan-submitted)           │ │
   │  └──────────────────────────────────────────────────────────┘ │
   │                                                               │
   │  ┌──────────────────────────────────────────────────────────┐ │
   │  │         Database Layer (Eloquent ORM)                     │ │
   │  │  - Query Building & Scopes (KodeAksesKantor::masihBerlaku)│ │
   │  │  - Relationship Management (BelongsTo, HasMany, HasOne)  │ │
   │  │  - Validation & Rule Objects                             │ │
   │  │  - Database Transactions (Kode Akses Quota Locking)      │ │
   │  └──────────────────────────────────────────────────────────┘ │
   └───────────────────────────┬───────────────────────────────────┘
                               │
           ┌───────────────────┴────────────────────┐
           │                                        │
       ┌───▼──────┐                        ┌──────▼──────┐
       │  MySQL   │                        │  Storage    │
       │ Database │                        │  (Files)    │
       │          │                        │             │
       │ 28 migr. │                        │ pegawai-    │
       │ 7 seeders│                        │ files/      │
       └──────────┘                        └─────────────┘
```

## 📁 Project Structure

```
Skripsi-M/
│
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Auth/
│   │   │   │   └── AuthenticatedSessionController.php    # Login/logout handler
│   │   │   ├── PegawaiFormController.php                 # Public form + kode akses + correction
│   │   │   ├── PegawaiController.php                     # Admin CRUD + validasi
│   │   │   ├── JabatanFungsionalController.php           # Jabatan management (Super Admin)
│   │   │   ├── DashboardController.php                   # Admin dashboard & analytics
│   │   │   ├── UnitKerjaController.php                   # Unit Kerja management (Super Admin)
│   │   │   ├── AdminUserController.php                   # Admin user management (Super Admin)
│   │   │   ├── PegawaiDashboardController.php            # Pegawai portal dashboard
│   │   │   ├── PegawaiAccountController.php              # Manage pegawai login accounts
│   │   │   ├── PegawaiAssessmentKompetensiController.php # Pegawai self-assessment
│   │   │   ├── AdminAssessmentKompetensiController.php   # Admin assessment review
│   │   │   ├── AssessmentKompetensiMasterController.php  # Assessment master data (Super Admin)
│   │   │   ├── KodeAksesKantorController.php             # Office access code management
│   │   │   └── ValidationHistoryController.php           # Validation audit log (Super Admin)
│   │   │
│   │   └── Middleware/
│   │       ├── AdminMiddleware.php                       # admin + super_admin access
│   │       ├── SuperAdminMiddleware.php                  # super_admin only access
│   │       └── PegawaiMiddleware.php                     # pegawai role access
│   │
│   ├── Mail/
│   │   └── PendataanPegawaiSubmitted.php                 # Email notification mailable
│   │
│   ├── Models/
│   │   ├── User.php                                      # Auth user (admin/super_admin/pegawai)
│   │   ├── Pegawai.php                                   # Pegawai data record
│   │   ├── JabatanFungsional.php                         # Job position
│   │   ├── JenjangJabatan.php                            # Position level/tier
│   │   ├── PegawaiFile.php                               # Uploaded files
│   │   ├── UnitKerja.php                                 # Work unit/department
│   │   ├── KodeAksesKantor.php                           # Office access codes
│   │   ├── PegawaiValidationHistory.php                  # Validation audit trail
│   │   ├── PegawaiJabatanHistory.php                     # Position change history
│   │   ├── Kompetensi.php                                # Competency definitions
│   │   ├── IndikatorKompetensi.php                       # Competency indicators
│   │   ├── StandarKompetensiJabatan.php                  # Competency standards per jabatan
│   │   ├── AssessmentKompetensi.php                      # Assessment answers
│   │   ├── AssessmentPengembangan.php                    # Development plan
│   │   └── RekomendasiPelatihan.php                      # Training recommendations
│   │
│   ├── Services/
│   │   ├── PegawaiEmailService.php                       # Email sending + account creation
│   │   └── AssessmentKompetensiService.php               # Assessment calculation logic
│   │
│   ├── Support/
│   │   ├── PegawaiOptions.php                            # Pendidikan & golongan options
│   │   └── PerencanaanSuksesiOptions.php                 # Succession planning options
│   │
│   └── Providers/
│       └── AppServiceProvider.php                        # Bootstrap Five pagination
│
├── database/
│   ├── migrations/
│   │   ├── 0001_01_01_000000_create_users_table.php
│   │   ├── 0001_01_01_000001_create_cache_table.php
│   │   ├── 0001_01_01_000002_create_jobs_table.php
│   │   ├── 2025_05_12_000003_add_role_to_users_table.php
│   │   ├── 2025_05_12_000004_create_jabatan_fungsional_table.php
│   │   ├── 2025_05_12_000005_create_pegawai_table.php
│   │   ├── 2025_05_12_000006_create_pegawai_files_table.php
│   │   ├── 2026_05_12_000001_add_email_status_to_pegawai_table.php
│   │   ├── 2026_05_12_000002_create_unit_kerja_table.php
│   │   ├── 2026_05_12_000003_add_super_admin_role_to_users_table.php
│   │   ├── 2026_05_12_000004_create_pegawai_validation_histories_table.php
│   │   ├── 2026_05_20_000001_add_unit_kerja_id_to_jabatan_fungsional_table.php
│   │   ├── 2026_05_20_000002_add_unit_kerja_id_to_users_table.php
│   │   ├── 2026_05_20_000003_add_golongan_to_pegawai_table.php
│   │   ├── 2026_05_20_000004_add_pegawai_role_and_link_to_users_table.php
│   │   ├── 2026_05_20_000005_add_must_change_password_to_users_table.php
│   │   ├── 2026_05_21_000004_create_pegawai_jabatan_histories_table.php
│   │   ├── 2026_05_21_000005_add_nomor_sk_and_status_to_pegawai_jabatan_histories_table.php
│   │   ├── 2026_05_21_000006_add_previous_and_current_jabatan_to_...table.php
│   │   ├── 2026_05_21_000007_create_jenjang_jabatan_table_and_link_jabatan_fungsional.php
│   │   ├── 2026_05_21_000013_normalize_pegawai_pendidikan_terakhir.php
│   │   ├── 2026_05_25_000001_create_assessment_kompetensi_tables.php
│   │   ├── 2026_05_25_000002_create_assessment_pengembangan_table.php
│   │   ├── 2026_05_25_000003_add_detail_karier_to_assessment_pengembangan_table.php
│   │   ├── 2026_06_10_000001_create_kode_akses_kantor_table.php
│   │   ├── 2026_06_10_000002_add_catatan_karier_to_assessment_pengembangan_table.php
│   │   ├── 2026_06_10_000003_add_detail_pengembangan_kompetensi_to_...table.php
│   │   └── 2026_06_23_000001_add_jenjang_jabatan_id_to_indikator_kompetensi_table.php
│   │
│   └── seeders/
│       ├── DatabaseSeeder.php                            # Main seeder
│       ├── AdminSeeder.php                               # Create admin users
│       ├── JabatanFungsionalSeeder.php                   # Default positions + jenjang
│       ├── UnitKerjaSeeder.php                           # Default unit kerja
│       ├── PegawaiSeeder.php                             # Sample pegawai data
│       ├── KodeAksesKantorSeeder.php                     # Sample office codes
│       └── AssessmentKompetensiSeeder.php                # Kompetensi + indikator + standar + rekomendasi
│
├── resources/
│   ├── views/
│   │   ├── layouts/
│   │   │   ├── app.blade.php                             # Public layout
│   │   │   └── admin.blade.php                           # Admin layout (sidebar)
│   │   │
│   │   ├── public/
│   │   │   ├── landing.blade.php                         # Landing/home page
│   │   │   ├── office-code.blade.php                     # Kode akses kantor entry
│   │   │   ├── form.blade.php                            # Pegawai form (new + correction)
│   │   │   └── success.blade.php                         # Success page
│   │   │
│   │   ├── admin/
│   │   │   ├── dashboard.blade.php                       # Admin dashboard
│   │   │   ├── pegawai/
│   │   │   │   ├── index.blade.php                       # Pegawai list (validated)
│   │   │   │   ├── show.blade.php                        # Pegawai detail + validation
│   │   │   │   ├── create.blade.php                      # Manual pegawai create
│   │   │   │   └── edit.blade.php                        # Edit pegawai
│   │   │   ├── jabatan/
│   │   │   │   ├── index.blade.php                       # Jabatan list
│   │   │   │   ├── create.blade.php                      # Create jabatan
│   │   │   │   ├── edit.blade.php                        # Edit jabatan
│   │   │   │   └── detail.blade.php                      # Jabatan detail by nama
│   │   │   ├── unit-kerja/
│   │   │   │   ├── index.blade.php                       # Unit kerja list
│   │   │   │   ├── create.blade.php                      # Create unit kerja
│   │   │   │   └── edit.blade.php                        # Edit unit kerja
│   │   │   ├── admin-users/
│   │   │   │   ├── index.blade.php                       # Admin user list
│   │   │   │   ├── create.blade.php                      # Create admin user
│   │   │   │   └── edit.blade.php                        # Edit admin user
│   │   │   ├── assessment-kompetensi/
│   │   │   │   ├── index.blade.php                       # Assessment list
│   │   │   │   ├── show.blade.php                        # Assessment detail + pengembangan
│   │   │   │   └── recap.blade.php                       # Assessment recap
│   │   │   ├── assessment-master/
│   │   │   │   └── index.blade.php                       # Master data management
│   │   │   ├── kode-akses-kantor/
│   │   │   │   └── index.blade.php                       # Access code management
│   │   │   ├── pegawai-accounts/
│   │   │   │   └── index.blade.php                       # Pegawai account management
│   │   │   ├── validation-histories/
│   │   │   │   └── index.blade.php                       # Validation audit log
│   │   │   ├── kompetensi/                               # (empty, reserved)
│   │   │   ├── pemetaan-kompetensi/                      # (empty, reserved)
│   │   │   └── promotions/                               # (empty, reserved)
│   │   │
│   │   ├── pegawai/
│   │   │   ├── dashboard.blade.php                       # Pegawai portal home
│   │   │   ├── change-password.blade.php                 # Change password
│   │   │   └── assessment-kompetensi/
│   │   │       ├── form.blade.php                        # Self-assessment form
│   │   │       ├── hasil.blade.php                       # Assessment results
│   │   │       └── rekomendasi.blade.php                 # Training recommendations
│   │   │
│   │   ├── auth/
│   │   │   └── login.blade.php                           # Login page
│   │   │
│   │   └── emails/
│   │       └── pendataan-submitted.blade.php             # Email template
│   │
│   └── css/
│       └── app.css                                       # Custom styles
│
├── routes/
│   ├── web.php                                           # Web routes
│   └── console.php                                       # Console commands
│
├── storage/
│   ├── app/
│   │   └── public/
│   │       └── pegawai-files/                            # Uploaded files
│   ├── framework/
│   └── logs/
│
├── bootstrap/
│   └── app.php                                           # Middleware registration
│
├── config/
│   ├── app.php
│   ├── auth.php
│   ├── database.php
│   ├── filesystems.php
│   └── mail.php
│
├── public/
│   ├── index.php                                         # Entry point
│   └── storage/                                          # Symbolic link
│
├── .env
├── .env.example
├── composer.json
├── package.json
├── vite.config.js
├── phpunit.xml
├── artisan
│
├── SETUP_GUIDE.md
├── QUICK_START.md
├── API_DOCUMENTATION.md
├── SQL_REFERENCES.md
├── PROJECT_SUMMARY.md
├── DEPLOYMENT_CHECKLIST.md
├── README.md
├── README_FINAL.md
└── ARCHITECTURE.md                                       # This file
```

## 🔑 Role & Access Control

### User Roles
| Role          | Deskripsi                        | Akses                                                  |
|---------------|----------------------------------|---------------------------------------------------------|
| `super_admin` | Super Administrator              | Semua fitur admin + master data + manajemen admin user  |
| `admin`       | Admin SDM BKPSDM                 | Dashboard, pegawai CRUD, validasi, assessment, kode akses |
| `pegawai`     | Pegawai (login via akun)         | Dashboard pegawai, assessment kompetensi, ubah password  |

### Middleware
```
AdminMiddleware       → isAdmin() → role in ['admin', 'super_admin']
SuperAdminMiddleware  → isSuperAdmin() → role === 'super_admin'
PegawaiMiddleware     → isPegawai() → role === 'pegawai'
```

## 🔄 Data Flow

### 1. Public Form Submission Flow (with Kode Akses Kantor)
```
User visits /pendataan
       ↓
Show office code entry form (office-code.blade.php)
       ↓
User enters Kode Akses Kantor
       ↓
PegawaiFormController::verifyOfficeCode()
       ↓
Validate kode: active, not expired, quota remaining
       ↓
Store kode_akses_kantor_id in session
       ↓
Show pendataan form (locked to unit kerja)
       ↓
Submit form (POST)
       ↓
PegawaiFormController::store()
       ↓
Validate input (nip unique, jabatan matches unit kerja)
       ↓
DB::transaction → Lock kode akses, create Pegawai, increment usage
       ↓
Handle file upload → Create PegawaiFile
       ↓
PegawaiEmailService::send() → Confirmation email
       ↓
Clear session kode → Redirect to success page
```

### 2. Admin Validation Flow
```
Admin checks dashboard
       ↓
Views pending / submissions count
       ↓
Navigates to /admin/pendataan-masuk
       ↓
PegawaiController::submissions()
       ↓
Clicks to view detail
       ↓
PegawaiController::show()
       ↓
Display pegawai data + documents
       ↓
Admin selects status (disetujui/ditolak) + catatan
       ↓
PegawaiController::updateValidation()
       ↓
Create PegawaiValidationHistory record
       ↓
Update Pegawai status_validasi
       ↓
If disetujui → Auto-create login account (PegawaiEmailService)
       ↓
Send email notification with status + correction link (if ditolak)
```

### 3. Rejected Submission Correction Flow
```
Pegawai receives rejection email with signed URL
       ↓
Click correction link (valid 7 days)
       ↓
PegawaiFormController::editRejected() (signed middleware)
       ↓
Verify status === 'ditolak'
       ↓
Show form pre-filled with existing data
       ↓
Submit corrections
       ↓
PegawaiFormController::updateRejected()
       ↓
Update pegawai, delete+reupload file if changed
       ↓
Set status → pending, catatan_penolakan → null
       ↓
Send updated email notification
```

### 4. Authentication Flow
```
User visits /login
       ↓
AuthenticatedSessionController::create()
       ↓
Submit credentials (email + password)
       ↓
AuthenticatedSessionController::store()
       ↓
Attempt authentication
       ↓
If success:
  ├── Role = admin/super_admin → Redirect /admin/dashboard
  └── Role = pegawai → Check must_change_password
       ├── true → Redirect /pegawai/ubah-password
       └── false → Redirect /pegawai/dashboard
       ↓
If failed:
  → Show error, redirect back to /login
```

### 5. Assessment Kompetensi Flow
```
Pegawai login → /pegawai/assessment-kompetensi
       ↓
PegawaiAssessmentKompetensiController::form()
       ↓
AssessmentKompetensiService::standar() → Load standar per jabatan aktif
       ↓
Filter IndikatorKompetensi by jenjang_jabatan_id
       ↓
Show assessment form (ya/tidak per indikator)
       ↓
Submit → PegawaiAssessmentKompetensiController::store()
       ↓
Save AssessmentKompetensi records (status: submitted)
       ↓
View hasil → AssessmentKompetensiService::hasil()
       ↓
Calculate: total, ya, tidak, persentase, kategori
       ↓
Show rekomendasi pelatihan for kompetensi perlu pengembangan
       ↓
Admin verifies → AdminAssessmentKompetensiController::verify()
       ↓
Update status → verified + fill AssessmentPengembangan
```

## 🔐 Database Relationships

### Entity Relationship Diagram (ERD)
```
┌──────────────────────┐
│       users          │
├──────────────────────┤
│ id (PK)              │
│ name                 │
│ email (UQ)           │
│ password             │
│ role                 │──── 'super_admin' | 'admin' | 'pegawai'
│ unit_kerja_id (FK)   │─────┐
│ pegawai_id (FK)      │──┐  │
│ must_change_password │  │  │
│ email_verified_at    │  │  │
│ timestamps           │  │  │
└──────────────────────┘  │  │
                          │  │
         ┌────────────────┘  │
         │ (1:1)              │
         ▼                    │
┌────────────────────────┐   │     ┌────────────────────┐
│       pegawai          │   │     │    unit_kerja       │
├────────────────────────┤   │     ├────────────────────┤
│ id (PK)                │   │     │ id (PK)            │
│ nip (UQ)               │   └────►│ nama_unit          │
│ nama_lengkap           │         │ timestamps         │
│ tempat_lahir           │         └───────┬────────────┘
│ tanggal_lahir          │                 │
│ jenis_kelamin          │                 │ 1    *
│ alamat                 │                 ▼
│ no_hp                  │   ┌─────────────────────────────┐
│ email                  │   │   jabatan_fungsional        │
│ unit_kerja             │   ├─────────────────────────────┤
│ pendidikan_terakhir    │   │ id (PK)                     │
│ golongan               │   │ nama_jabatan                │
│ jabatan_fungsional_id  │──►│ jenjang_jabatan_id (FK)     │───┐
│ tanggal_mulai_jabatan  │   │ kategori                    │   │
│ status_validasi        │   │ unit_kerja_id (FK)          │   │
│ catatan_penolakan      │   │ timestamps                  │   │
│ email_status           │   └────────┬────────────────────┘   │
│ email_sent_at          │            │                         │
│ email_error            │            │ 1    *                  │
│ timestamps             │            ▼                         ▼
└──────┬─────────────────┘   standar_kompetensi_jabatan   ┌─────────────────────┐
       │                     ┌──────────────────────┐     │  jenjang_jabatan    │
       │ 1    *              │ id (PK)              │     ├─────────────────────┤
       ├────────────────────►│ jabatan_fungsional_id│     │ id (PK)             │
       │  pegawai_files      │ kompetensi_id (FK)   │     │ kode                │
       │  ┌─────────────┐    │ level                │     │ nama_jenjang        │
       │  │ id (PK)     │    │ deskripsi            │     │ kategori            │
       │  │ pegawai_id  │    │ timestamps           │     │ golongan_min        │
       │  │ nama_file   │    └──────────────────────┘     │ golongan_max        │
       │  │ tipe_file   │                                 │ usia_pensiun        │
       │  │ path        │    ┌──────────────────────┐     │ sort_order          │
       │  │ timestamps  │    │    kompetensi        │     │ timestamps          │
       │  └─────────────┘    ├──────────────────────┤     └─────────────────────┘
       │                     │ id (PK)              │
       │ 1    *              │ nama_kompetensi      │
       ├────────────────┐    │ jenis_kompetensi     │──── 'manajerial' | 'sosial_kultural' | 'teknis'
       │                │    │ deskripsi            │
       │                │    │ timestamps           │
       │  pegawai_      │    └──────┬──────┬────────┘
       │  validation_   │           │      │
       │  histories     │      1  * │      │ 1    *
       │  ┌──────────┐  │           ▼      ▼
       │  │ id       │  │   indikator_   rekomendasi_
       │  │pegawai_id│  │   kompetensi   pelatihan
       │  │admin_id  │  │   ┌──────────┐ ┌──────────────┐
       │  │status_   │  │   │id        │ │id            │
       │  │sebelumnya│  │   │kompeten- │ │kompetensi_id │
       │  │status_   │  │   │ si_id    │ │nama_pelatihan│
       │  │baru      │  │   │jenjang_  │ │jenis_        │
       │  │catatan   │  │   │jabatan_id│ │pelatihan     │
       │  │timestamps│  │   │kode_     │ │bentuk_       │
       │  └──────────┘  │   │indikator │ │pelatihan     │
       │                │   │pertanyaan│ │deskripsi     │
       │ 1    *         │   │timestamps│ │status        │
       ├──────────┐     │   └──────────┘ │timestamps    │
       │          │     │        │        └──────────────┘
       │  pegawai_│     │        │ 1    *
       │  jabatan_│     │        ▼
       │  histories     │   assessment_kompetensi
       │  ┌──────────┐  │   ┌──────────────┐
       │  │ id       │  │   │ id           │
       │  │pegawai_id│  │   │ pegawai_id   │─── from pegawai
       │  │jabatan_  │  │   │ indikator_   │
       │  │fungsional│  │   │ kompetensi_id│
       │  │_id       │  │   │ jawaban      │──── 'ya' | 'tidak'
       │  │nama_     │  │   │ periode_tahun│
       │  │jabatan   │  │   │ status       │──── 'draft'|'submitted'|'verified'
       │  │jenjang   │  │   │ timestamps   │
       │  │golongan  │  │   └──────────────┘
       │  │tgl_mulai │  │
       │  │jabatan_  │  │   assessment_pengembangan
       │  │sebelumnya│  │   ┌─────────────────────────┐
       │  │jenjang_  │  │   │ id                      │
       │  │sebelumnya│  └──►│ pegawai_id              │
       │  │jabatan_  │      │ periode_tahun           │
       │  │saat_ini  │      │ dikembangkan_karier     │
       │  │jenjang_  │      │ dikembangkan_kompetensi │
       │  │saat_ini  │      │ bentuk_pengembangan_    │
       │  │sk_file_id│      │   karier                │
       │  │nomor_sk  │      │ waktu_pelaksanaan_tahun │
       │  │status    │      │ prosedur_pengisian_     │
       │  │admin_id  │      │   jabatan               │
       │  │catatan   │      │ mekanisme_pengisian_    │
       │  │timestamps│      │   jabatan               │
       │  └──────────┘      │ catatan_pengembangan_   │
       │                    │   karier                 │
       │                    │ hasil_penilaian_         │
       │                    │   kompetensi             │
       │                    │ sejarah_karier           │
       │                    │ hasil_penilaian_kinerja  │
       │                    │ perencanaan_suksesi      │
       │                    │ timestamps               │
       │                    └─────────────────────────┘
       │
       │                ┌──────────────────────────┐
       │                │   kode_akses_kantor      │
       │                ├──────────────────────────┤
       │                │ id (PK)                  │
       │                │ unit_kerja_id (FK)       │
       │                │ created_by (FK → users)  │
       │                │ kode (UQ)                │
       │                │ batas_penggunaan         │
       │                │ jumlah_digunakan         │
       │                │ kedaluwarsa_pada         │
       │                │ aktif                    │
       │                │ timestamps               │
       │                └──────────────────────────┘
```

### Relationship Definitions

#### User
```php
// Belongs to UnitKerja (admin scoping)
public function unitKerja(): BelongsTo → UnitKerja

// Belongs to Pegawai (pegawai role linkage)
public function pegawai(): BelongsTo → Pegawai

// Role methods
isAdmin(): bool     // role in ['admin', 'super_admin']
isSuperAdmin(): bool // role === 'super_admin'
isPegawai(): bool   // role === 'pegawai'
```

#### Pegawai (Central Entity)
```php
public function jabatan(): BelongsTo → JabatanFungsional
public function files(): HasMany → PegawaiFile
public function validationHistories(): HasMany → PegawaiValidationHistory
public function jabatanHistories(): HasMany → PegawaiJabatanHistory
public function assessmentKompetensi(): HasMany → AssessmentKompetensi
public function user(): HasOne → User

// Accessors
getStatusLabelAttribute(): string
getRetirementInfoAttribute(): ?array // Calculates pension info from jenjang
```

#### JabatanFungsional
```php
public function pegawai(): HasMany → Pegawai
public function standarKompetensi(): HasMany → StandarKompetensiJabatan
public function unitKerja(): BelongsTo → UnitKerja
public function jenjangJabatan(): BelongsTo → JenjangJabatan

// Accessors
getJenjangAttribute(): ?string
getJenjangLabelAttribute(): string
getNamaJabatanLengkapAttribute(): string
```

#### JenjangJabatan
```php
public function jabatanFungsional(): HasMany → JabatanFungsional

// Accessors
getRentangGolonganAttribute(): string // e.g. "III/a - III/b"
```

#### UnitKerja
```php
public function jabatanFungsional(): HasMany → JabatanFungsional
public function admins(): HasMany → User
public function kodeAksesKantor(): HasMany → KodeAksesKantor
```

#### KodeAksesKantor
```php
public function unitKerja(): BelongsTo → UnitKerja
public function pembuat(): BelongsTo → User (created_by)

// Scope
scopeMasihBerlaku(Builder): Builder // active, not expired, quota remaining

// Methods
masihBisaDigunakan(): bool
getSisaPenggunaanAttribute(): int
getStatusLabelAttribute(): string // Aktif | Dinonaktifkan | Kedaluwarsa | Kuota Habis
```

#### Kompetensi
```php
public function indikator(): HasMany → IndikatorKompetensi
public function standarJabatan(): HasMany → StandarKompetensiJabatan
public function rekomendasiPelatihan(): HasMany → RekomendasiPelatihan
```

#### IndikatorKompetensi
```php
public function kompetensi(): BelongsTo → Kompetensi
public function jenjangJabatan(): BelongsTo → JenjangJabatan
public function assessments(): HasMany → AssessmentKompetensi
```

## 🎯 Request Routing

### Public Routes (Tanpa Login)
```
GET  /                              → Landing page (public.landing)
GET  /pendataan                     → PegawaiFormController@show (office code / form)
POST /pendataan/akses               → PegawaiFormController@verifyOfficeCode
POST /pendataan/ganti-kode          → PegawaiFormController@clearOfficeCode
POST /pendataan                     → PegawaiFormController@store
GET  /pendataan/{pegawai}/perbaiki  → PegawaiFormController@editRejected (signed)
POST /pendataan/{pegawai}/perbaiki  → PegawaiFormController@updateRejected (signed)
GET  /pendataan/{pegawai}/success   → PegawaiFormController@success
GET  /pegawai-files/{file}          → PegawaiFormController@showFile (signed)
```

### Auth Routes
```
GET  /login                         → AuthenticatedSessionController@create (guest)
POST /login                         → AuthenticatedSessionController@store (guest)
POST /logout                        → AuthenticatedSessionController@destroy (auth)
```

### Pegawai Routes (Protected by 'auth' & 'pegawai' middleware)
```
GET  /pegawai/dashboard                        → PegawaiDashboardController@index
GET  /pegawai/ubah-password                    → PegawaiDashboardController@editPassword
POST /pegawai/ubah-password                    → PegawaiDashboardController@updatePassword
GET  /pegawai/assessment-kompetensi            → PegawaiAssessmentKompetensiController@form
POST /pegawai/assessment-kompetensi            → PegawaiAssessmentKompetensiController@store
GET  /pegawai/assessment-kompetensi/hasil      → PegawaiAssessmentKompetensiController@hasil
GET  /pegawai/assessment-kompetensi/rekomendasi→ PegawaiAssessmentKompetensiController@rekomendasi
```

### Admin Routes (Protected by 'auth' & 'admin' middleware)
```
GET  /admin/dashboard                          → DashboardController@index

GET  /admin/pendataan-masuk                    → PegawaiController@submissions
GET  /admin/pegawai                            → PegawaiController@index
GET  /admin/pegawai/create                     → PegawaiController@create
POST /admin/pegawai                            → PegawaiController@store
GET  /admin/pegawai/{id}                       → PegawaiController@show
GET  /admin/pegawai/{id}/edit                  → PegawaiController@edit
PUT  /admin/pegawai/{id}                       → PegawaiController@update
POST /admin/pegawai/{id}/validation            → PegawaiController@updateValidation

GET  /admin/akun-pegawai                       → PegawaiAccountController@index
POST /admin/akun-pegawai/{pegawai}             → PegawaiAccountController@store
POST /admin/akun-pegawai/{pegawai}/reset-password → PegawaiAccountController@resetPassword

GET  /admin/assessment-kompetensi              → AdminAssessmentKompetensiController@index
GET  /admin/assessment-kompetensi/rekap        → AdminAssessmentKompetensiController@recap
GET  /admin/assessment-kompetensi/{pegawai}    → AdminAssessmentKompetensiController@show
POST /admin/assessment-kompetensi/{pegawai}/pengembangan → AdminAssessmentKompetensiController@updatePengembangan
POST /admin/assessment-kompetensi/{pegawai}/verify       → AdminAssessmentKompetensiController@verify

GET  /admin/kode-akses-kantor                  → KodeAksesKantorController@index
POST /admin/kode-akses-kantor                  → KodeAksesKantorController@store
PATCH /admin/kode-akses-kantor/{id}/toggle     → KodeAksesKantorController@toggle
DELETE /admin/kode-akses-kantor/{id}           → KodeAksesKantorController@destroy
```

### Super Admin Routes (Protected by 'auth' & 'admin' & 'super_admin' middleware)
```
RESOURCE /admin/admin-users                    → AdminUserController (index, create, store, edit, update, destroy)
GET  /admin/validation-histories               → ValidationHistoryController@index

GET  /admin/master-assessment-kompetensi       → AssessmentKompetensiMasterController@index
POST /admin/master-assessment-kompetensi/kompetensi  → ...@storeKompetensi
POST /admin/master-assessment-kompetensi/indikator   → ...@storeIndikator
POST /admin/master-assessment-kompetensi/standar     → ...@storeStandard
POST /admin/master-assessment-kompetensi/rekomendasi → ...@storeRekomendasi

RESOURCE /admin/unit-kerja                     → UnitKerjaController (index, create, store, edit, update, destroy)

GET  /admin/jabatan/detail/{namaJabatan}       → JabatanFungsionalController@detail
RESOURCE /admin/jabatan                        → JabatanFungsionalController (index, create, store, edit, update, destroy)
```

## 🛡️ Middleware Stack

### Request Middleware Stack
```
Request
   ↓
Laravel 11 Global Middleware (auto-configured)
   ↓
Route Middleware (web group)
   ↓
Route-Specific Middleware (registered in bootstrap/app.php)
   ├── guest (for login page)
   ├── signed (for correction URLs, file access)
   ├── auth (for protected routes)
   │    ├── pegawai → PegawaiMiddleware (pegawai portal)
   │    └── admin → AdminMiddleware (admin/super_admin)
   │         └── super_admin → SuperAdminMiddleware (super_admin only)
   ↓
Controller Action
```

## 📝 Validation Rules

### Pegawai Form Validation (Public)
```php
[
    'nip' => ['required', 'string', 'max:20', Rule::unique('pegawai', 'nip')],
    'nama_lengkap' => 'required|string|max:255',
    'tempat_lahir' => 'required|string|max:255',
    'tanggal_lahir' => 'required|date|before:today',
    'jenis_kelamin' => 'required|in:Laki-laki,Perempuan',
    'alamat' => 'required|string|max:1000',
    'no_hp' => ['required', 'string', 'max:20', 'regex:/^(\+62|62|0)[0-9]{9,12}$/'],
    'email' => 'required|email|max:255',
    'unit_kerja' => ['required', 'string', Rule::in([$kodeAkses->unitKerja->nama_unit])],
    'pendidikan_terakhir' => ['required', Rule::in(PegawaiOptions::pendidikan())],
    'golongan' => ['required', Rule::in(PegawaiOptions::golongan())],
    'jabatan_fungsional_id' => 'required|exists:jabatan_fungsional,id',
    'tanggal_mulai_jabatan' => 'required|date',
    'file' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:5120',  // 5MB max
]
```

### Additional Business Validations
- Jabatan fungsional must belong to the selected unit kerja
- Kode akses kantor must be active, not expired, and have remaining quota
- Correction form only available when `status_validasi === 'ditolak'`
- NIP uniqueness enforced (ignoring self on correction)

## 🎨 Frontend Architecture

### Layout Hierarchy
```
app.blade.php (Public)
├── navbar
├── alerts (success/error)
├── content area
└── footer

admin.blade.php (Admin)
├── sidebar navigation (role-aware menu items)
├── topbar (user info + logout)
├── content area
└── alerts
```

### Component Reusability
- **Form components** reuse between create/edit/correction
- **Shared alert template** for errors/success via session flash
- **Pagination** included in listing pages (Bootstrap 5 via `Paginator::useBootstrapFive()`)
- **Modal** for confirmation dialogs (delete, validate)
- **Assessment form** reusable between pegawai self-assessment and admin view

## 📊 Session Management

### Session Configuration
```env
SESSION_DRIVER=database
SESSION_LIFETIME=120  # minutes
SESSION_ENCRYPT=false
```

### Session Data Stored
```php
// Auth session
auth()->user()                              // Current logged-in user

// Flash data
session('success')
session('error')

// Custom session (Kode Akses Kantor)
session('kode_akses_kantor_id')            // Active office code ID
```

## 📧 Email System

### PegawaiEmailService
- **Mode: `submitted`** — Konfirmasi pendataan baru
- **Mode: `status_updated`** — Notifikasi update status validasi
- **Login account email** — Kirim credential akun pegawai
- **Log mode detection** — Handles `MAIL_MAILER=log` gracefully
- **Error tracking** — Stores `email_status`, `email_sent_at`, `email_error` on pegawai

### Signed URLs
- Correction links expire in **7 days**
- File access uses signed routes for security

## 🔍 Query Optimization

### Eager Loading Used
```php
// Controllers use with() for relationships
Pegawai::with('jabatan', 'files', 'jabatan.jenjangJabatan')
JabatanFungsional::with('jenjangJabatan', 'unitKerja')
JabatanFungsional::withCount('pegawai')
AssessmentKompetensi with indikator.kompetensi chains
```

### Scopes
```php
KodeAksesKantor::masihBerlaku() // active + not expired + quota remaining
```

### Database Transactions
```php
// Kode Akses quota locking during form submission
DB::transaction(function () {
    $lockedCode = KodeAksesKantor::lockForUpdate()->first();
    // Create pegawai + increment usage atomically
});
```

## 🧩 Service Layer

### AssessmentKompetensiService
- `jabatanAktif(Pegawai)` — Resolve active jabatan from history or current
- `standar(Pegawai)` — Load competency standards filtered by jenjang
- `jawaban(Pegawai, tahun)` — Get assessment answers keyed by indikator ID
- `hasil(Pegawai, tahun)` — Calculate full assessment results (percentage, category)
- `rekomendasi(Collection)` — Fetch training recommendations for weak competencies
- `kategori(float)` — Map percentage to category label:
  - ≥ 100% → Terpenuhi
  - ≥ 75% → Hampir Terpenuhi
  - ≥ 50% → Perlu Pengembangan
  - < 50% → Prioritas Pengembangan

### PegawaiEmailService
- `send(Pegawai, mode, ?loginAccount)` — Send email notification
- `createLoginAccount(Pegawai)` — Auto-create User with role `pegawai`

## 🚀 Performance Considerations

1. **Pagination**: All lists use pagination (Bootstrap 5)
2. **Eager Loading**: Relationships loaded upfront to avoid N+1
3. **Database Indexes**: Applied on foreign keys and search fields
4. **File Uploads**: With size limits (5MB max per file)
5. **Database Transactions**: Used for atomic operations (kode akses quota)
6. **Pessimistic Locking**: `lockForUpdate()` prevents race conditions on kode akses
7. **Signed URLs**: Prevents unauthorized access to correction forms and files

## 📚 Code Style & Standards

### PSR-12 Compliance
- 4-space indentation
- Line length max 120 characters
- Namespace at top
- Use statements grouped

### Model Conventions
```php
// Singular class name
class Pegawai extends Model {
    // Lowercase, snake_case table name
    protected $table = 'pegawai';
}
```

### Controller Conventions
```php
// Resource controller methods
index()   - List
create()  - Create form
store()   - Save
show()    - Detail
edit()    - Edit form
update()  - Save changes
destroy() - Delete

// Custom actions
submissions()       - Pendataan masuk list
updateValidation()  - Approve/reject pegawai
verify()            - Verify assessment
```

### PHP 8.1+ Features Used
- `match()` expressions for status labels
- Constructor promotion in Mailables
- Null-safe operator `?->` for optional relationships
- Named arguments
- PHP Attributes (`#[Fillable]`, `#[Hidden]`) on User model
- Spread operator `...` in arrays

---

**Architecture Version:** 2.0
**Last Updated:** 24 Juni 2026
