Panduan alur coding — Portal Berita (fullstack)
Memahami halaman publik + dashboard author/admin + backend API: alur sistem, alur coding, dan alur folder/file. Selaras dengan kode aktual proyek dan PERENCANAAN.md.
0 Gambaran project (tiga folder utama)
NEWS PKL/ ← folder project (buka di VS Code / Cursor)
├── database/ ← schema.sql + seed.sql (PostgreSQL)
├── backend/ ← API Express + pg → http://localhost:5000
└── frontend/ ← React + Vite → http://localhost:5173
| Yang dijalankan | Terminal | Perintah | URL |
| Database | — | Import schema.sql + seed.sql ke PostgreSQL | — |
| API | 1 | cd backend lalu npm run dev | :5000 |
| Web | 2 | cd frontend lalu npm run dev | :5173 |
Jalankan kedua terminal setelah database siap — web butuh API sudah hidup.
Penting: halaman React tidak mengakses PostgreSQL langsung. Jika backend mati, akan muncul Failed to fetch atau data kosong.
1 Frontend ↔ Backend (baca ini dulu)
1.1 Dua aplikasi terpisah
| Lapisan | Teknologi | Tugas |
| Frontend | React (Vite) + Bootstrap | Tampilan halaman, form, tabel, navigasi |
| Backend | Express + PostgreSQL (pg) | Simpan/baca data, cek login JWT, kirim JSON |
Browser hanya menampilkan React. React memanggil API lewat apiFetch di frontend/src/services/api.js ke http://localhost:5000/api/....
1.2 Login — dari tombol sampai dashboard
[Buka http://localhost:5173/login]
│
▼
Login.jsx → authService.login(email, password)
│ POST http://localhost:5000/api/auth/login
▼
authController.login → bcrypt.compare → JWT + { id, nama, email, role }
│
▼
setAuth(token, user) → localStorage "token" + "user"
│
▼
Navigate: role === "admin" → /dashboard/admin
role === "author" → /dashboard/author
│
▼
ProtectedRoute cek getUser().role → AdminLayout / AuthorLayout
- Satu halaman login untuk admin dan author (
POST /api/auth/login).
- Perbedaan akses ada di field
role: "admin" vs "author".
- Akun admin hanya dari
seed.sql. Pendaftaran publik (/daftar) selalu membuat author.
1.3 Contoh: author menulis berita
| Di browser (frontend) | Di server (backend) |
FormBerita.jsx — form + upload gambar | POST /api/berita (FormData) |
BeritaSaya.jsx — tabel berita saya | GET /api/berita/mine |
| Edit → form terisi data lama | GET /api/berita/:id lalu PUT /api/berita/:id |
| Hapus + konfirmasi | DELETE /api/berita/:id |
Request yang butuh login memakai header (otomatis di apiFetch):
Authorization: Bearer <token dari localStorage>
1.4 Peta halaman ↔ API utama
| Area | Halaman (contoh) | Service / API |
| Publik | Home.jsx, ListBerita.jsx, DetailBerita.jsx, Kategori.jsx | beritaService, infoWebService.getInfoWeb |
| Auth | Login.jsx, Daftar.jsx | authService.login / register |
| Author | Dashboard, BeritaSaya, FormBerita, Profil | /api/berita/mine, CRUD /api/berita, /api/auth/me |
| Admin | ListUser, ListBerita, InfoWeb, Profil | adminService → /api/admin/..., PUT /api/info-web |
Routing: frontend/src/routes/index.jsx. Panggilan API: folder frontend/src/services/.
1.5 Batasan penting (supaya tidak bingung)
- Author: CRUD berita milik sendiri saja. Tidak mengatur headline / info web / user lain.
- Admin: lihat semua berita, hapus, set/cabut headline. Tidak boleh create/edit isi berita.
- Admin: kelola author (list, detail, edit nama/email, hapus + cascade berita).
info_web: satu baris — admin hanya UPDATE (plus upload logo).
2 Alur sistem (siapa ngapain)
2.1 Diagram umum fullstack
┌─────────────┐ HTTP (JSON) ┌─────────────┐ SQL ┌────────────┐
│ Browser │ ◄──────────────────► │ Backend │ ◄──────────► │ PostgreSQL │
│ React Vite │ localhost:5000 │ Express │ │ (DB news) │
│ :5173 │ │ │ │ │
└─────────────┘ └─────────────┘ └────────────┘
2.2 Tiga area pengguna
| Pengguna | Frontend | Backend | Keterangan |
| Publik | /, /berita, /kategori/:slug | GET /api/berita, /headline, /info-web | Tanpa login |
| Author | /daftar, /login → /dashboard/author/* | /api/berita/mine, CRUD berita, /auth/me | JWT role author |
| Admin | /login → /dashboard/admin/* | /api/admin/..., PUT /info-web | JWT role admin |
2.3 Alur singkat: publik baca berita
- Buka Home →
getHeadline() + getBerita({ limit }) + getInfoWeb().
- Klik kartu →
/berita/:id → getBeritaById(id).
- Filter kategori →
/kategori/teknologi → getBerita({ kategori: "Teknologi" }).
2.4 Alur singkat: admin moderasi
- Login admin → dashboard hitung author/berita/headline dari API admin.
- List berita → set headline (
PATCH .../headline) atau cabut (DELETE .../headline).
- Hapus berita / hapus author → backend hapus record + file gambar di
uploads/.
- Info Web → form + FormData logo →
PUT /api/info-web.
3 Alur coding (satu request masuk sampai keluar)
3.1 Backend — urutan eksekusi (MVC API)
Browser / React (apiFetch)
→ server.js (Express, CORS, JSON, static /uploads)
→ routes/*.js (cocokkan URL + method)
→ middlewares/ (auth JWT, role, multer upload)
→ controllers/ (validasi, aturan bisnis, success/fail)
→ models/ (query SQL parameterized $1, $2, ...)
→ config/db.js (Pool PostgreSQL)
→ respons JSON balik ke React
Kenapa urutannya begitu? Route = peta URL, controller = logika, model = data. Ganti query cukup di models/.
3.2 Frontend — urutan eksekusi
Page (mis. BeritaSaya.jsx / Home.jsx)
→ services/beritaService.js (getBeritaSaya, getBerita, ...)
→ services/api.js apiFetch() (base URL + Bearer token)
→ fetch → backend
→ setState(...) → render (tabel / BeritaCard)
Konfigurasi: frontend/.env → VITE_API_URL=http://localhost:5000.
3.3 Contoh: author klik “Hapus berita”
| Langkah | Lapisan | Apa yang terjadi |
| 1 | UI | BeritaSaya.handleDelete(id) + confirm |
| 2 | beritaService.js | DELETE /api/berita/:id + Bearer |
| 3 | beritaRoutes.js | auth + role author → beritaController.remove |
| 4 | Controller | Cek berita milik req.user.id |
| 5 | Model | DELETE FROM berita WHERE id = $1 AND author_id = $2 |
| 6 | fileHelper | Hapus file di uploads/berita/... |
| 7 | UI | load() — ambil daftar lagi |
4 Alur folder & file (mulai baca dari mana)
4.1 Pohon folder backend (inti)
backend/
├── server.js ← ① PINTU MASUK
├── .env ← ② PORT, JWT_SECRET, DB_*, FRONTEND_URL
├── config/db.js ← ③ Pool PostgreSQL
├── routes/ ← ④ auth, berita, admin, infoWeb
├── middlewares/ ← ⑤ auth, role, upload
├── controllers/ ← logika + JSON
├── models/ ← SQL per tabel
├── utils/response.js, fileHelper.js
└── uploads/berita|logo|sosmed/
4.2 Pohon folder frontend (inti)
frontend/src/
├── main.jsx, App.jsx ← ①② entry + Router
├── routes/index.jsx ← ③ semua <Route> + ProtectedRoute
├── services/ ← ④ api.js + *Service.js
├── pages/public|dashboard/ ← halaman
├── components/layout|berita|home|auth|common
└── styles/custom.css
4.3 Urutan belajar (disarankan)
| Urutan | Baca / kerjakan | Kenapa |
| 1 | Jalankan DB + backend + frontend; buka Home & login seed | Pahami hasil dulu |
| 2 | routes/index.jsx + Home.jsx | URL browser ↔ fetch API |
| 3 | services/api.js + beritaService.js | Cara React memanggil backend |
| 4 | beritaRoutes.js → beritaController.js → beritaModel.js | Satu fitur end-to-end (MVC) |
| 5 | authRoutes + authMiddleware + ProtectedRoute | Login & proteksi role |
| 6 | Dashboard author lalu admin | Bedakan hak akses |
| 7 | server.js + database/schema.sql | Menyatukan semuanya |
4.4 Folder vs MVC
| Folder | Peran | Catatan |
routes/ | Routing | URL → middleware → controller |
controllers/ | Controller | Validasi + success() / fail() |
models/ | Model | SQL dengan $1, $2 |
middlewares/ | Filter | JWT, role, multer |
pages/ + components/ | View | React menampilkan JSON |
View HTML server tidak ada — tampilan ada di React; backend hanya JSON (+ file statis /uploads).
5 Ringkasan endpoint API
Base URL: http://localhost:5000/api
| Method | Path | Auth | Fungsi |
| POST | /auth/register | — | Daftar author |
| POST | /auth/login | — | Login → token + user |
| GET/PUT | /auth/me | JWT | Profil sendiri |
| GET | /berita, /headline, /:id | — | Baca berita publik |
| GET | /berita/mine | author | Berita milik saya |
| POST/PUT/DELETE | /berita, /berita/:id | author | CRUD milik sendiri |
| GET/PUT/DELETE | /admin/users... | admin | Kelola author |
| GET/DELETE | /admin/berita... | admin | Moderasi (tanpa edit isi) |
| PATCH/DELETE | /admin/berita/:id/headline | admin | Set / cabut headline |
| GET | /info-web | — | Baca info situs |
| PUT | /info-web | admin | Update info + logo |
6 Database (PostgreSQL)
| File | Fungsi |
database/schema.sql | CREATE TABLE + ENUM + relasi |
database/seed.sql | Admin, author contoh, berita, 1 baris info_web |
| Tabel | Model | Dipakai untuk |
users | userModel.js | Login, register, profil, kelola author |
berita | beritaModel.js | Portal berita + CRUD + headline |
info_web | infoWebModel.js | Nama situs, kontak, logo, sosmed (1 baris) |
Query wajib parameterized ($1, $2) — jangan gabung string user ke SQL.
7 Upload gambar
| Topik | Nilai |
| Middleware | uploadMiddleware.js (multer) |
| Berita | Field form gambar → uploads/berita/ |
| Info web | logo_web → uploads/logo/; logo_wa/logo_ig → uploads/sosmed/ |
| Batasan | jpg / png / webp; ukuran max dari UPLOAD_MAX_MB (default 2) |
| URL di browser | imageUrl(path) → http://localhost:5000/uploads/... |
| Fallback | public/placeholder-image.jpg + onError |
8 Ringkasan
- Frontend React dan backend Express adalah dua aplikasi; data lewat REST JSON.
- Backend mengikuti Routes → Middleware → Controller → Model → PostgreSQL.
- Frontend: Page → Service → apiFetch → setState → tampilan.
- Role menentukan dashboard dan endpoint: publik / author / admin.
- Pelajari satu fitur utuh dulu (misalnya list berita Home), baru perluas ke auth dan dashboard.
Dokumen pasangan: docs/STRUKTUR-PROJECT.html (peta folder & file). Acuan desain & aturan bisnis: PERENCANAAN.md.