318 lines
9.6 KiB
Markdown
318 lines
9.6 KiB
Markdown
|
|
# Quick Start Guide - Menu Module Access System
|
||
|
|
|
||
|
|
## 🚀 Langkah-langkah Setup
|
||
|
|
|
||
|
|
### 1. Jalankan Migration
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Connect ke PostgreSQL dan jalankan migration
|
||
|
|
psql -U your_username -d your_database -f docs/migrations/004_add_menu_module_access_system.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Setup Data Master
|
||
|
|
|
||
|
|
#### a. Buat Modules untuk Artikel
|
||
|
|
|
||
|
|
```sql
|
||
|
|
INSERT INTO master_modules (name, description, path_url, action_type, status_id, is_active) VALUES
|
||
|
|
('Lihat Artikel', 'Melihat daftar dan detail artikel', '/api/articles', 'view', 1, true),
|
||
|
|
('Buat Artikel', 'Membuat artikel baru', '/api/articles', 'create', 1, true),
|
||
|
|
('Edit Artikel', 'Mengedit artikel yang ada', '/api/articles/:id', 'edit', 1, true),
|
||
|
|
('Hapus Artikel', 'Menghapus artikel', '/api/articles/:id', 'delete', 1, true),
|
||
|
|
('Approve Artikel', 'Menyetujui artikel', '/api/articles/:id/approve', 'approve', 1, true);
|
||
|
|
-- Dapatkan ID modules yang baru dibuat untuk step selanjutnya
|
||
|
|
```
|
||
|
|
|
||
|
|
#### b. Buat Menu Artikel
|
||
|
|
|
||
|
|
```sql
|
||
|
|
INSERT INTO master_menus (name, description, module_id, icon, "group", position, status_id, is_active)
|
||
|
|
VALUES ('Artikel', 'Manajemen Artikel', 1, 'article-icon', 'Konten', 1, 1, true);
|
||
|
|
-- Dapatkan menu_id untuk step selanjutnya (misal: menu_id = 10)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### c. Hubungkan Menu dengan Modules
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Asumsikan menu_id = 10, dan module_ids = 1,2,3,4,5
|
||
|
|
INSERT INTO menu_modules (menu_id, module_id, position, is_active) VALUES
|
||
|
|
(10, 1, 1, true), -- Lihat
|
||
|
|
(10, 2, 2, true), -- Buat
|
||
|
|
(10, 3, 3, true), -- Edit
|
||
|
|
(10, 4, 4, true), -- Hapus
|
||
|
|
(10, 5, 5, true); -- Approve
|
||
|
|
```
|
||
|
|
|
||
|
|
#### d. Berikan Akses ke User Levels
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Admin Pusat (user_level_id = 1) - Full Access
|
||
|
|
INSERT INTO user_level_module_accesses (user_level_id, module_id, can_access, is_active) VALUES
|
||
|
|
(1, 1, true, true), -- Lihat
|
||
|
|
(1, 2, true, true), -- Buat
|
||
|
|
(1, 3, true, true), -- Edit
|
||
|
|
(1, 4, true, true), -- Hapus
|
||
|
|
(1, 5, true, true); -- Approve
|
||
|
|
|
||
|
|
-- Editor (user_level_id = 2) - Lihat, Buat, Edit saja
|
||
|
|
INSERT INTO user_level_module_accesses (user_level_id, module_id, can_access, is_active) VALUES
|
||
|
|
(2, 1, true, true), -- Lihat
|
||
|
|
(2, 2, true, true), -- Buat
|
||
|
|
(2, 3, true, true); -- Edit
|
||
|
|
|
||
|
|
-- Viewer (user_level_id = 3) - Lihat saja
|
||
|
|
INSERT INTO user_level_module_accesses (user_level_id, module_id, can_access, is_active) VALUES
|
||
|
|
(3, 1, true, true); -- Lihat
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Implementasi di Code
|
||
|
|
|
||
|
|
#### a. Tambahkan Routes dengan Middleware
|
||
|
|
|
||
|
|
Buat file baru atau update: `app/router/article.routes.go`
|
||
|
|
|
||
|
|
```go
|
||
|
|
package router
|
||
|
|
|
||
|
|
import (
|
||
|
|
"netidhub-saas-be/app/database"
|
||
|
|
"netidhub-saas-be/app/middleware"
|
||
|
|
"netidhub-saas-be/app/module/articles/controller"
|
||
|
|
|
||
|
|
"github.com/gofiber/fiber/v2"
|
||
|
|
)
|
||
|
|
|
||
|
|
func SetupArticleRoutes(app *fiber.App, db *database.Database, ctrl controller.ArticleController) {
|
||
|
|
// Initialize middlewares
|
||
|
|
authMw := middleware.NewUserMiddleware(db)
|
||
|
|
moduleAccessMw := middleware.NewModuleAccessMiddleware(db)
|
||
|
|
|
||
|
|
// Article routes group
|
||
|
|
articles := app.Group("/api/articles")
|
||
|
|
|
||
|
|
// GET /api/articles - View (module_id = 1)
|
||
|
|
articles.Get("/",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(1)),
|
||
|
|
ctrl.GetAll,
|
||
|
|
)
|
||
|
|
|
||
|
|
// GET /api/articles/:id - View detail (module_id = 1)
|
||
|
|
articles.Get("/:id",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(1)),
|
||
|
|
ctrl.GetOne,
|
||
|
|
)
|
||
|
|
|
||
|
|
// POST /api/articles - Create (module_id = 2)
|
||
|
|
articles.Post("/",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(2)),
|
||
|
|
ctrl.Create,
|
||
|
|
)
|
||
|
|
|
||
|
|
// PUT /api/articles/:id - Edit (module_id = 3)
|
||
|
|
articles.Put("/:id",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(3)),
|
||
|
|
ctrl.Update,
|
||
|
|
)
|
||
|
|
|
||
|
|
// DELETE /api/articles/:id - Delete (module_id = 4)
|
||
|
|
articles.Delete("/:id",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(4)),
|
||
|
|
ctrl.Delete,
|
||
|
|
)
|
||
|
|
|
||
|
|
// POST /api/articles/:id/approve - Approve (module_id = 5)
|
||
|
|
articles.Post("/:id/approve",
|
||
|
|
authMw.ValidateToken(),
|
||
|
|
moduleAccessMw.CheckModuleAccess(uint(5)),
|
||
|
|
ctrl.Approve,
|
||
|
|
)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### b. Register Routes di Main Router
|
||
|
|
|
||
|
|
Update `app/router/api.go`:
|
||
|
|
|
||
|
|
```go
|
||
|
|
// Import article routes
|
||
|
|
import (
|
||
|
|
articleController "netidhub-saas-be/app/module/articles/controller"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Di dalam fungsi RegisterRoutes
|
||
|
|
func RegisterRoutes(app *fiber.App, db *database.Database) {
|
||
|
|
// ... existing routes ...
|
||
|
|
|
||
|
|
// Article routes with module access control
|
||
|
|
articleCtrl := articleController.NewArticleController(articleService)
|
||
|
|
SetupArticleRoutes(app, db, articleCtrl)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Testing
|
||
|
|
|
||
|
|
#### Test 1: User dengan Full Access (Admin)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Login sebagai admin (user_level_id = 1)
|
||
|
|
curl -X POST http://localhost:3000/api/auth/login \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"username": "admin",
|
||
|
|
"password": "password"
|
||
|
|
}'
|
||
|
|
|
||
|
|
# Copy token dari response
|
||
|
|
TOKEN="your_admin_token_here"
|
||
|
|
|
||
|
|
# Test akses semua endpoint - Semua harus berhasil
|
||
|
|
curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles
|
||
|
|
curl -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles -d '{"title":"Test"}'
|
||
|
|
curl -X PUT -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1 -d '{"title":"Updated"}'
|
||
|
|
curl -X DELETE -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1
|
||
|
|
curl -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1/approve
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Test 2: User dengan Limited Access (Editor)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Login sebagai editor (user_level_id = 2)
|
||
|
|
curl -X POST http://localhost:3000/api/auth/login \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"username": "editor",
|
||
|
|
"password": "password"
|
||
|
|
}'
|
||
|
|
|
||
|
|
TOKEN="your_editor_token_here"
|
||
|
|
|
||
|
|
# Test akses - View, Create, Edit harus berhasil
|
||
|
|
curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles # ✓ Berhasil
|
||
|
|
curl -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles -d '{"title":"Test"}' # ✓ Berhasil
|
||
|
|
curl -X PUT -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1 -d '{"title":"Updated"}' # ✓ Berhasil
|
||
|
|
|
||
|
|
# Test akses - Delete dan Approve harus ditolak
|
||
|
|
curl -X DELETE -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1 # ✗ 403 Forbidden
|
||
|
|
curl -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/articles/1/approve # ✗ 403 Forbidden
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Test 3: Check Access via API
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check apakah user level 2 bisa akses module 4 (Delete)
|
||
|
|
curl -X POST http://localhost:3000/api/user-level-module-accesses/check-access \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"user_level_id": 2,
|
||
|
|
"module_id": 4
|
||
|
|
}'
|
||
|
|
|
||
|
|
# Expected response:
|
||
|
|
# {
|
||
|
|
# "success": true,
|
||
|
|
# "messages": ["Access check completed"],
|
||
|
|
# "data": {
|
||
|
|
# "has_access": false
|
||
|
|
# }
|
||
|
|
# }
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. Manage Access via API
|
||
|
|
|
||
|
|
#### Berikan Akses Baru
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Berikan akses Delete ke Editor (user_level_id = 2, module_id = 4)
|
||
|
|
curl -X POST http://localhost:3000/api/user-level-module-accesses \
|
||
|
|
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"user_level_id": 2,
|
||
|
|
"module_id": 4,
|
||
|
|
"can_access": true
|
||
|
|
}'
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Berikan Akses Multiple Modules Sekaligus
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Berikan akses ke banyak modul sekaligus (batch)
|
||
|
|
curl -X POST http://localhost:3000/api/user-level-module-accesses/batch \
|
||
|
|
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"user_level_id": 4,
|
||
|
|
"module_ids": [1, 2, 3],
|
||
|
|
"can_access": true
|
||
|
|
}'
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Lihat Akses User Level
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Lihat semua akses untuk user_level_id = 2
|
||
|
|
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
|
|
"http://localhost:3000/api/user-level-module-accesses/user-level/2"
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Cabut Akses
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update akses menjadi false (cabut akses)
|
||
|
|
curl -X PUT http://localhost:3000/api/user-level-module-accesses/123 \
|
||
|
|
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{
|
||
|
|
"can_access": false
|
||
|
|
}'
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📋 Checklist Implementation
|
||
|
|
|
||
|
|
- [ ] Migration script sudah dijalankan
|
||
|
|
- [ ] Tabel `menu_modules` dan `user_level_module_accesses` sudah ada
|
||
|
|
- [ ] Modules sudah dibuat di `master_modules`
|
||
|
|
- [ ] Menu sudah dibuat di `master_menus`
|
||
|
|
- [ ] Menu-Module sudah dihubungkan di `menu_modules`
|
||
|
|
- [ ] User Level Access sudah dikonfigurasi di `user_level_module_accesses`
|
||
|
|
- [ ] Middleware `ModuleAccessMiddleware` sudah diterapkan di routes
|
||
|
|
- [ ] Testing berhasil untuk berbagai user level
|
||
|
|
- [ ] Dokumentasi internal sudah diupdate
|
||
|
|
|
||
|
|
## 🎯 Tips & Best Practices
|
||
|
|
|
||
|
|
1. **Konsisten dengan Action Type**: Gunakan standar `view`, `create`, `edit`, `delete`, `approve`, `export`
|
||
|
|
2. **Batch Operations**: Gunakan endpoint batch untuk setup awal atau bulk changes
|
||
|
|
3. **Soft Delete**: Gunakan `is_active=false` daripada hard delete
|
||
|
|
4. **Audit Log**: Log setiap perubahan access control untuk audit trail
|
||
|
|
5. **Default Deny**: Jika tidak ada record = tidak ada akses (secure by default)
|
||
|
|
|
||
|
|
## ❓ Troubleshooting
|
||
|
|
|
||
|
|
### Error: "User tidak valid"
|
||
|
|
- Pastikan middleware auth (`ValidateToken()`) dipanggil sebelum `CheckModuleAccess()`
|
||
|
|
- Pastikan user sudah login dan token valid
|
||
|
|
|
||
|
|
### Error: "Module tidak ditemukan"
|
||
|
|
- Cek module_id yang digunakan di middleware
|
||
|
|
- Pastikan module exists dan `is_active = true`
|
||
|
|
|
||
|
|
### Error: "Anda tidak memiliki akses ke modul ini"
|
||
|
|
- Cek `user_level_module_accesses` untuk user level tersebut
|
||
|
|
- Pastikan `can_access = true` dan `is_active = true`
|
||
|
|
|
||
|
|
### User Level tidak sesuai
|
||
|
|
- Cek `user_roles.user_level_id` untuk user tersebut
|
||
|
|
- Pastikan relasi users -> user_roles -> user_levels sudah benar
|
||
|
|
|
||
|
|
## 📚 Selanjutnya
|
||
|
|
|
||
|
|
Baca dokumentasi lengkap di: [MENU_MODULE_ACCESS_SYSTEM.md](./MENU_MODULE_ACCESS_SYSTEM.md)
|
||
|
|
|