# 📋 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:** ```go 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:** ```go 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:** ```go 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:** ```go // 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:** ```go // 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) ```bash # 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 ```bash # 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 ```go 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 ```go 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 ```go 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.