Memahami frontend React + backend API Express untuk majalah dinding digital sekolah: alur sistem, alur coding, dan alur folder/file. Selaras dengan kode di project Mading Online dan PERENCANAAN.md.
Mading Online/ ← folder project (buka di VS Code / Cursor) ├── database/ ← schema.sql + seed.sql (PostgreSQL, DB: mading) ├── backend/ ← API Express + pg → http://localhost:5000 └── frontend/ ← React + Vite → http://localhost:5173
| Yang dijalankan | Terminal | Perintah | URL |
|---|---|---|---|
| Database | — | psql import schema & seed | PostgreSQL :5432 |
| API | 1 | cd backend lalu npm run dev | :5000 |
| Web | 2 | cd frontend lalu npm run dev | :5173 |
Jalankan kedua terminal (backend + frontend) — web butuh API sudah hidup dulu.
apiFetch.| Lapisan | Teknologi | Tugas |
|---|---|---|
| Frontend | React (Vite) + Bootstrap | Beranda, list/detail post, form login/daftar, dashboard |
| Backend | Express + PostgreSQL | Auth JWT, CRUD post, kelola penulis, kirim JSON |
Browser hanya menampilkan React. React memanggil API lewat apiFetch ke http://localhost:5000/api/....
[Siswa buka http://localhost:5173/login]
│
▼
Login.jsx → authService.login() → POST /api/auth/login
│ body: { email, password }
▼
authController.login → cek bcrypt → JWT + user.role ("admin" | "author")
│
▼
setAuth(token, user) → localStorage: "token" + "user"
│
▼
Navigate sesuai role:
admin → /dashboard/admin
author → /dashboard/author
│
▼
ProtectedRoute cek getUser().role → DashboardLayout (sidebar + konten)
POST /api/auth/login.role: "admin" vs "author"./dashboard/admin/* hanya jika role === "admin"; /dashboard/author/* hanya untuk penulis./daftar selalu membuat role author. Admin hanya dari database/seed.sql.Contoh panel penulis menulis post (/dashboard/author/post/tambah):
| Di browser (frontend) | Di server (backend) |
|---|---|
FormPost.jsx — form judul, ringkasan, isi, rubrik, gambar | POST /api/post (multipart, field gambar) |
| Dashboard penulis — daftar post milik sendiri | GET /api/post/mine |
| Edit post | PUT /api/post/:id |
| Hapus post | DELETE /api/post/:id |
Semua request yang butuh login memakai header:
Authorization: Bearer <token dari localStorage>
Diatur otomatis di frontend/src/services/api.js (apiFetch).
| Area / halaman | File halaman | API utama |
|---|---|---|
| Beranda | pages/public/Home.jsx | GET /api/post?limit=... |
| List Post (+ filter rubrik) | ListPost.jsx | GET /api/post?kategori=... |
| Detail Post | DetailPost.jsx | GET /api/post/:id |
| Daftar / Login | Daftar.jsx, Login.jsx | POST /api/auth/register, /login |
| Dashboard Penulis | author/Dashboard.jsx | GET /api/post/mine |
| Tulis / Edit Post | author/FormPost.jsx | CRUD /api/post |
| Dashboard Admin | admin/Dashboard.jsx | agregat dari list users + post |
| Kelola Post (admin) | admin/ListPost.jsx, dll. | /api/admin/post |
| Kelola Penulis | admin/ListUser.jsx, dll. | /api/admin/users |
| Profil | dashboard/Profil.jsx | GET/PUT /api/auth/me |
Routing: frontend/src/routes/index.jsx. Pemanggilan API: services/authService.js + services/postService.js.
| File | Fungsi |
|---|---|
components/layout/PublicLayout.jsx | Navbar + footer beranda / list / detail |
components/layout/DashboardLayout.jsx | Sidebar + area konten panel |
components/auth/ProtectedRoute.jsx | Blokir jika belum login / role salah |
components/post/PostTable.jsx | Tabel daftar post di dashboard |
components/ConfirmModal.jsx | Konfirmasi hapus |
constants/site.js | Nama web, rubrik, branding hardcode |
services/api.js | apiFetch, token, imageUrl |
Alur CRUD post penulis:
getMyPosts() → tabel di Dashboard.FormPost → createPost(FormData).FormPost + updatePost(id, FormData).ConfirmModal → deletePost(id) → reload daftar.┌─────────────┐ HTTP (JSON) ┌─────────────┐ SQL ┌────────────┐ │ Browser │ ◄──────────────────► │ Backend │ ◄──────────► │ PostgreSQL │ │ React Vite │ localhost:5000 │ Express │ │ DB: mading │ │ :5173 │ │ │ │ │ └─────────────┘ └─────────────┘ └────────────┘
| Pengguna | Frontend | Backend | Keterangan |
|---|---|---|---|
| Pengunjung | /, /post, /post/:id | GET /api/post, GET /api/post/:id | Tanpa login |
| Penulis | /daftar, /login → /dashboard/author/* | /api/auth/*, /api/post (CRUD milik sendiri) | JWT role author |
| Admin | /login → /dashboard/admin/* | /api/admin/... | JWT role admin (dari seed) |
/api/auth/... — daftar, login, profil sendiri./api/post/... — baca publik + CRUD post penulis./api/admin/... — kelola semua post + semua penulis; wajib token admin.Rubrik (kategori) | Arti di mading sekolah |
|---|---|
Berita Sekolah | Kegiatan, event, info sekolah |
Artikel | Tulisan / opini / edukasi (default) |
Kreatif | Puisi, cerpen, karya kreatif |
Prestasi | Juara, penghargaan |
Filter di UI: link ke /post?kategori=... — tidak ada route /kategori/:slug.
database/schema.sql, database/seed.sql.backend/.env (salin dari .env.example).cd backend → npm run dev. Terminal 2: cd frontend → npm run dev./login dengan akun seed admin./daftar (nama, email, kelas, jurusan, password) → role author./dashboard/author./api/post/mine + CRUD).Browser / React (apiFetch)
→ server.js (Express, CORS, JSON body, static /uploads)
→ routes/auth|post|admin (cocokkan URL + method)
→ middlewares/ (authMiddleware, loadUser, requireRole, multer)
→ controllers/ (validasi, aturan bisnis, status HTTP)
→ models/ (query SQL parameterized)
→ config/db.js (pool PostgreSQL / pg)
→ respons JSON { success, message, data? } balik ke React
Kenapa urutannya begitu? Route = peta URL, controller = logika, model = data. Ganti query cukup sentuh models/.
Halaman (mis. ListPost.jsx / FormPost.jsx)
→ postService.getPosts() / createPost()
→ api.js apiFetch() (tambah Bearer token, base URL + /api)
→ fetch → backend
→ setState → render UI
→ komponen (PostTable, ConfirmModal, …)
Konfigurasi: frontend/.env → VITE_API_URL=http://localhost:5000 (tanpa /api di akhir; path /api ditambah di apiFetch).
| Langkah | Lapisan | Apa yang terjadi |
|---|---|---|
| 1 | UI | ConfirmModal → konfirmasi |
| 2 | postService.js | DELETE /api/post/5 + Bearer |
| 3 | routes/postRoutes.js | → middleware auth + role author → postController.remove |
| 4 | Middleware | Cek JWT + role === author |
| 5 | Controller | Pastikan post milik user login, hapus file gambar jika ada |
| 6 | Model | DELETE FROM posting WHERE id = $1 (milik author) |
| 7 | UI | Reload daftar getMyPosts() |
DELETE /api/admin/post/:id → adminPostController (boleh hapus post siapa saja).backend/ ├── server.js ← ① PINTU MASUK ├── .env ← ② PORT, JWT_SECRET, DB_*, FRONTEND_URL ├── config/db.js ← ③ pool PostgreSQL ├── routes/authRoutes.js ← ④ /api/auth ├── routes/postRoutes.js ← ⑤ /api/post ├── routes/adminRoutes.js ← ⑥ /api/admin ├── middlewares/authMiddleware.js ← JWT, loadUser, requireRole ├── middlewares/uploadMiddleware.js← multer → uploads/post/ ├── controllers/ ← logika + JSON ├── models/userModel.js, postModel.js ├── utils/response.js, helpers.js, fileHelper.js └── uploads/post/
frontend/src/ ├── main.jsx, App.jsx ← ①② mount + AppRoutes ├── routes/index.jsx ← ③ semua <Route> ├── services/api.js ← ④ apiFetch + token ├── services/authService.js, postService.js ├── components/layout/, auth/, post/ ├── pages/public/ ← beranda, list, detail, login, daftar ├── pages/dashboard/author/ ← panel penulis ├── pages/dashboard/admin/ ← panel admin └── constants/site.js ← branding & rubrik
| Urutan | Baca / kerjakan | Kenapa |
|---|---|---|
| 1 | Import DB + jalankan backend & frontend + buka beranda | Pahami hasil dulu |
| 2 | routes/index.jsx + Home.jsx + ListPost.jsx | URL browser ↔ API publik |
| 3 | api.js + postService.js + authService.js | Cara React memanggil backend |
| 4 | routes/postRoutes.js + authRoutes.js | Daftar endpoint |
| 5 | postController.js + authController.js | Logika setelah request masuk |
| 6 | postModel.js + userModel.js | SQL & tabel posting / users |
| 7 | server.js + authMiddleware.js | Server menyambungkan semuanya |
| 8 | Panel author lalu admin — bandingkan /api/post vs /api/admin | Pahami beda hak akses |
| Folder | Peran | Catatan |
|---|---|---|
routes/ | Routing | URL → middleware → controller |
controllers/ | Controller | Validasi + JSON |
models/ | Model | SQL dengan $1, $2, … (pg) |
middlewares/ | Filter | Auth, role, upload |
config/ | Infrastruktur | Koneksi DB, bukan bisnis mading |
View HTML tidak ada di API — tampilan ada di React, backend hanya JSON.
Base: http://localhost:5000/api
/api/auth| Method | Path | Auth | Fungsi |
|---|---|---|---|
| POST | /register | Tidak | Daftar penulis (role dipaksa author) |
| POST | /login | Tidak | Login → JWT + data user |
| GET | /me | Bearer | Profil user login |
| PUT | /me | Bearer | Update profil sendiri |
/api/post| Method | Path | Auth | Fungsi |
|---|---|---|---|
| GET | / | Tidak | Daftar post (?kategori=&limit=&offset=) |
| GET | /:id | Tidak | Detail post |
| GET | /mine | Bearer author | Post milik penulis login |
| POST | / | Bearer author | Buat post (+ upload gambar) |
| PUT | /:id | Bearer author | Update post milik sendiri |
| DELETE | /:id | Bearer author | Hapus post milik sendiri |
/api/adminSemua route di bawah router.use(authMiddleware, loadUserMiddleware, requireRole("admin")).
| Method | Path | Fungsi |
|---|---|---|
| GET | /users | Daftar penulis |
| GET/PUT/DELETE | /users/:id | Detail / ubah / hapus penulis |
| GET/POST | /post | Daftar / tambah post (semua) |
| GET/PUT/DELETE | /post/:id | Detail / ubah / hapus post mana pun |
| Aksi | Publik | Penulis | Admin |
|---|---|---|---|
| Baca post | ya | ya | ya |
| Daftar akun | ya → author | — | — |
| Create / update / delete post | — | milik sendiri | semua post |
| Kelola penulis | — | — | ya |
| Update profil sendiri | — | ya | ya |
UPLOAD_MAX_MB (default 2 MB).| File | Fungsi |
|---|---|
database/schema.sql | Enum role & rubrik, tabel users + posting |
database/seed.sql | Admin + penulis contoh + post contoh mading |
database/dbdiagram.sql | Referensi diagram relasi (opsional) |
# Contoh setup (Windows / PowerShell sesuaikan path) psql -U postgres -c "CREATE DATABASE mading;" psql -U postgres -d mading -f database/schema.sql psql -U postgres -d mading -f database/seed.sql
Akun seed lab: admin admin@sekolah.sch.id / Admin123! — ganti di produksi.
Nama file model: postModel.js. Nama tabel di DB: posting.
| Topik | Nilai |
|---|---|
| Folder penyimpanan | backend/uploads/post/ |
| Akses file | http://localhost:5000/uploads/post/<namafile> |
| Author upload | POST/PUT /api/post (field form gambar) |
| Admin upload | POST/PUT /api/admin/post (field yang sama) |
| Middleware | uploadMiddleware.js → uploadPost.single("gambar") |
| Path di DB | Bentuk /uploads/post/... |
| Tampil di React | imageUrl(path) di api.js (+ placeholder jika kosong) |
Mading Online: React di :5173 menampilkan beranda & dashboard, lalu memanggil JSON API di :5000/api (/auth, /post, /admin) dengan JWT sesuai role.
Backend: setiap request mengalir server.js → routes → middlewares → controllers → models → PostgreSQL, lalu balik sebagai JSON ke React.