Memahami frontend admin + backend API, lalu alur sistem, alur coding, dan alur folder/file. Selaras dengan backend/ALUR-CODING.md.
testfullstack/ ← folder project (buka di VS Code / Cursor) ├── backend/ ← API Express + MySQL → http://localhost:5000 └── frontend/ ← React + Vite → http://localhost:5173
| Yang dijalankan | Terminal | Perintah | URL |
|---|---|---|---|
| API | 1 | cd backend lalu npm run dev | :5000 |
| Web | 2 | cd frontend lalu npm run dev | :5173 |
Jalankan kedua terminal — web butuh API sudah hidup dulu.
| Lapisan | Teknologi | Tugas |
|---|---|---|
| Frontend | React (Vite) | Tampilan halaman, form, tabel, modal |
| Backend | Express + MySQL | Simpan/baca data, cek login, kirim JSON |
Browser hanya menampilkan React. React memanggil API lewat fetch ke http://localhost:5000.
[Siswa buka http://localhost:5173/login]
│
▼
LoginPage.jsx → POST http://localhost:5000/api/users/login
│ body: { email, passwd }
▼
usersController (backend) → cek password → JWT + role: "admin"
│
▼
AuthContext.jsx menyimpan token di localStorage
│
▼
Navigate ke /admin → RequireAuth cek role === "admin"
│
▼
AdminLayout (sidebar + konten)
/api/users/login).role di JWT: "admin" vs "pembeli"./admin/* hanya boleh dibuka jika role === "admin".Contoh halaman Produk (/admin/produk):
| Di browser (frontend) | Di server (backend) |
|---|---|
AdminProdukPage.jsx — tabel + Tambah / Detail / Ubah / Hapus | GET /api/admin/produk |
| Klik Detail → modal | GET /api/admin/produk/:id |
| Klik Ubah → form modal | PUT /api/admin/produk/:id |
| Klik Hapus → konfirmasi | DELETE /api/admin/produk/:id |
| Tombol Tambah | POST /api/admin/produk |
| Upload gambar produk | POST /api/admin/upload-gambar → path di kolom gambar |
Semua request admin memakai header:
Authorization: Bearer <token dari localStorage>
Diatur di frontend/src/api/http.js (authHeaders()).
| Menu / halaman | File halaman | API utama (/api/admin/...) |
|---|---|---|
| Dashboard | AdminOverviewPage.jsx | GET /stats |
| Produk | AdminProdukPage.jsx | CRUD /produk, upload gambar |
| Pembeli | AdminPembeliPage.jsx | GET /pembeli, CRUD /users/:id |
| Pesanan | AdminPembelianPage.jsx | GET/PUT/DELETE /pembelian |
| Artikel | AdminArtikelPage.jsx | CRUD /artikel |
| Kontak | AdminKontakPage.jsx | GET/PUT/DELETE /kontak |
| Info toko | AdminInfoTokoPage.jsx | GET/PUT /info-toko |
| Profil | AdminProfilPage.jsx | GET/PUT /me |
Routing: frontend/src/App.jsx. API: frontend/src/api/adminApi.js.
| File | Fungsi |
|---|---|
layouts/AdminLayout.jsx | Sidebar + area konten |
components/admin/AdminSidebar.jsx | Menu navigasi |
context/AdminShopContext.jsx | Logo + nama toko di sidebar (dari DB) |
components/admin/AdminRowActions.jsx | Tombol Detail · Ubah · Hapus |
components/admin/AdminDetailModal.jsx | Modal baca saja |
components/admin/AdminModal.jsx | Modal form tambah/ubah |
hooks/useAdminList.js | Ambil daftar + loading/error |
hooks/useAdminGuard.js | Redirect jika token habis / bukan admin |
Alur CRUD (misalnya Kontak):
useAdminList(adminApi.getKontak) → tabel.getKontakById → AdminDetailModal.AdminModal + updateKontak.deleteKontak + reload().┌─────────────┐ HTTP (JSON) ┌─────────────┐ SQL ┌──────────┐ │ Browser │ ◄──────────────────► │ Backend │ ◄──────────► │ MySQL │ │ React Vite │ localhost:5000 │ Express │ │ toko DB │ │ :5173 │ │ │ │ │ └─────────────┘ └─────────────┘ └──────────┘
| Pengguna | Frontend | Backend | Keterangan |
|---|---|---|---|
| Pengunjung | / (HomePage) | GET /api/users/produk, artikel, info-toko | Tanpa login |
| Pembeli | /login, /akun | /me, /pembelian | JWT role pembeli |
| Admin | /login → /admin/* | /api/admin/... | JWT role admin |
/api/users/... — toko publik + akun pembeli + pesanan sendiri./api/admin/... — kelola semua data toko; wajib token admin.Admin memakai GET /api/admin/me, bukan GET /api/users/me.
toko_online.sql atau database/schema-latihan-toko.sql).seed-admin.sql atau data di dump).cd backend → npm run dev. Terminal 2: cd frontend → npm run dev./login dengan akun admin./api/admin/stats.GET /api/users/produk).pembeli.POST /api/users/pembelian (id_pembeli dari token).GET /api/users/pembelian.Detail lengkap: lihat Bagian 6.
Browser / React (fetch)
→ server.js (Express, CORS, JSON body, static uploads)
→ routes/admin.js (cocokkan URL + method)
→ middlewares/ (authenticate + requireRole("admin"))
→ controllers/ (validasi, aturan bisnis, status HTTP)
→ models/ (query SQL)
→ config/db.js (pool MySQL)
→ respons JSON balik ke React
Kenapa urutannya begitu? Route = peta URL, controller = logika, model = data. Ganti database cukup sentuh models/.
AdminProdukPage.jsx (atau halaman lain)
→ adminApi.getProduk() (adminApi.js)
→ http.js apiRequest() (tambah Bearer token, base URL)
→ fetch → backend
→ setState(rows) → render tabel
→ AdminRowActions → modal Detail / Ubah / Hapus
Konfigurasi: frontend/.env.development → VITE_API_URL=http://localhost:5000.
| Langkah | Lapisan | Apa yang terjadi |
|---|---|---|
| 1 | UI | onDelete(id) + window.confirm |
| 2 | adminApi.js | DELETE /api/admin/produk/5 + Bearer |
| 3 | routes/admin.js | → adminController.deleteProduk |
| 4 | Middleware | Cek JWT + role === admin |
| 5 | Controller | Validasi id, panggil model |
| 6 | Model | DELETE FROM produk WHERE id_produk = ? |
| 7 | UI | reload() — getProduk lagi |
backend/ ├── server.js ← ① PINTU MASUK ├── .env ← ② PORT, JWT_SECRET, DB_* ├── config/db.js ← ③ pool MySQL ├── routes/users.js, admin.js ← ④⑤ routing ├── middlewares/ ← ⑥⑦ auth, role, upload ├── controllers/ ← logika + JSON ├── models/ ← SQL per tabel ├── uploads/images/ ├── toko_online.sql └── database/
frontend/src/ ├── main.jsx, App.jsx ← ①② routing ├── context/AuthContext.jsx, AdminShopContext.jsx ├── api/http.js, adminApi.js ← ④⑤ panggil API ├── layouts/AdminLayout.jsx ├── pages/admin/ ← halaman panel ├── hooks/useAdminList.js, useAdminGuard.js └── components/admin/
| Urutan | Baca / kerjakan | Kenapa |
|---|---|---|
| 1 | Jalankan backend + frontend + login admin + menu /admin | Pahami hasil dulu |
| 2 | App.jsx + AdminProdukPage.jsx | URL browser ↔ API |
| 3 | adminApi.js + http.js | Cara React memanggil backend |
| 4 | routes/admin.js | Daftar endpoint admin |
| 5 | adminController.js | Logika setelah request masuk |
| 6 | produkModel.js (contoh) | SQL & tabel |
| 7 | server.js + authMiddleware.js | Server menyambungkan semuanya |
| 8 | Postman — uji tanpa React | Latihan API murni |
| Folder | Peran | Catatan |
|---|---|---|
routes/ | Routing | URL → middleware → controller |
controllers/ | Controller | Validasi + JSON |
models/ | Model | SQL dengan ? |
middlewares/ | Filter | Auth, role, upload |
config/ | Infrastruktur | Bukan bisnis toko |
View HTML tidak ada di API — tampilan admin ada di React, backend hanya JSON.
/api/adminSemua route di bawah router.use(authenticate, requireRole("admin")) di routes/admin.js.
| Method | Path | Fungsi |
|---|---|---|
| GET | /me | Profil admin login |
| PUT | /me | Ubah profil admin |
| GET | /stats | Angka dashboard |
| GET | /pembeli | Daftar pembeli (ringkas) |
| GET | /users | Daftar user (?role=pembeli) |
| POST | /users | Tambah akun pembeli |
| GET/PUT/DELETE | /users/:id | Detail / ubah / hapus pembeli |
| GET/POST | /produk | Daftar / tambah produk |
| GET/PUT/DELETE | /produk/:id_produk | Detail / ubah / hapus |
| GET | /pembelian | Semua pesanan |
| GET/PUT/DELETE | /pembelian/:id | Detail / ubah / hapus |
| GET/POST | /artikel | Daftar / tambah artikel |
| GET/PUT/DELETE | /artikel/:id | Detail / ubah / hapus |
| GET | /kontak | Daftar pesan kontak |
| GET/PUT/DELETE | /kontak/:id | Detail / ubah / hapus pesan |
| GET/PUT | /info-toko | Baca / ubah data toko |
| POST | /upload-gambar | Upload (field gambar) → data.path |
/api/users)Base URL: http://localhost:5000/api/users
| Langkah | Endpoint | Auth |
|---|---|---|
| Lihat katalog | GET /produk, GET /produk/:id_produk | Tidak |
| Info toko & artikel | GET /info-toko, GET /artikel | Tidak |
| Daftar / login | POST /register, POST /login | Tidak |
| Form kontak | POST /contact | Tidak |
| Profil | GET/PUT /me | Bearer pembeli |
| Upload gambar | POST /upload-gambar | Bearer pembeli |
| Buat pesanan | POST /pembelian | Bearer pembeli |
| Riwayat | GET /pembelian, GET /pembelian/:id | Bearer pembeli |
id_pembeli diambil dari req.user.id (JWT), bukan dari body.File terkait: routes/users.js → pembeliController.js → pembelianModel.js, dll.
| File | Fungsi |
|---|---|
toko_online.sql | Dump database acuan (phpMyAdmin) |
database/schema-latihan-toko.sql | Buat tabel dari nol |
seed-admin.sql | User admin jika belum ada |
seed-lengkapi-toko-online.sql | Contoh produk/artikel/info toko |
database/alter-database-yang-sudah-ada.sql | Selaraskan DB lama |
scripts/migrate-foto-bukti.js | Kolom pembelian.foto_bukti (npm run db:migrate-foto-bukti) |
| Topik | Nilai |
|---|---|
| Folder penyimpanan | backend/uploads/images/ |
| Akses file | http://localhost:5000/uploads/images/<namafile> |
| Admin upload | POST /api/admin/upload-gambar (Bearer admin, field gambar) |
| Pembeli upload | POST /api/users/upload-gambar (profil / bukti bayar) |
| Aturan | JPEG/PNG/GIF/WebP, maks 5 MB |
| Path di JSON | Bentuk /uploads/images/... |
Panel admin: React di :5173 menampilkan /admin/* dan memanggil JSON API di :5000/api/admin/* dengan token JWT admin.
Backend: setiap request mengalir server.js → routes → middlewares → controllers → models → MySQL, lalu balik sebagai JSON ke React.