Dokumen ini memetakan seluruh folder dan file project majalah dinding digital, membedakan yang bawaan vs dibuat sendiri, file bawaan yang perlu diedit, serta alur komunikasi antar bagian.
Cara menjalankan (2 terminal + DB):
| Langkah | Folder / alat | Perintah | URL / hasil |
|---|---|---|---|
| DB | database/ | psql … -f schema.sql & seed.sql | DB mading |
| 1 | backend/ | npm run dev | http://localhost:5000 |
| 2 | frontend/ | npm run dev | http://localhost:5173 |
| Simbol | Arti |
|---|---|
| [B] | Bawaan — dari npm create vite, npm init, atau tool instalasi |
| [BUAT] | Dibuat sendiri — untuk kebutuhan latihan Mading Online |
| [EDIT] | File bawaan yang wajib/diperlukan diedit agar project jalan |
| [OPS] | Operasional — dihasilkan otomatis atau isinya dari penggunaan (upload, build) |
| [DOC] | Dokumentasi / materi belajar |
| [ARSIP] | Materi lama (sistem berita) — jangan dipakai sebagai panduan mading saat ini |
node_modules dan dist)Mading Online/ ← folder project (buka di VS Code / Cursor)
│
├── README.md [BUAT][DOC] setup, akun seed, endpoint ringkas
├── PERENCANAAN.md [BUAT][DOC] fitur, API, keputusan bisnis
├── STRUKTUR.md [BUAT][DOC] ringkasan tree (teks)
├── dbdiagram.md [BUAT][DOC] catatan diagram DB (opsional)
│
├── database/ [BUAT] skrip PostgreSQL (bukan MySQL)
│ ├── schema.sql [BUAT] enum + tabel users & posting
│ ├── seed.sql [BUAT] admin, penulis, post contoh
│ └── dbdiagram.sql [BUAT][DOC] referensi diagram
│
├── docs/ [BUAT][DOC]
│ ├── README.md [BUAT][DOC] petunjuk mana yang aktif / arsip
│ ├── materi-alur-mading-online.html [BUAT][DOC] panduan alur coding (aktif)
│ ├── STRUKTUR-PROJECT-mading-online.html [BUAT][DOC] ← file ini
│ ├── materi-alur-backend-news.html [ARSIP] portal berita lama
│ └── STRUKTUR-PROJECT-news.html [ARSIP] struktur berita lama
│
├── backend/ [BUAT] folder utama API (Express + PostgreSQL)
│ ├── server.js [BUAT][EDIT] pintu masuk API — CORS, JSON, static, mount route
│ ├── package.json [B][EDIT] dependensi: express, pg, bcrypt, jwt, multer, cors, dotenv
│ ├── package-lock.json [B][OPS]
│ ├── .env [BUAT][EDIT] rahasia: PORT, DB_*, JWT_SECRET, FRONTEND_URL
│ ├── .env.example [BUAT][DOC] contoh env (aman di-commit)
│ │
│ ├── config/
│ │ └── db.js [BUAT] pool koneksi PostgreSQL (pg)
│ │
│ ├── routes/
│ │ ├── authRoutes.js [BUAT] /api/auth — register, login, /me
│ │ ├── postRoutes.js [BUAT] /api/post — publik + CRUD author
│ │ └── adminRoutes.js [BUAT] /api/admin — users + post (wajib JWT admin)
│ │
│ ├── controllers/
│ │ ├── authController.js [BUAT] register, login, getMe, updateMe
│ │ ├── postController.js [BUAT] list/detail publik + CRUD milik author
│ │ ├── adminPostController.js [BUAT] CRUD penuh semua posting
│ │ └── adminUserController.js [BUAT] list/detail/update/hapus penulis
│ │
│ ├── models/
│ │ ├── userModel.js [BUAT] query tabel users
│ │ └── postModel.js [BUAT] query tabel posting
│ │
│ ├── middlewares/
│ │ ├── authMiddleware.js [BUAT] JWT → loadUser → requireRole
│ │ └── uploadMiddleware.js [BUAT] multer → uploads/post/
│ │
│ ├── utils/
│ │ ├── response.js [BUAT] helper JSON sukses/gagal seragam
│ │ ├── helpers.js [BUAT] util validasi / format kecil
│ │ └── fileHelper.js [BUAT] hapus file upload saat post dihapus
│ │
│ ├── scripts/ [BUAT] skrip bantu (audit API, gen hash, dll.)
│ │ ├── audit-api.js
│ │ └── genhash.js
│ │
│ └── uploads/
│ └── post/ [BUAT][OPS] file gambar hasil upload
│
└── frontend/ [B] kerangka React + Vite
├── index.html [B][EDIT] judul & meta Mading Online
├── vite.config.js [B][EDIT] plugin React, port dev
├── package.json [B][EDIT] react, react-router-dom, bootstrap
├── package-lock.json [B][OPS]
├── eslint.config.js [B]
├── .gitignore [B]
├── .env [BUAT][EDIT] VITE_API_URL=http://localhost:5000
├── .env.example [BUAT][DOC]
│
├── public/
│ ├── favicon.svg [B][EDIT]
│ └── placeholder-image.jpg [BUAT] gambar default jika post tanpa foto
│
├── dist/ [OPS] hasil npm run build
│
└── src/
├── main.jsx [B][EDIT] mount React + Bootstrap + App
├── App.jsx [B][EDIT] merender AppRoutes
│
├── routes/
│ └── index.jsx [BUAT] semua <Route> publik, author, admin
│
├── services/ [BUAT] layer HTTP ke backend
│ ├── api.js [BUAT] apiFetch, token, imageUrl, setAuth
│ ├── authService.js [BUAT] /api/auth/*
│ └── postService.js [BUAT] /api/post + /api/admin/*
│
├── constants/
│ └── site.js [BUAT] nama situs, rubrik, teks hardcode
│
├── components/
│ ├── ConfirmModal.jsx [BUAT] dialog konfirmasi hapus
│ ├── auth/
│ │ └── ProtectedRoute.jsx [BUAT] jaga /dashboard/* sesuai role
│ ├── layout/
│ │ ├── PublicLayout.jsx [BUAT] header/footer halaman publik
│ │ └── DashboardLayout.jsx [BUAT] sidebar + Outlet panel
│ └── post/
│ └── PostTable.jsx [BUAT] tabel post di dashboard
│
└── pages/
├── public/
│ ├── Home.jsx [BUAT] /
│ ├── ListPost.jsx [BUAT] /post (?kategori=)
│ ├── DetailPost.jsx [BUAT] /post/:id
│ ├── Login.jsx [BUAT] /login
│ └── Daftar.jsx [BUAT] /daftar
└── dashboard/
├── Profil.jsx [BUAT] profil bersama author & admin
├── author/
│ ├── Dashboard.jsx [BUAT] daftar post milik sendiri
│ └── FormPost.jsx [BUAT] tulis / edit post
└── admin/
├── Dashboard.jsx [BUAT] ringkasan statistik
├── ListPost.jsx [BUAT] kelola semua post
├── DetailPost.jsx [BUAT]
├── ListUser.jsx [BUAT] kelola penulis
├── DetailUser.jsx [BUAT]
└── EditUser.jsx [BUAT]
Tidak ditulis di tree (bawaan npm):
backend/node_modules/ — [B][OPS] paket Node backendfrontend/node_modules/ — [B][OPS] paket Node frontendfrontend/node_modules/.vite/ — [B][OPS] cache dev Vite| Folder | Asal | Keterangan |
|---|---|---|
database/ | [BUAT] | SQL PostgreSQL untuk DB mading |
backend/ | [BUAT] | Seluruh isi API dibuat untuk latihan; tidak dari template Vite |
frontend/ | [B] kerangka + [BUAT] isi src/ | Kerangka dari npm create vite; hampir semua file di src/ buatan latihan |
docs/ | [BUAT][DOC] | Materi belajar; bedakan file aktif vs arsip berita |
node_modules/ | [B][OPS] | Hasil npm install di masing-masing folder |
| File | Yang biasanya diubah |
|---|---|
index.html | Judul halaman, meta |
vite.config.js | Plugin React / port jika perlu |
package.json | Tambah bootstrap, react-router-dom |
.env / .env.example | VITE_API_URL=http://localhost:5000 |
src/main.jsx | Import Bootstrap + mount App |
src/App.jsx | Merender AppRoutes |
src/routes/index.jsx | [BUAT] Semua <Route> Mading Online |
| File | Keterangan |
|---|---|
eslint.config.js | Aturan lint default |
README.md (jika masih default Vite) | Opsional diperbarui |
Tidak ada scaffold Express otomatis seperti Vite. Yang paling mendekati “bawaan npm”:
| File | Asal |
|---|---|
package.json | [B] dari npm init, lalu [EDIT] dependencies & script dev |
package-lock.json | [B][OPS] |
Semua file .js di config/, routes/, controllers/, models/, middlewares/, utils/ adalah [BUAT].
Browser (:5173) Browser / Postman (:5000)
│ │
│ fetch JSON + JWT │
└──────────────────────────────────────►│ backend/server.js
│ │
│ ├─► routes/*.js
│ ├─► middlewares/
│ ├─► controllers/
│ ├─► models/
│ └─► config/db.js → PostgreSQL (mading)
│
◄──────────────────────────────────────┘ JSON + file /uploads/...
Frontend tidak memanggil PostgreSQL langsung. Semua data lewat REST API di backend/.
HTTP request
→ server.js (CORS, JSON body, static /uploads)
→ routes/auth|post|admin (cocokkan path + method)
→ middlewares/ (opsional: JWT, loadUser, role, multer)
→ controllers/ (validasi, aturan bisnis)
→ models/ (SQL SELECT / INSERT / UPDATE / DELETE)
→ config/db.js (pool pg)
→ PostgreSQL
← JSON { success, message, data? } ke client
Contoh: Penulis update post milik sendiri
FormPost.jsx → postService.updatePost() → PUT /api/post/:id → postRoutes.js → postController.update → postModel → tabel posting.
index.html
→ main.jsx (render React + Bootstrap)
→ App.jsx (AppRoutes)
→ routes/index.jsx (semua <Route>)
→ halaman di pages/ (Home, ListPost, FormPost, …)
→ komponen di components/
→ services/api.js (fetch + Authorization)
→ authService.js | postService.js
→ backend API
Contoh: Beranda menampilkan post terbaru
Home.jsx → getPosts({ limit }) → GET /api/post → postController.getAll → postModel → render kartu/list di UI.
Login.jsx
→ authService.login() → POST /api/auth/login
→ authController.login → bcrypt + jwt.sign
→ setAuth(token, user) → localStorage "token" + "user"
Request berikutnya (dashboard):
→ apiFetch() → Header: Authorization: Bearer <token>
→ authMiddleware → decode JWT
→ loadUserMiddleware → req.user dari DB
→ requireRole("admin" | "author") (jika dipakai)
→ controller
| Role | Prefix API | Halaman frontend |
|---|---|---|
| Publik | GET /api/post, GET /api/post/:id | /, /post, /post/:id |
| Author | /api/auth/me, /api/post/mine, CRUD /api/post | /dashboard/author/* |
| Admin | /api/admin/users, /api/admin/post | /dashboard/admin/* |
ProtectedRoute.jsx memblokir dashboard jika belum login atau role salah. Proteksi sesungguhnya tetap di middleware backend.
FormPost (frontend) — FormData + field "gambar"
→ postService.createPost / updatePost
atau createPostAdmin / updatePostAdmin
→ POST/PUT multipart /api/post atau /api/admin/post
→ middlewares/uploadMiddleware.js (multer)
→ uploads/post/<file>
→ controller simpan path ke kolom posting.gambar
→ JSON path: "/uploads/post/..."
Tampil di browser:
→ api.js imageUrl(path) → http://localhost:5000/uploads/post/...
→ jika kosong: /placeholder-image.jpg (public frontend)
| URL browser | File halaman | API utama |
|---|---|---|
/ | Home.jsx | GET /api/post |
/post | ListPost.jsx | GET /api/post?kategori= |
/post/:id | DetailPost.jsx | GET /api/post/:id |
/login, /daftar | Login.jsx, Daftar.jsx | POST /auth/login, /register |
/dashboard/author/* | pages/dashboard/author/* + layout | postService → /api/post |
/dashboard/admin/* | pages/dashboard/admin/* + layout | /api/admin/* |
.../profil | Profil.jsx | GET/PUT /api/auth/me |
Menu & rubrik hardcode: constants/site.js → layout publik / link filter.
| Tabel / enum | Model | Dipakai untuk |
|---|---|---|
users + enum user_role | userModel.js | login, register, profil, admin kelola penulis |
posting + enum kategori_posting | postModel.js | konten mading (4 rubrik) |
users (admin | author) ──menulis──> posting
author_id (FK)
Import awal: jalankan schema.sql lalu seed.sql, isi backend/.env.
database/schema.sql + seed.sql — pahami tabel & akun labbackend/server.js → routes/authRoutes.js → authController.jsfrontend/src/main.jsx → App.jsx → routes/index.jsx → pages/public/Home.jsxfrontend/src/services/api.js → postService.jsLogin.jsx + ProtectedRoute + JWT di authMiddleware.jsDashboard.jsx + FormPost.jsx → postRoutes.jsadmin/ListPost.jsx + ListUser.jsx → adminRoutes.jsdocs/materi-alur-mading-online.html + PERENCANAAN.mdpackage.json di root — backend dan frontend dijalankan terpisah (2 terminal).pg), bukan MySQL — beda dengan contoh toko latihan lain.frontend/dist/ hanya muncul setelah npm run build; untuk latihan cukup npm run dev.backend/uploads/post/ hasil upload nyata; jangan commit isi upload ke git.*-news.html di docs/ adalah arsip portal berita lama — jangan diikuti untuk path API mading saat ini.