# Padjajaran Elektrik — Dokumentasi Implementasi

Dokumen ini merangkum arsitektur, penggunaan CMS, keamanan, deployment, backup, pengujian, dan checklist peluncuran. Versi awal: 22 Agustus 2026.

## 1. Ringkasan tujuan website

Website dirancang untuk mengubah pencarian lokal terkait jasa instalasi listrik Bogor menjadi percakapan WhatsApp, telepon, formulir konsultasi, permintaan estimasi, pengiriman foto kondisi, dan jadwal survei. Sistem memisahkan website publik, CMS, autentikasi, database relasional, media, audit, serta konfigurasi integrasi.

Prinsip konten:

- jasa instalasi listrik adalah layanan utama;
- perbaikan dan maintenance menjadi layanan pendukung;
- data yang belum terverifikasi tidak ditampilkan di frontend;
- tidak ada statistik, testimoni, proyek, sertifikasi, alamat, atau afiliasi yang dikarang;
- hanya empat harga yang berhasil diverifikasi dimasukkan sebagai data awal;
- harga lain harus memakai status “Hubungi kami untuk estimasi”.

## 2. Sitemap

| Kelompok | URL |
| --- | --- |
| Utama | `/`, `/tentang-kami`, `/kontak`, `/faq` |
| Layanan | `/layanan`, `/layanan/[slug]` |
| Harga | `/harga-instalasi-listrik-bogor`, `/kalkulator-estimasi`, `/disclaimer-harga` |
| Lokal | `/area`, `/area/[slug]` |
| Bukti sosial | `/portofolio`, `/proyek/[slug]` |
| Konten | `/artikel`, `/artikel/[slug]`, `/feed.xml` |
| Kampanye | `/promo`; landing page baru disusun dari Page Builder |
| Konversi | `/permintaan-survei` |
| Legal | `/kebijakan-privasi`, `/syarat-dan-ketentuan` |
| Utilitas | `/search`, `/sitemap.xml`, `/robots.txt`, halaman 404 |
| CMS | `/cms/login`, `/cms/setup`, `/cms/dashboard` |

Slug layanan awal: `instalasi-listrik-rumah`, `instalasi-ruko-kantor`, `panel-listrik`, `tambah-titik-listrik`, `perbaikan-korsleting`, `grounding-system`, `penggantian-kabel`, dan `audit-maintenance`.

## 3. User flow

1. Pengunjung tiba dari Google, Google Maps, media sosial, atau kampanye.
2. Hero menjelaskan layanan, area Bogor, dan CTA survei/WhatsApp.
3. Pengunjung membaca layanan, masalah, proses, harga, atau halaman area.
4. Pengunjung menghitung estimasi awal atau mengisi formulir.
5. Sistem menyimpan lead, UTM, halaman asal, waktu, dan foto yang lolos validasi.
6. Sales/Super Admin mengubah status: Baru → Dihubungi → Dijadwalkan survei → Penawaran dikirim → Negosiasi → Menang/Kalah/Spam.
7. Percakapan dapat dilanjutkan melalui WhatsApp dengan template otomatis.

Alur CMS: login → verifikasi password dan MFA → dashboard sesuai peran → edit → draft/review/jadwal/publish → revision dan audit log.

## 4. Desain sistem

- Warna: hijau tua `#123D32`, hijau menengah `#2F6B5A`, sage `#98AEA3`, putih hangat `#F7F7F3`, abu muda `#ECEFEB`, charcoal `#1E2925`, aksen `#F2B84B`.
- Heading: Manrope/Plus Jakarta Sans; body: Inter/Plus Jakarta Sans dengan fallback sistem.
- Radius: 11–28 px sesuai hierarki; tombol utama berbentuk pil.
- Grid: maksimum 1180 px; section publik 70–112 px; mobile memiliki gutter 14 px.
- Foto: aset AI orisinal teknisi listrik Indonesia ber-APD, tanpa logo, teks, atau watermark.
- Accessibility: landmark semantik, label form, focus ring, navigasi keyboard, alt text, kontras tinggi, reduced motion, dan ukuran target sentuh.
- Tidak ada representasi visual fiktif untuk proyek atau testimoni.

## 5. Struktur homepage

Sticky header → hero → empat keunggulan → tentang → layanan berlatar hijau → masalah dan peringatan keselamatan → proses lima langkah → harga dan kalkulator → area layanan → FAQ → formulir lead → CTA foto → footer.

Portofolio, testimoni, alamat, peta, sosial, sertifikasi, legalitas, dan logo resmi disembunyikan sampai terverifikasi.

## 6. Arsitektur teknis

| Lapisan | Implementasi |
| --- | --- |
| UI | Next.js 16, React 19, TypeScript, Tailwind CSS 4 + CSS sistem |
| Rendering | Server rendering/static route generation; JavaScript klien hanya untuk interaksi |
| API | Route handlers server-side |
| Database | MySQL 8 melalui `mysql2` + Drizzle ORM/migration |
| Media | Folder privat `storage/` pada disk server; metadata di MySQL |
| Auth CMS | PBKDF2-SHA-256 100.000 iterasi (batas runtime) dengan server-side HMAC pepper terpisah, hash berversi, TOTP, dan session server-side |
| Deployment | Hosting Node.js/cPanel Node/VPS dengan reverse proxy HTTPS |
| Audit | Tabel append-only `audit_logs` untuk login dan perubahan penting |

Database memakai connection pool MySQL dan query terparameterisasi. File gambar tidak dimasukkan ke kolom database; hanya metadata dan kunci penyimpanannya yang disimpan di MySQL. Tidak ada data utama yang disimpan di `localStorage`.

## 7. Struktur database

Migration berada di `database/mysql/generated/` dan installer phpMyAdmin di `database/mysql/install.sql`. Terdapat 36 tabel aplikasi: roles, permissions, role_permissions, users, sessions, login_attempts, verification_tokens, pages, page_blocks, page_versions, reusable_blocks, posts, post_versions, categories, tags, post_categories, post_tags, services, price_categories, price_items, promotions, faqs, projects, project_media, testimonials, service_areas, media, menus, menu_items, site_settings, seo_settings, redirects, leads, form_submissions, audit_logs, dan backups. Migration CLI juga membuat tabel internal `pe_migrations`.

Konten penting memiliki `deleted_at` untuk soft delete. Harga menyimpan status aktif, harga promo, satuan, tipe harga, urutan, tanggal verifikasi, dan sumber.

## 8. Matriks role dan permission

| Modul/aksi | Super Admin | Penulis Artikel | Sales Promotion |
| --- | :---: | :---: | :---: |
| Semua pengaturan & keamanan | ✓ | — | — |
| User/role, audit, backup | ✓ | — | — |
| Halaman utama dan harga | ✓ | — | — |
| Buat/edit artikel sendiri | ✓ | ✓ | — |
| Publish artikel | ✓ | Review | — |
| Media untuk artikel | ✓ | ✓ | Sesuai kampanye |
| Promo, banner, periode, CTA | ✓ | — | ✓ |
| Landing page block terkontrol | ✓ | — | ✓ |
| JavaScript/iframe/HTML bebas | — | — | — |
| Lead | Semua | — | Sesuai izin/kampanye |

Pemeriksaan izin dilakukan kembali pada API server, bukan hanya pada tampilan tombol.

## 9–13. Source, backend, migration, seed, environment

- Frontend: `app/`, terutama `page.tsx`, `components/`, dan halaman rute.
- Backend/API: `app/api/`.
- CMS: `app/cms/` dan `app/components/cms-ui.tsx`.
- Database: `db/schema.ts`, `db/runtime.ts`, dan `database/mysql/generated/`.
- Seed: `database/mysql/seed.sql` memuat role, page, block, layanan, harga, FAQ, pengaturan, dan sepuluh artikel berstatus draft/noindex.
- Environment contoh: `.env.example`. Nilai rahasia tidak boleh masuk source code.

## 14. Instalasi lokal

Prasyarat: Node.js minimal 22.13, npm, dan MySQL minimal 8.0.13.

1. Buat database MySQL kosong ber-charset `utf8mb4`.
2. Salin `.env.example` menjadi `.env.local`, lalu isi `DATABASE_URL` dan seluruh secret.
3. Jalankan `npm ci`.
4. Jalankan `npm run db:setup`, kemudian `npm run db:check`.
5. Jalankan mode pengembangan melalui `npm run dev`.
6. Jalankan pengujian: `npm test`.

Panduan Windows, phpMyAdmin, cPanel, dan VPS tersedia di `docs/MYSQL-HOSTING.md`.

## 15. Deployment

1. Buat database dan user MySQL dengan hak hanya untuk database aplikasi.
2. Atur `DATABASE_URL`, `SESSION_SECRET`, `PASSWORD_PEPPER`, `BACKUP_ENCRYPTION_KEY`, `SETUP_TOKEN`, `OWNER_RECOVERY_TOKEN`, `SUPER_ADMIN_EMAIL`, dan `SITE_BASE_URL` sebagai environment production.
3. Jalankan `npm ci`, `npm run db:setup`, `npm run build`, lalu `npm start`.
4. Pastikan folder `storage/` dapat ditulis dan dibackup.
5. Lakukan setup Super Admin ketika website masih dibatasi.
6. Hubungkan domain, HTTPS, canonical URL, dan integrasi Google.
7. Buka akses publik hanya setelah konten, legalitas, backup, notifikasi, dan monitoring siap.

## 16. Pembuatan Super Admin

Tidak ada akun atau password default.

1. Set `SUPER_ADMIN_EMAIL` ke email pemilik yang terverifikasi.
2. Buka `/cms/setup` ketika website masih dibatasi dan masukkan `SETUP_TOKEN` dari environment.
3. Isi nama dan password minimal 12 karakter (huruf besar, kecil, dan angka; hindari password umum).
4. Tunggu secret TOTP yang dibuat server, lalu tambahkan sebagai kunci berbasis waktu (SHA-1, 6 digit, 30 detik) ke aplikasi authenticator.
5. Masukkan kode enam digit terbaru. Jika secret dibuat ulang, hapus entri lama dan gunakan secret terbaru.
6. Endpoint setup otomatis menolak pembuatan kedua setelah tabel user terisi.

Simpan recovery procedure MFA di tempat terpisah sebelum website dipublikasikan.

## 17. Penggunaan CMS

- Dashboard: ringkasan halaman, draft, lead, dan harga.
- Page Builder: tambahkan block tervalidasi, drag untuk mengurutkan, sembunyikan, hapus, simpan draft, atau publish sesuai izin.
- Pages: slug, template, jadwal, index/noindex, canonical, CTA, dan revision.
- Artikel: rich content terstruktur; SEO title, meta description, canonical, OG, keyword, heading, alt text, internal link, TOC, related article, waktu baca, dan workflow.
- Harga: tambah/ubah/nonaktifkan/urutkan/promo; update dicatat di audit log.
- Promo: periode aktif, banner, CTA, template WhatsApp, landing page, dan ringkasan lead.
- Konten kosong tidak muncul di frontend sampai aktif/terverifikasi.

## 18. Integrasi GA4 dan Search Console

1. CMS → SEO & Integrasi → Google.
2. Isi GA4 Measurement ID atau GTM Container ID; jangan memasukkan keduanya jika GTM sudah memuat GA4.
3. Isi meta verification Search Console atau unggah file verifikasi melalui media terkontrol.
4. Alternatif DNS: tambahkan TXT record yang diberikan Google pada pengelola DNS domain.
5. Submit `/sitemap.xml` ke Google Search Console dan Bing Webmaster Tools.
6. Aktifkan consent banner sebelum analytics non-esensial.
7. Pastikan mode development dan sesi administrator dikecualikan dari analytics.

ID integrasi disimpan sebagai pengaturan server/runtime, bukan hard-coded di source.

## 19. Backup dan restore

Kebijakan awal yang disarankan:

- database: harian, retensi 14 harian + 8 mingguan + 6 bulanan;
- media: versioning/object replication sesuai kebutuhan;
- audit log: minimal 180 hari;
- backup dienkripsi dan checksum disimpan pada tabel `backups`;
- uji restore sekurang-kurangnya per kuartal.

Urutan restore: bekukan write → ekspor backup MySQL saat ini → validasi checksum backup target → restore database MySQL → restore/verifikasi folder `storage/` → jalankan smoke test login, halaman, harga, form lead, dan redirect → buka write kembali → catat audit pemulihan.

Jangan menganggap backup valid sebelum restore test berhasil.

## 20. Hasil pengujian

Production build memeriksa seluruh route publik, API, CMS, halaman dinamis, sitemap, feed, dan integrasi MySQL. Test suite otomatis lulus **17/17** dan memeriksa build Next.js, schema/migration/seed MySQL, tidak ada credential admin default, hashing/MFA/rate limit/session, WYSIWYG, page builder, upload, leads CSV, keamanan, backup, dan larangan penyimpanan browser sebagai database. Lint lulus tanpa error dengan beberapa warning non-blocking.

QA browser memverifikasi hierarchy visual homepage, gambar hero, halaman detail layanan, seluruh gambar informatif memiliki alt text, seluruh tombol memiliki accessible name, 13 label formulir terbaca, dan tidak ada horizontal overflow pada viewport desktop preview. CSS menyediakan breakpoint khusus untuk 1100, 900, dan 650 px; pemeriksaan perangkat nyata 360/390/768 px tetap menjadi butir pra-peluncuran.

Pengujian manual yang harus dilakukan setelah Super Admin dibuat: setup, login benar/salah, MFA, lockout, logout, role writer/sales, publish page, revision restore, update harga, kirim form+foto aman, penolakan file berbahaya, scheduled promo, dan backup/restore.

## 21. Checklist sebelum peluncuran

- [ ] Logo resmi diunggah dan alt text diisi.
- [ ] Alamat, pin Maps, legalitas, dan sertifikasi diverifikasi.
- [ ] Nomor WhatsApp/telepon placeholder diganti.
- [ ] Email notifikasi lead diuji.
- [ ] Portofolio dan testimoni asli diinput beserta sumber.
- [ ] Semua harga dikonfirmasi administrator dan disclaimer ditinjau.
- [ ] GA4/GTM, consent, Search Console, sitemap, dan robots diuji.
- [ ] Super Admin + MFA aktif; akun writer/sales memakai izin minimum.
- [ ] Password reset provider dan notifikasi login dikonfigurasi.
- [ ] CSP diperketat dengan nonce bila integrasi script eksternal ditambah.
- [ ] Scan dependency dan security header lulus.
- [ ] Form spam/rate limit dan upload berbahaya diuji.
- [ ] Responsive 360, 390, 768, 1366, dan 1440 px diperiksa.
- [ ] Lighthouse diuji pada domain production dalam jaringan stabil.
- [ ] Backup terenkripsi selesai dan restore test berhasil.
- [ ] Broken link scan dan review copy final selesai.
- [ ] Website tetap privat sampai seluruh butir kritis siap.

## Catatan keamanan

Tidak ada sistem yang dapat dijanjikan 100% anti-hacker. Implementasi ini memakai pertahanan berlapis: password hashing kuat, TOTP wajib Super Admin, session rotation/invalidation, rate limit dan lockout, cookie Secure/HttpOnly/SameSite, same-origin write check, validasi server, query terparameterisasi, CSP, HSTS, anti-clickjacking, MIME/magic-byte/size upload validation, nama file acak, secrets di environment, audit log, dan error publik tanpa stack trace.

Password reset satu-kali, CAPTCHA pihak ketiga, email notifikasi, malware scanning, EXIF stripping server-side, vulnerability monitoring, dan backup otomatis memerlukan provider production yang dipilih sebelum akses publik.
