Struktur Project — Portal Berita (Fullstack)

Dokumen ini memetakan folder dan file inti proyek, membedakan yang bawaan vs dibuat sendiri, serta alur komunikasi antar bagian. Selaras dengan kode aktual dan PERENCANAAN.md.

Cara menjalankan (2 terminal + DB):

TerminalFolderPerintahURL
database/Import schema.sql + seed.sql (PostgreSQL)
1backend/npm run devhttp://localhost:5000
2frontend/npm run devhttp://localhost:5173

Legenda

SimbolArti
[B]Bawaan — dari npm create vite, npm init, atau tool instalasi
[BUAT]Dibuat sendiri — untuk kebutuhan latihan Portal Berita
[EDIT]File bawaan yang perlu diedit agar project jalan
[OPS]Operasional — otomatis / hasil penggunaan (upload, lock, build)
[DOC]Dokumentasi / materi belajar

Tree folder & file (tanpa node_modules dan dist)

NEWS PKL/                                 ← folder project
│
├── backend/                              [BUAT] folder API (Express + PostgreSQL)
│   ├── server.js                         [BUAT]  pintu masuk — CORS, JSON, /uploads, mount routes
│   ├── package.json                      [B][EDIT]  dependensi: express, pg, cors, dotenv, jwt, bcrypt, multer
│   ├── package-lock.json                 [B][OPS]
│   ├── .env                              [BUAT][EDIT]  DB_*, PORT, JWT_SECRET, FRONTEND_URL (jangan di-commit)
│   ├── .env.example                      [BUAT][DOC]   contoh env tanpa rahasia
│   │
│   ├── config/
│   │   └── db.js                         [BUAT]  Pool koneksi pg
│   │
│   ├── routes/
│   │   ├── authRoutes.js                 [BUAT]  /api/auth — register, login, /me
│   │   ├── beritaRoutes.js               [BUAT]  /api/berita — publik + CRUD author
│   │   ├── adminRoutes.js                [BUAT]  /api/admin — users + moderasi berita
│   │   └── infoWebRoutes.js              [BUAT]  /api/info-web — GET publik, PUT admin
│   │
│   ├── controllers/
│   │   ├── authController.js             [BUAT]  register, login, getMe, updateMe
│   │   ├── beritaController.js           [BUAT]  list/detail publik + CRUD author
│   │   ├── adminBeritaController.js      [BUAT]  list/detail/hapus/headline (tanpa edit isi)
│   │   ├── adminUserController.js        [BUAT]  kelola author
│   │   └── infoWebController.js          [BUAT]  get + update info_web
│   │
│   ├── models/
│   │   ├── userModel.js                  [BUAT]  query tabel users
│   │   ├── beritaModel.js                [BUAT]  query tabel berita (+ headline transaksi)
│   │   └── infoWebModel.js               [BUAT]  query tabel info_web (1 baris)
│   │
│   ├── middlewares/
│   │   ├── authMiddleware.js             [BUAT]  verifikasi JWT + load user
│   │   ├── roleMiddleware.js             [BUAT]  requireRole("admin"|"author")
│   │   └── uploadMiddleware.js           [BUAT]  multer → uploads/berita|logo|sosmed
│   │
│   ├── utils/
│   │   ├── response.js                   [BUAT]  success() / fail()
│   │   └── fileHelper.js                 [BUAT]  hapus file gambar di disk
│   │
│   └── uploads/                          [BUAT][OPS]
│       ├── berita/                       [OPS]  gambar berita
│       ├── logo/                         [OPS]  logo_web
│       └── sosmed/                       [OPS]  logo_wa, logo_ig
│
└── frontend/                             [B] kerangka Vite + isi latihan
    ├── index.html                        [B][EDIT]  judul halaman
    ├── vite.config.js                    [B]        biasanya tidak perlu diubah
    ├── package.json                      [B][EDIT]  tambah bootstrap, react-router-dom
    ├── package-lock.json                 [B][OPS]
    ├── eslint.config.js                  [B]        linter (npm run lint)
    ├── .env / .env.example               [BUAT][EDIT]  VITE_API_URL=http://localhost:5000
    │
    ├── public/
    │   ├── placeholder-image.jpg         [BUAT]  fallback gambar
    │   ├── favicon.svg                   [B]
    │   └── icons.svg                     [B/OPS]
    │
    └── src/
        ├── main.jsx                      [B][EDIT]  Bootstrap + BrowserRouter + App
        ├── App.jsx                       [B][EDIT]  memanggil AppRoutes
        ├── routes/
        │   └── index.jsx                 [BUAT]  semua <Route> + ProtectedRoute
        │
        ├── services/                     [BUAT]  layer HTTP ke backend
        │   ├── api.js                    [BUAT]  apiFetch, token, imageUrl
        │   ├── authService.js            [BUAT]  /api/auth/*
        │   ├── beritaService.js          [BUAT]  /api/berita/*
        │   ├── adminService.js           [BUAT]  /api/admin/*
        │   └── infoWebService.js         [BUAT]  /api/info-web
        │
        ├── styles/
        │   └── custom.css                [BUAT]  gaya proyek
        │
        ├── components/
        │   ├── layout/
        │   │   ├── PublicLayout.jsx      [BUAT]  header + Outlet + footer
        │   │   ├── HeaderNavbar.jsx      [BUAT]  menu publik + logo dari info_web
        │   │   ├── FooterBar.jsx         [BUAT]  kontak dari info_web
        │   │   ├── AdminLayout.jsx       [BUAT]  panel admin
        │   │   ├── AuthorLayout.jsx      [BUAT]  panel author
        │   │   └── DashboardSidebar.jsx  [BUAT]  sidebar + topbar + logout
        │   ├── berita/
        │   │   └── BeritaCard.jsx        [BUAT]  kartu satu berita
        │   ├── home/
        │   │   ├── KategoriGrid.jsx      [BUAT]
        │   │   └── CtaBanner.jsx         [BUAT]
        │   ├── common/
        │   │   └── PageHeader.jsx        [BUAT]
        │   └── auth/
        │       └── ProtectedRoute.jsx    [BUAT]  cek login + role
        │
        └── pages/
            ├── public/
            │   ├── Home.jsx
            │   ├── ListBerita.jsx
            │   ├── DetailBerita.jsx
            │   ├── Kategori.jsx
            │   ├── Login.jsx
            │   └── Daftar.jsx
            └── dashboard/
                ├── author/
                │   ├── Dashboard.jsx
                │   ├── BeritaSaya.jsx
                │   ├── FormBerita.jsx      (tambah + edit)
                │   └── Profil.jsx
                └── admin/
                    ├── Dashboard.jsx
                    ├── ListUser.jsx
                    ├── DetailUser.jsx
                    ├── EditUser.jsx
                    ├── ListBerita.jsx
                    ├── DetailBerita.jsx
                    ├── InfoWeb.jsx
                    └── Profil.jsx          (re-export profil author)

Tidak ditulis di tree (bawaan npm / sisa Vite):

Ringkasan: bawaan vs buat sendiri

Folder level atas

FolderAsalKeterangan
backend/[BUAT]API dibuat manual (npm init + coding MVC)
frontend/[B] kerangka + [BUAT] isi src/Dari create vite; hampir semua di src/ buatan latihan

File bawaan frontend yang perlu diedit

FileYang biasanya diubah
index.htmlJudul tab browser
package.jsonTambah bootstrap, react-router-dom
.envVITE_API_URL=http://localhost:5000
src/main.jsxImport Bootstrap + custom.css + Router
src/App.jsxMemanggil AppRoutes

Backend

Tidak ada scaffold Express otomatis. package.json dari npm init lalu diisi dependencies. Semua file di config/, routes/, controllers/, models/, middlewares/, utils/ adalah [BUAT].

Alur komunikasi antar folder & file

1. Gambaran besar

Browser (:5173)                         Postman / browser API (:5000)
     │                                           │
     │  fetch JSON + JWT (opsional)                │
     └───────────────────────────────────────────►│  backend/server.js
                                                  │       │
                                                  │       ├─► routes/*.js
                                                  │       ├─► middlewares/
                                                  │       ├─► controllers/
                                                  │       ├─► models/
                                                  │       └─► config/db.js → PostgreSQL
                                                  │
     ◄───────────────────────────────────────────┘  JSON + file /uploads/...

Frontend tidak memanggil PostgreSQL langsung. Semua data lewat REST API.


2. Alur request backend

HTTP request
    → server.js
    → routes/auth|berita|admin|infoWeb.js
    → middlewares/ (JWT, role, multer)   ← jika route dilindungi / upload
    → controllers/
    → models/
    → config/db.js → PostgreSQL
    ← JSON { success, message, data? }

Contoh: Author update berita → FormBeritaupdateBerita(id, formData)PUT /api/berita/:idberitaRoutes → auth+author → beritaController.updateberitaModel.update.


3. Alur frontend

index.html
    → main.jsx
    → App.jsx
    → routes/index.jsx          (+ ProtectedRoute untuk dashboard)
    → pages/...                 (Home, Login, BeritaSaya, ...)
    → components/...
    → services/*Service.js
    → services/api.js           (apiFetch + Bearer)
    → backend /api/...

Contoh: Home menampilkan headline → Home.jsxgetHeadline() + getBerita() + getInfoWeb() → setState → hero + BeritaCard + CtaBanner.


4. Autentikasi

Login.jsx
    → authService.login()  →  POST /api/auth/login
    → authController.login →  bcrypt + jwt.sign
    → setAuth(token, user) →  localStorage

Request berikutnya:
    → apiFetch()  →  Authorization: Bearer <token>
    → authMiddleware + loadUserMiddleware
    → roleMiddleware("admin"|"author")  (jika diperlukan)
    → controller

Frontend guard:
    → ProtectedRoute  →  getUser() dari localStorage
    → salah role → redirect dashboard yang sesuai
RolePrefix API utamaHalaman frontend
PublikGET /api/berita, /info-web/, /berita, /kategori/:slug
Author/api/berita/mine, CRUD /api/berita, /auth/me/dashboard/author/*
Admin/api/admin/*, PUT /api/info-web/dashboard/admin/*

5. Upload gambar

FormBerita / InfoWeb (FormData)
    → createBerita / updateBerita / updateInfoWeb
    → multer di uploadMiddleware.js
    → uploads/berita|logo|sosmed/<file>
    → path disimpan di DB (/uploads/...)

Tampil:
    → imageUrl(path)  →  http://localhost:5000/uploads/...
    → gagal load → PLACEHOLDER_IMAGE

6. Peta halaman → file utama

URL browserFile halamanAPI utama
/Home.jsxheadline, berita, info-web
/beritaListBerita.jsxGET /api/berita
/berita/:idDetailBerita.jsxGET /api/berita/:id
/kategori/:slugKategori.jsxGET /api/berita?kategori=...
/login, /daftarLogin, DaftarPOST /auth/login|register
/dashboard/author/*pages/dashboard/author/*berita milik sendiri + profil
/dashboard/admin/*pages/dashboard/admin/*adminService + info-web

7. Database ↔ kode

TabelModelDipakai untuk
usersuserModel.jsAuth, profil, kelola author
beritaberitaModel.jsPortal + CRUD author + headline admin
info_webinfoWebModel.jsNavbar, footer, form Info Web

Urutan belajar file

  1. backend/server.jsroutes/beritaRoutes.jsberitaController.jsberitaModel.js
  2. frontend/src/main.jsxApp.jsxroutes/index.jsxpages/public/Home.jsx
  3. services/api.jsberitaService.jsBeritaCard.jsx
  4. Login: Login.jsx + authService.js + authMiddleware.js + ProtectedRoute.jsx
  5. Author: AuthorLayoutBeritaSaya / FormBerita
  6. Admin: AdminLayoutListBerita / ListUser / InfoWeb

Catatan project

Fokus tree ini: folder backend/ dan frontend/ yang dijalankan sistem.