kontenhumas-be/docs/MODULE_UPDATE_CHECKLIST.md

10 KiB

📋 Module Update Checklist untuk Multi-Client Support

Status Saat Ini

Module BELUM disesuaikan dengan entity baru
Entity sudah diupdate (Clients, Users, UserClientAccess)
Middleware baru sudah dibuat (ClientMiddlewareV2)
Utilities sudah dibuat (client_hierarchy, client_utils_v2)


🎯 Module yang PERLU Diupdate

Priority 1: CRITICAL (Harus diupdate dulu)

1. Module: clients (PARTIALLY DONE)

Status: Request & Response V2 sudah dibuat
TODO:

  • Update clients.repository.go - Add hierarchy queries
  • Update clients.service.go - Add hierarchy logic
  • Update clients.controller.go - Add new endpoints
  • Update clients.mapper.go - Support new fields

Files Updated:

  • request/clients.request.v2.go - NEW
  • response/clients.response.v2.go - NEW

New Endpoints Needed:

GET    /api/v2/clients/:id/hierarchy          // Get client tree
GET    /api/v2/clients/:id/sub-clients        // Get direct children
POST   /api/v2/clients/:id/sub-clients        // Create sub-client
PUT    /api/v2/clients/:id/move               // Move to different parent
GET    /api/v2/clients/:id/stats              // Get client statistics
POST   /api/v2/clients/bulk-sub-clients       // Bulk create sub-clients

⚠️ 2. Module: users

Impact: HIGH - Users sekarang bisa multi-client access
TODO:

  • Add endpoint untuk get accessible clients
  • Add endpoint untuk switch current client
  • Update user creation untuk set is_super_admin
  • Update user list untuk show client access info

New Endpoints Needed:

GET    /api/v2/users/me/accessible-clients    // Get my accessible clients
POST   /api/v2/users/me/switch-client         // Switch active client
GET    /api/v2/users/:id/client-access        // Get user's client access
POST   /api/v2/users/:id/grant-client-access  // Grant multi-client access
DELETE /api/v2/users/:id/revoke-client-access // Revoke client access

⚠️ 3. Module: user_client_access (NEW MODULE)

Status: NEED TO CREATE
Purpose: Manage many-to-many User ↔ Client relationships

Structure:

app/module/user_client_access/
├── user_client_access.module.go
├── controller/
│   └── user_client_access.controller.go
├── service/
│   └── user_client_access.service.go
├── repository/
│   └── user_client_access.repository.go
├── request/
│   └── user_client_access.request.go
└── response/
    └── user_client_access.response.go

Endpoints:

GET    /api/v2/user-client-access              // List all access grants
POST   /api/v2/user-client-access              // Grant access
DELETE /api/v2/user-client-access/:id          // Revoke access
GET    /api/v2/user-client-access/user/:id     // Get by user
GET    /api/v2/user-client-access/client/:id   // Get by client

Priority 2: MEDIUM (Update untuk consistency)

🔸 4. Module: articles

Impact: MEDIUM - Perlu support multi-client filtering
TODO:

  • Update repository GetAll() - Use AddMultiClientFilter()
  • Update repository FindOne() - Validate client access
  • Update service untuk validate user has access to target client
  • Update controller untuk support ?client_id=xxx filter

Changes Needed:

// OLD
func (r *Repository) GetAll(clientId *uuid.UUID, req request.QueryRequest) {
    query := r.DB.Model(&entity.Articles{})
    if clientId != nil {
        query = query.Where("client_id = ?", clientId)
    }
}

// NEW
func (r *Repository) GetAll(c *fiber.Ctx, req request.QueryRequest) {
    query := r.DB.Model(&entity.Articles{})
    
    // Auto-filter by accessible clients
    query = middlewareUtils.AddMultiClientFilter(query, c)
    
    // Optional: specific client filter
    if req.ClientId != nil {
        // Validate access first
        query = query.Where("client_id = ?", req.ClientId)
    }
}

🔸 5. Module: user_roles

Impact: MEDIUM - Roles mungkin specific per client
TODO:

  • Update untuk support multi-client role access
  • Add logic untuk inherit roles dari parent client (optional)

🔸 6. Module: user_levels

Impact: MEDIUM - Levels mungkin berbeda per client
TODO:

  • Update untuk support multi-client level definitions
  • Add hierarchy logic untuk levels across clients

Priority 3: LOW (Optional updates)

Modules berikut juga punya ClientId field, tapi update bisa dilakukan bertahap:

  • schedules - Update filtering
  • feedbacks - Update filtering
  • subscriptions - Update filtering
  • magazines - Update filtering
  • advertisements - Update filtering
  • article_categories - Update filtering
  • bookmarks - Update filtering

Pattern sama untuk semua:

// Replace single-client filter
query = query.Where("client_id = ?", clientId)

// With multi-client filter
query = middlewareUtils.AddMultiClientFilter(query, c)

🚀 Quick Start Guide

Step 1: Update Module Clients (Paling Penting)

# 1. Buat file baru
touch app/module/clients/repository/clients.repository.v2.go
touch app/module/clients/service/clients.service.v2.go
touch app/module/clients/controller/clients.controller.v2.go

Step 2: Create UserClientAccess Module

# 2. Buat module baru
mkdir -p app/module/user_client_access/{controller,service,repository,request,response}

# Generate files (atau copy template)

Step 3: Update Existing Modules Bertahap

Update per module, testing setiap perubahan:

  1. Update articles (most used)
  2. Update users
  3. Update other modules one by one

📝 Template untuk Update Repository

package repository

import (
    "netidhub-saas-be/app/database/entity"
    middlewareUtils "netidhub-saas-be/utils/middleware"
    "github.com/gofiber/fiber/v2"
    "gorm.io/gorm"
)

type Repository struct {
    DB *gorm.DB
}

// OLD VERSION (single-client)
func (r *Repository) GetAllOld(clientId *uuid.UUID, req request.QueryRequest) ([]entity.Model, error) {
    query := r.DB.Model(&entity.Model{})
    
    if clientId != nil {
        query = query.Where("client_id = ?", clientId)
    }
    
    var results []entity.Model
    query.Find(&results)
    return results, nil
}

// NEW VERSION (multi-client)
func (r *Repository) GetAll(c *fiber.Ctx, req request.QueryRequest) ([]entity.Model, error) {
    query := r.DB.Model(&entity.Model{})
    
    // ✨ One line - auto multi-client filtering!
    query = middlewareUtils.AddMultiClientFilter(query, c)
    
    // Rest of your existing logic
    var results []entity.Model
    query.Find(&results)
    return results, nil
}

📝 Template untuk Update Service

package service

import (
    customMiddleware "netidhub-saas-be/app/middleware"
    clientUtils "netidhub-saas-be/utils/client"
    "github.com/gofiber/fiber/v2"
)

type Service struct {
    repo Repository
}

// Before creating/updating, validate client access
func (s *Service) Create(c *fiber.Ctx, req request.CreateRequest) error {
    userId := c.Locals(customMiddleware.UserIDContextKey).(uint)
    isSuperAdmin := customMiddleware.IsSuperAdmin(c)
    
    // If user specified a client, verify access
    if req.ClientId != nil {
        hasAccess, err := clientUtils.HasAccessToClient(
            s.repo.DB, 
            userId, 
            *req.ClientId, 
            isSuperAdmin,
        )
        
        if err != nil || !hasAccess {
            return fiber.NewError(403, "No access to this client")
        }
    }
    
    // Continue with creation
    return s.repo.Create(req)
}

📝 Template untuk Update Controller

package controller

import (
    customMiddleware "netidhub-saas-be/app/middleware"
    "github.com/gofiber/fiber/v2"
)

type Controller struct {
    service Service
}

// List with multi-client support
func (ctrl *Controller) GetAll(c *fiber.Ctx) error {
    var req request.QueryRequest
    c.QueryParser(&req)
    
    // Service/Repository will handle multi-client filtering
    results, err := ctrl.service.GetAll(c, req)
    
    if err != nil {
        return c.Status(500).JSON(fiber.Map{
            "success": false,
            "message": "Failed to retrieve data",
        })
    }
    
    // Show current context info (helpful for debugging)
    isSuperAdmin := customMiddleware.IsSuperAdmin(c)
    accessibleClients := customMiddleware.GetAccessibleClientIDs(c)
    
    return c.JSON(fiber.Map{
        "success": true,
        "data": results,
        "meta": fiber.Map{
            "is_super_admin": isSuperAdmin,
            "accessible_clients_count": len(accessibleClients),
        },
    })
}

Testing Checklist

Untuk setiap module yang diupdate:

  • Super Admin bisa lihat semua data (no client filter)
  • Multi-client user hanya lihat data dari accessible clients
  • Single-client user hanya lihat data dari 1 client (backward compat)
  • Create data dengan client_id validation
  • Update data dengan access check
  • Delete data dengan access check
  • Filter by client_id works correctly
  • Performance tidak menurun significant

📊 Progress Tracking

Module Priority Status Updated By Date
clients P1 🟡 In Progress - -
users P1 Not Started - -
user_client_access P1 Not Started - -
articles P2 Not Started - -
user_roles P2 Not Started - -
user_levels P2 Not Started - -
schedules P3 Not Started - -
feedbacks P3 Not Started - -
subscriptions P3 Not Started - -

Legend:

  • Not Started
  • 🟡 In Progress
  • 🟢 Completed
  • 🔴 Blocked

🆘 Need Help?

Jika stuck atau ada pertanyaan:

  1. Lihat docs/examples/articles_controller_example.go untuk contoh lengkap
  2. Lihat docs/MULTI_CLIENT_ACCESS_GUIDE.md untuk penjelasan konsep
  3. Check docs/IMPLEMENTATION_SUMMARY.md untuk overview

🎯 Estimated Timeline

  • Week 1: Update module clients + Create user_client_access module
  • Week 2: Update module users + articles
  • Week 3: Update remaining P2 modules
  • Week 4: Update P3 modules + Testing

Total: ~1 month untuk full implementation semua modules.

Bisa lebih cepat jika dikerjakan parallel atau prioritas hanya module penting saja.