tutorial

91 Studi Kasus: Sistem Manajemen Artikel (CMS)

91 Studi Kasus: Sistem Manajemen Artikel (CMS)

CMS (Content Management System) adalah salah satu sistem paling fundamental dalam ekosistem software modern. Di era serba digital, kebutuhan untuk mengelola konten secara terstruktur, skalabel, dan aman sangat vital—baik untuk blog personal, portal berita, hingga knowledge base enterprise.

Artikel ini adalah bagian dari seri 91 Studi Kasus di mana kita akan mendisect arsitektur, implementasi, dan best practices membangun CMS dengan pendekatan engineering-first, sekaligus menghadirkan studi kasus dan contoh kode implementasi pragmatis.


1. Masalah & Kebutuhan

Studi Kasus: Portal Berita “MediaKita”

Skenario:
MediaKita adalah portal berita yang sedang berkembang. Awalnya, artikel diunggah manual oleh tim via Google Docs, kemudian di-copy paste ke website oleh developer. Proses yang tidak scalable dan sering mengundang masalah, seperti:

  • Kesalahan format dan metadata.
  • Artikel duplikat.
  • Deadline sering terlewati.
  • Tidak ada sistem approval/editorial workflow.

Key Requirements dari Stakeholder:

  • Setiap pengguna (author) bisa menulis, menyimpan, dan mempublikasikan artikel.
  • Artikel harus bisa dikategorikan, diberi tag, serta memiliki status (draft, review, published).
  • Editor bisa mereview dan meng-approve artikel sebelum terpublish.
  • Sistem harus trackable (audit trail).
  • REST API untuk integrasi frontend & mobile app.

2. High Level Design

Mari kita breakdown menjadi beberapa komponen:

flowchart TD
    subgraph Frontend
        FE[React/Vue SPA]
    end
    subgraph Backend
        BE[REST API (Express/NestJS)]
    end
    subgraph Database
        DB[(PostgreSQL/MongoDB)]
    end
    FE -- HTTP/JSON --> BE
    BE -- ORM/ODM --> DB

Entity Model

Tabel berikut mengilustrasikan 3 entitas inti dalam sistem CMS sederhana.

EntityFieldsRelasi
Userid, name, email, role (author/editor/admin), password_hash1 User : n Article
Articleid, title, slug, content, category_id, status, created_at, updated_at, author_id, editor_id, audit_logn Article : 1 Category
Categoryid, name, slug, parent_idn Category : n Article

User Stories

1. Penulis Menulis Artikel

  • User buka halaman form, mengisi title, content, memilih kategori.
  • Menyimpan sebagai draft.

2. Editorial Workflow

  • Draft masuk ke review queue.
  • Editor memberikan feedback atau approve.
  • Setelah approved, status artikel berubah menjadi published.

3. Audit Trail

  • Setiap perubahan status atau content dicatat dalam audit log.

3. Contoh Kode: Backend API (Node.js + Express + Sequelize)

Mari lihat bagaimana konteks di atas diterjemahkan menjadi endpoint RESTful:

// src/routes/articles.js
const express = require('express');
const router = express.Router();
const { Article, Category, User } = require('../models');
const auth = require('../middleware/auth');

// Endpoint: Buat artikel (Draft)
router.post('/', auth, async (req, res) => {
  try {
    const { title, content, category_id } = req.body;
    const article = await Article.create({
      title, content, category_id,
      author_id: req.user.id,
      status: 'draft'
    });
    res.status(201).json(article);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Endpoint: Update status artikel ke 'review'
router.post('/:id/submit', auth, async (req, res) => {
  try {
    const article = await Article.findByPk(req.params.id);
    if (article.author_id !== req.user.id) return res.status(403).json({ error: "Unauthorized" });
    article.status = 'review';
    await article.save();
    res.json(article);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Endpoint: Approve artikel (Editor)
router.post('/:id/approve', auth, async (req, res) => {
  try {
    if (req.user.role !== 'editor') return res.status(403).json({ error: "Editor only" });
    const article = await Article.findByPk(req.params.id);
    article.status = 'published';
    article.editor_id = req.user.id;
    await article.save();
    res.json(article);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

4. Editorial Workflow: State Machine

Untuk menjaga proses editorial tetap robust, workflow status biasanya diatur via state machine.

stateDiagram-v2
    [*] --> Draft
    Draft --> Review: Submit for Review
    Review --> Draft: Request Change
    Review --> Published: Approve
    Published --> Archived: Archive
    Draft --> Deleted: Delete
    Review --> Deleted: Delete

5. Audit Trail: Simulasi & Implementasi

Audit trail penting untuk governance dan debugging. Simulasi sederhana dengan hook pada model ORM:

// src/models/Article.js (Sequelize Model)
Article.afterUpdate(async (article, options) => {
  await AuditLog.create({
    article_id: article.id,
    changed_by: options.user.id,
    status: article.status,
    timestamp: new Date()
  });
});

Setiap kali status artikel berubah, record dimasukkan ke tabel audit_logs.

Contoh Query Audit Log

SELECT * FROM audit_logs WHERE article_id = 123 ORDER BY timestamp DESC;

6. Kategori dan Tagging

Pengelompokan konten sangat penting untuk navigasi dan discoverability. Misal, satu artikel bisa punya banyak tag.

Tabel Relationship Many-to-Many:

article_idtag_id
103
108
123

7. Integrasi Frontend

Dengan memiliki REST API, frontend bisa dibuat dengan framework modern seperti React.

Contoh Simulasi Fetch Artikel:

useEffect(() => {
  fetch("/api/articles?status=published")
    .then(res => res.json())
    .then(data => setArticles(data));
}, []);

8. Deployment & Scalability

  • Database: PostgreSQL, opsi full-text search untuk pencarian artikel.
  • Backend: Node.js/NestJS/Go, disarankan stateless service untuk kemudahan scaling.
  • Frontend: SPA, cache data penting di CDN jika traffic tinggi.
  • Integrasi OAuth: Untuk login aman.

9. Studi Kasus Live: Simulasi Workflow

Alur Editorial:

  1. Author buat artikel draft.
  2. Submit for review.
  3. Editor memberikan feedback (request change) atau approve.
  4. Jika approved, artikel terpublish otomatis.

Simulasi Request API:

# 1. Author create
curl -X POST /api/articles -d '{ "title": "CMS Rules", "content": "...", ... }'

# 2. Author submit
curl -X POST /api/articles/5/submit

# 3. Editor approve
curl -X POST /api/articles/5/approve

Tabel Sample Audit Trail:

IDArticle IDChanged ByStatusWaktu
1512draft2024-06-01 09:01:01
2512review2024-06-01 09:02:00
3513published2024-06-01 11:10:00

10. Lessons Learnt & Best Practices

  • Separation of Concerns: Pisahkan strictly antara model, controller, dan layer service.
  • Access Control: Implementasi RBAC (Role-Based Access Control) pada endpoint dan UI.
  • State Machine: Jangan hardcode status sebagai string magic, gunakan state machine pattern.
  • Audit Trail: Dengan log perubahan, kita bisa dengan mudah menelusuri siapa mengubah apa.
  • API-First: Desain backend supaya bisa diintegrasikan ke frontend/web/mobile dengan mudah.
  • Validasi & Error Handling: Jangan lupakan validation layer baik di backend maupun frontend.

11. Kesimpulan

Membangun CMS bukan hanya soal CRUD artikel, tapi mendesain sistem workflow, integritas data, dan kemudahan scaling yang enterprise-ready. Dari studi kasus MediaKita, kebutuhan editorial yang dulu mengandalkan proses manual, kini bisa di-automasi serta dipantau dengan baik. Value utamanya terletak pada flexibility, governance, dan extensibility.

Semoga breakdown kasus ini membantu Anda yang sedang merancang atau refactor sistem CMS untuk scale-up ke level berikutnya. Jangan ragu bereksperimen, iterasi, dan selalu lakukan audit atas tiap flow penting dalam sistem!

Bagaimana pengalaman Anda membangun CMS? Sampaikan di komentar!

comments powered by Disqus