Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
01 Oct 2026 · 20 mnt baca ·Artikel 57 / 208
Go

Context Management AI untuk Go Monorepo: CLAUDE.md Hierarki, go.work

Cara mengelola context AI tools secara efektif di Go monorepo. Hierarki CLAUDE.md root dan per-service, shared domain packages, cross-service boundaries.

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Context Management untuk Go Monorepo

Mengelola context AI tools di Go monorepo adalah tantangan nyata saat tim berkembang. Service bertambah, codebase makin besar, dan satu CLAUDE.md untuk semua tidak lagi cukup. Artikel ini adalah panduan untuk setup hierarki context yang scalable, mulai dari root universal hingga override per-service.


17.1 Tantangan Context di Monorepo

Sebelum membahas solusi, mari lihat dulu bentuk masalahnya. Struktur monorepo berikut menggambarkan kondisi nyata di Santekno Corp beserta tantangan context yang muncul di dalamnya.

text
 1Monorepo Santekno Corp (contoh nyata):
 2
 3santekno-shop/
 4├── services/
 5│   ├── order-service/        (~100K lines)
 6│   ├── payment-service/      (~80K lines)
 7│   ├── notification-service/ (~40K lines)
 8│   └── catalog-service/      (~60K lines)
 9├── shared/
10│   └── domain/               (shared domain types)
11├── CLAUDE.md                 (root: universal rules)
12└── go.work                   (Go workspace file)
13
14Challenge:
151. Universal CLAUDE.md terlalu generic untuk service-specific patterns
162. AI perlu tahu: "Sedang kerja di service mana?"
173. Cross-service dependency TIDAK boleh jadi direct import
184. Shared types harus konsisten antar services

Empat tantangan ini bermuara pada satu kebutuhan: AI harus tahu di service mana ia bekerja dan aturan apa yang berlaku di sana — sesuatu yang tidak bisa dijawab satu file context tunggal.


17.2 Solusi: Hierarki Context File

Jawaban atas tantangan tadi adalah hierarki context yang di-load dari direktori terdalam ke atas. Diagram berikut menunjukkan bagaimana Claude Code menggabungkan CLAUDE.md service dengan CLAUDE.md root.

text
 1Context loading ketika claude run dari services/order-service/:
 2
 3services/order-service/CLAUDE.md   (service-specific)
 4    ↕ "EXTENDS root"
 5CLAUDE.md                           (root universal)
 6
 7= Combined context untuk order-service session
 8
 9Cara kerja Claude Code hierarki:
101. Read CLAUDE.md dari current directory
112. Walk up ke parent directories
123. Read semua CLAUDE.md yang ditemukan
134. Combine dengan current dir taking priority

Mekanisme “walk up” inilah kuncinya: aturan universal ditulis sekali di root, aturan spesifik ditambahkan di service, dan keduanya otomatis tergabung tanpa duplikasi.


17.3 Root CLAUDE.md: Universal Rules

Lapisan pertama hierarki adalah root CLAUDE.md yang memuat aturan berlaku untuk semua service. Contoh berikut menunjukkan isi minimal yang wajib ada di level root.

markdown
 1# santekno-shop/CLAUDE.md
 2# Universal rules untuk SEMUA services
 3
 4## Go Version
 5Go 1.22 across all services. No 1.23+ features.
 6
 7## Architecture (All Services)
 8Clean Architecture: handler → usecase → repository → domain
 9Same layer rules apply everywhere.
10
11## Error Handling (Universal)
12Repository not-found: return nil, nil (NEVER error)
13Error wrap: fmt.Errorf("pkg.Method: %w", err)
14HTTP error format: {"error": "UPPERCASE_CODE"}
15
16## Monetary Values (Critical)
17ALWAYS int64 cents via shared/domain/money.IDR
18NEVER float64, float32 for money
19
20## Shared Domain Types (MUST USE)
21money.IDR   — monetary values
22event.BaseEvent — embedded in all Kafka events
23id.OrderID, id.UserID, id.ProductID — cross-service IDs
24
25## Cross-Service Rules (STRICT)
26NEVER import another service's internal packages
27Cross-service communication: Kafka events ONLY
28Shared types: shared/domain ONLY, no duplication
29
30## Testing
31testify/suite + gomock pattern. Universal.
32
33## Packages
34pgx/v5, go-redis/v9, echo/v4, confluent-kafka-go/v2
35go.uber.org/mock/gomock (NOT github.com/golang/mock)

Root ini sengaja dijaga generik: hanya aturan yang benar-benar berlaku di setiap service — arsitektur, error handling, tipe uang, dan batas cross-service.


17.4 Service-Specific CLAUDE.md Template

Lapisan kedua adalah CLAUDE.md per-service yang menambahkan detail spesifik tanpa mengulang aturan universal. Template berikut menunjukkan pola untuk order-service.

markdown
 1# services/order-service/CLAUDE.md
 2# EXTENDS: ../../CLAUDE.md (ALL universal rules apply here)
 3
 4## Service Identity
 5Name: order-service
 6Port: 8081
 7Purpose: Order lifecycle — creation to delivery
 8
 9## Kafka Topics (This Service)
10Produces:
11  - order.created      (after successful order creation)
12  - order.confirmed    (after payment.completed consumed)
13  - order.cancelled    (after cancel with stock restore)
14
15Consumes:
16  - payment.completed  → trigger order confirmation
17  - inventory.reserved → proceed with order processing
18
19## Redis Keys Pattern
20  order:{order_id}:lock  — distributed lock (TTL: 30s)
21  order:{user_id}:recent — recent orders cache (TTL: 5min)
22
23## Service-Specific Error Codes
24Beyond universal codes, this service uses:
25  ORDER_NOT_FOUND, ORDER_NOT_CANCELLABLE
26  CANCEL_WINDOW_EXPIRED, ORDER_ALREADY_CONFIRMED
27  SHIPPING_ADDRESS_REQUIRED
28
29## Performance SLOs
30  GET /orders/:id  — P99 < 50ms
31  POST /orders     — P99 < 200ms
32  Batch ops        — max 1000 items/batch
33
34## Domain Boundaries (STRICT)
35OWNS: Order, OrderItem, OrderStatus
36REFERENCES ONLY (by ID): User, Product, Payment, Inventory
37NEVER: import domain types from other services

Baris pertama # EXTENDS: ../../CLAUDE.md adalah konvensi penting: ia mengingatkan AI (dan developer) bahwa semua aturan root tetap berlaku, dan file ini hanya menambah — bukan menggantikan.


17.5 Shared Domain Package

Konsistensi antar-service dijamin oleh shared domain package yang menyediakan tipe bersama. Kode Go berikut mendefinisikan tipe uang, ID lintas-service, dan envelope event yang wajib dipakai semua service.

go
 1// shared/domain/money/money.go
 2package money
 3
 4// IDR represents Indonesian Rupiah in cents.
 5// ALWAYS use this for monetary values across all services.
 6// Example: Rp 50,000 = IDR(5_000_000)
 7type IDR int64
 8
 9func (m IDR) ToRupiah() float64 { return float64(m) / 100 }
10func FromRupiah(r float64) IDR  { return IDR(r * 100) }
11
12// shared/domain/id/id.go
13package id
14
15import "github.com/google/uuid"
16
17// Cross-service ID type aliases.
18// Services MUST use these for cross-service references.
19// NEVER create custom UUID aliases in individual services.
20type (
21    OrderID   = uuid.UUID
22    UserID    = uuid.UUID
23    ProductID = uuid.UUID
24    PaymentID = uuid.UUID
25)
26
27// shared/domain/event/event.go
28package event
29
30import "time"
31
32// BaseEvent MUST be embedded in ALL Kafka event structs
33// across all services. Ensures consistent event envelope.
34type BaseEvent struct {
35    EventID    string    `json:"event_id"`
36    EventType  string    `json:"event_type"`
37    OccurredAt time.Time `json:"occurred_at"`
38    Version    int       `json:"version"`
39}

Dengan memusatkan money.IDR, alias ID, dan event.BaseEvent di satu tempat, tidak ada lagi risiko dua service mendefinisikan tipe Amount yang berbeda — sumber drift paling umum di monorepo tereliminasi.


17.6 go.work Setup

Agar AI dan developer bisa me-resolve import lintas-module tanpa published module, monorepo memakai Go workspace. Perintah dan konfigurasi berikut menunjukkan isi go.work dan import yang menjadi valid karenanya.

bash
 1# go.work file untuk development workspace
 2cat go.work
 3
 4# go 1.22
 5#
 6# use ./shared/domain
 7# use ./services/order-service
 8# use ./services/payment-service
 9# use ./services/notification-service
10# use ./services/catalog-service
11
12# Benefit: AI dapat resolve cross-service imports
13# tanpa perlu published module.
14# Developer bisa import shared/domain dari semua services.
15
16# Contoh import yang valid berkat go.work:
17# services/order-service/internal/usecase/cancel_order.go
18
19import (
20    "github.com/santekno/santekno-shop/shared/domain/money"
21    "github.com/santekno/santekno-shop/shared/domain/event"
22    "github.com/santekno/santekno-shop/shared/domain/id"
23)

Tanpa go.work, AI akan bingung me-resolve import shared/domain; dengan file ini, seluruh workspace jadi satu kesatuan yang bisa dipahami baik oleh compiler maupun tool AI.


17.7 Cross-Service Feature dengan AI

Fitur yang melintasi dua service adalah ujian nyata untuk boundary. Contoh berikut memisahkan pekerjaan cancel-order menjadi dua sesi Claude Code yang masing-masing hanya menyentuh satu service.

bash
 1# Feature: order cancel → trigger payment refund
 2# Span 2 services, cross-service communication via Kafka
 3
 4# Session 1: order-service side
 5cd services/order-service
 6claude
 7> CLAUDE.md sudah di-load (universal + order-specific).
 8> Implement CancelOrder yang publish ORDER_CANCELLED event.
 9>
10> Event payload yang harus di-publish:
11>   OrderID   id.OrderID
12>   UserID    id.UserID
13>   Amount    money.IDR
14>   OccurredAt time.Time (embed event.BaseEvent)
15>
16> SCOPE: hanya order-service.
17> payment-service akan consume event ini untuk refund.
18> Tidak ada direct call ke payment-service.
19
20# Session 2: payment-service side
21cd services/payment-service
22claude
23> CLAUDE.md sudah di-load (universal + payment-specific).
24> Implement Kafka consumer untuk ORDER_CANCELLED event.
25>
26> Event schema (dari order-service):
27> @internal/domain/order/events.go
28>
29> Ketika consume:
30> 1. Create refund record di DB
31> 2. Call Midtrans API untuk initiate refund
32> 3. Publish REFUND_INITIATED event
33>
34> BOUNDARY: payment-service hanya react ke event.
35> Tidak call order-service API secara langsung.

Pola dua sesi ini menegakkan boundary secara alami: karena setiap sesi hanya cd ke satu service, AI tidak pernah tergoda membuat direct import lintas-service — komunikasi tetap lewat Kafka event.


17.8 Monorepo Developer Workflow

Aturan paling fundamental di monorepo adalah selalu cd ke service yang dikerjakan sebelum memulai sesi AI. Perintah berikut menunjukkan kebiasaan yang benar dan yang harus dihindari.

bash
 1# Workflow sehari-hari developer di monorepo:
 2
 3# ATURAN UTAMA: SELALU cd ke service yang sedang dikerjakan
 4cd services/order-service
 5claude
 6# Claude load: services/order-service/CLAUDE.md + root CLAUDE.md
 7# Context: order-service specific + universal
 8
 9# JANGAN: run claude dari root monorepo untuk coding di specific service
10# cd santekno-shop && claude   <- ini akan load hanya root CLAUDE.md
11# AI tidak tahu service-specific patterns
12
13# Untuk cross-service impact analysis:
14# Ini adalah use case dimana Gemini (1M context) unggul
15# Atau gunakan Claude Code dari root dengan explicit context:
16cd santekno-shop
17claude
18> Analyze impact dari perubahan OrderCancelledEvent payload.
19> Services yang perlu di-update:
20> - services/payment-service (consumer)
21> - services/notification-service (consumer)
22>
23> Cek kompatibilitas antara publisher dan semua consumers.

Perhatikan pembedaannya: untuk coding di satu service, cd ke service itu; untuk analisis dampak lintas-service, baru jalankan dari root dengan context eksplisit — dua konteks yang berbeda butuh titik mulai yang berbeda.


17.9 Kurasi Context untuk Monorepo

Tidak semua file layak masuk context AI. Konfigurasi berikut memisahkan file yang perlu di-include dari file generated yang sebaiknya di-exclude lewat .claudeignore.

bash
 1# File yang PERLU ada di context AI (include):
 2# - Service CLAUDE.md dan root CLAUDE.md
 3# - Current service's domain entities
 4# - Current service's interfaces (not implementations)
 5# - Shared domain types yang digunakan
 6
 7# File yang sebaiknya EXCLUDE dari context:
 8# .cursorignore (untuk Cursor)
 9# .claudeignore (untuk Claude Code)
10
11cat > santekno-shop/.claudeignore << 'IGNORE'
12# Generated files — tidak perlu AI baca ini
13**/mock_*.go
14**/*.pb.go
15**/*.pb.gw.go
16
17# Vendor dependencies
18**/vendor/
19
20# Test fixtures yang besar
21**/testdata/*.json
22**/testdata/*.sql
23
24# Build outputs
25**/bin/
26**/*.out
27IGNORE

Mengecualikan file generated dan vendor bukan sekadar soal kebersihan: setiap token context yang tidak relevan mengurangi ruang untuk kode yang benar-benar penting dan menaikkan biaya.


17.10 Architecture Check untuk Monorepo

Boundary lintas-service harus ditegakkan otomatis, bukan mengandalkan disiplin manual. Skrip Go berikut mem-parse import di setiap service dan menggagalkan build jika ada yang mengimpor internal package service lain.

go
 1// scripts/check-monorepo-boundaries.go
 2// Validate cross-service import boundaries
 3
 4package main
 5
 6import (
 7    "fmt"
 8    "go/parser"
 9    "go/token"
10    "os"
11    "path/filepath"
12    "strings"
13)
14
15// Map: service path prefix → allowed imports only
16var serviceAllowedExternals = map[string][]string{
17    "services/order-service": {
18        "shared/domain",      // allowed: shared domain
19        "github.com/",        // allowed: external packages
20        "golang.org/",        // allowed: golang stdlib extras
21    },
22    // payment-service CANNOT import order-service internal
23    "services/payment-service": {
24        "shared/domain",
25        "github.com/",
26        "golang.org/",
27    },
28}
29
30func main() {
31    violations := 0
32
33    for service, allowed := range serviceAllowedExternals {
34        _ = allowed
35        filepath.Walk(service+"/internal", func(path string, info os.FileInfo, err error) error {
36            if err != nil || !strings.HasSuffix(path, ".go") {
37                return nil
38            }
39
40            fset := token.NewFileSet()
41            f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
42            if err != nil {
43                return nil
44            }
45
46            for _, imp := range f.Imports {
47                importPath := strings.Trim(imp.Path.Value, `"`)
48
49                // Check if import is from another service's internal
50                for otherService := range serviceAllowedExternals {
51                    if otherService != service &&
52                        strings.Contains(importPath, otherService+"/internal") {
53                        fmt.Printf("VIOLATION: %s imports %s (cross-service internal)\n",
54                            path, importPath)
55                        violations++
56                    }
57                }
58            }
59            return nil
60        })
61    }
62
63    if violations > 0 {
64        fmt.Printf("\n%d boundary violations found\n", violations)
65        os.Exit(1)
66    }
67    fmt.Println("OK: All service boundaries respected")
68}

Dengan skrip ini di pipeline, aturan “never import another service’s internal” berhenti jadi imbauan di CLAUDE.md dan menjadi gate yang benar-benar memblokir merge — enforcement yang tidak bergantung pada ingatan reviewer.


17.11 Monorepo Context Governance

Context file adalah aset bersama, jadi kepemilikan dan proses perubahannya harus jelas. Pembagian tanggung jawab berikut memisahkan ownership root, service, dan shared domain.

text
 1Ownership per layer:
 2
 3Root CLAUDE.md (universal rules):
 4  Owner: Architecture Team / Tech Lead
 5  Change process: PR dengan approval dari architecture team
 6  Review cadence: Monthly check untuk consistency
 7
 8Service CLAUDE.md (service-specific):
 9  Owner: Service Team
10  Change process: PR dengan approval dari service tech lead
11  Review cadence: Sprint end review
12
13Shared domain (shared/domain/):
14  Owner: Architecture Team
15  Change process: RFC + PR (breaking changes need migration plan)
16  Review cadence: Quarterly evolution review
17
18Process untuk add new pattern ke CLAUDE.md:
191. Developer identify pattern yang sering salah di AI output
202. Propose addition ke service CLAUDE.md
213. Jika pattern universal: promote ke root CLAUDE.md
224. Update .cursorrules dan copilot-instructions jika perlu

Governance berlapis ini menjaga keseimbangan: perubahan universal butuh approval ketat dari architecture team, sementara aturan service tetap agile di tangan tim yang paling paham konteksnya.


17.12 Skenario: Onboarding Developer Baru di Monorepo

Salah satu manfaat context hierarchy yang paling terasa adalah onboarding. Sesi berikut menunjukkan bagaimana developer baru bisa memahami monorepo lewat AI yang membaca CLAUDE.md.

bash
 1# Developer baru join, perlu understand monorepo:
 2
 3claude
 4> Saya baru join tim Santekno. Tolong bantu saya understand:
 5>
 6> 1. Bagaimana monorepo ini di-structure?
 7> 2. Apa cross-service communication mechanism yang digunakan?
 8> 3. Apa shared types yang HARUS digunakan?
 9> 4. Bagaimana error handling universal yang berlaku di semua service?
10> 5. Apa boundaries yang TIDAK boleh dilanggar?
11>
12> Baca CLAUDE.md yang tersedia untuk answer ini.
13
14# Claude akan:
15# - Baca root CLAUDE.md
16# - Explain hierarki yang jelas
17# - Highlight critical rules (cross-service, money types, etc.)
18# - Generate summary yang berguna
19
20# Ini lebih efektif dari "baca semua dokumentasi dulu"
21# Claude sebagai guided tour untuk onboarding

Pendekatan ini mengubah onboarding dari “baca semua dokumen” menjadi tur berpemandu: developer baru bertanya langsung dan AI menjawab dari sumber kebenaran yang sama dengan yang memandu code generation.


17.13 Tips & Gotchas Monorepo Context

Beberapa pelajaran praktis berikut adalah yang paling menentukan keberhasilan context management di monorepo, dirangkum sebagai tips dan gotcha.

💡 Tip 1: SELALU cd ke service directory sebelum Claude Code session. Ini adalah aturan paling penting.

💡 Tip 2: Service CLAUDE.md harus explicit referensi root. Tambahkan di baris pertama: # EXTENDS: ../../CLAUDE.md

💡 Tip 3: Cross-service patterns harus di root CLAUDE.md, bukan per-service. Kalau satu service perlu tahu, semua service perlu tahu.

💡 Tip 4: Shared domain types mencegah drift. Jika order-service dan payment-service punya definisi Amount yang berbeda, itu adalah bug waiting to happen.

⚠️ Gotcha 1: AI yang generate import dari service lain. Rule NEVER import another service's internal harus explicit di CLAUDE.md dengan contoh.

⚠️ Gotcha 2: Monorepo terlalu besar untuk single context window. Gunakan Gemini (1M token) untuk cross-service analysis.

⚠️ Gotcha 3: Root CLAUDE.md yang terlalu verbose. Jaga tetap concise (< 250 baris) agar tidak diluted.

Benang merahnya: disiplin cd ke service, root yang concise, dan shared types yang konsisten — tiga kebiasaan kecil yang mencegah mayoritas masalah context di monorepo.


17.14 Checklist Setup Monorepo Context

Untuk memastikan tidak ada langkah terlewat, checklist berikut merangkum setup, governance, dan kebiasaan developer yang perlu ada.

text
 1Setup:
 2□ Root CLAUDE.md dibuat dengan universal rules (< 250 baris)
 3□ Setiap service punya service-specific CLAUDE.md
 4□ Service CLAUDE.md explicit reference root ("EXTENDS: ../../CLAUDE.md")
 5□ shared/domain/ setup: money, event, id packages
 6□ go.work setup untuk development workspace
 7□ .claudeignore setup untuk exclude generated files
 8□ Architecture boundary check script dibuat (17.10)
 9
10Governance:
11□ Ownership per layer terdefinisi (root vs service)
12□ PR process untuk perubahan context files
13□ Monthly review schedule untuk consistency
14□ New developer onboarding guide menggunakan AI (17.12)
15
16Developer habits:
17□ Semua developer tahu: selalu cd ke service directory
18□ Cross-service: Kafka events only, never direct import
19□ Shared types: selalu dari shared/domain/
20□ Generated files: via go generate, never manual edit

Checklist ini sebaiknya jadi bagian dari definition-of-done saat sebuah monorepo baru dibentuk — jauh lebih murah menyiapkan hierarki di awal daripada retrofit setelah lima service tumbuh.


17.15 Advanced: Monorepo AI Review Pipeline

Review AI di monorepo idealnya sadar akan boundary service. Workflow GitHub Actions berikut mendeteksi service yang berubah dan menjalankan review dengan context yang tepat per service.

yaml
 1# .github/workflows/monorepo-ai-review.yml
 2# Review yang aware dengan service boundaries
 3
 4name: Monorepo AI Review
 5
 6on:
 7  pull_request:
 8    branches: [main, develop]
 9
10jobs:
11  detect-services:
12    runs-on: ubuntu-latest
13    outputs:
14      services: ${{ steps.detect.outputs.services }}
15    steps:
16      - uses: actions/checkout@v4
17        with:
18          fetch-depth: 0
19      - name: Detect changed services
20        id: detect
21        run: |
22          CHANGED=$(git diff --name-only origin/main...HEAD | \
23            grep "^services/" | \
24            cut -d'/' -f2 | sort -u | \
25            jq -R -s -c 'split("\n")[:-1]')
26          echo "services=$CHANGED" >> $GITHUB_OUTPUT
27
28  review-per-service:
29    needs: detect-services
30    runs-on: ubuntu-latest
31    if: needs.detect-services.outputs.services != '[]'
32    strategy:
33      matrix:
34        service: ${{ fromJson(needs.detect-services.outputs.services) }}
35    steps:
36      - uses: actions/checkout@v4
37        with:
38          fetch-depth: 0
39
40      - name: Review ${{ matrix.service }}
41        run: |
42          # Get diff untuk specific service
43          DIFF=$(git diff origin/main...HEAD -- "services/${{ matrix.service }}/**/*.go")
44
45          # Load service-specific CLAUDE.md context
46          SERVICE_RULES=$(cat services/${{ matrix.service }}/CLAUDE.md 2>/dev/null || echo "No service CLAUDE.md")
47          ROOT_RULES=$(cat CLAUDE.md)
48
49          # AI review dengan combined context
50          # ... (call Claude API dengan combined context)
51          echo "Reviewing ${{ matrix.service }}..."

Dengan matrix per-service, review tidak lagi memakai satu aturan seragam untuk seluruh repo — tiap service dinilai dengan context-nya sendiri, persis seperti developer yang cd ke service tersebut.


17.16 Versioning Context Files

Context file adalah dokumen hidup yang perlu jejak perubahan. Header changelog berikut menunjukkan cara memberi versi pada CLAUDE.md agar perubahan behavior AI bisa ditelusuri.

text
 1Context file sebagai living document yang perlu versioning:
 2
 3# CLAUDE.md (root)
 4# Version: 3.2
 5# Last updated: 2026-07-15
 6# Changelog:
 7#   3.2: Add cross-service Kafka event rules
 8#   3.1: Add Redis key naming convention
 9#   3.0: Major rewrite untuk monorepo setup
10
11Kenapa versioning penting:
121. Audit trail ketika AI behavior berubah
132. Easy rollback jika update menyebabkan regresi
143. Developer tahu kapan rules terakhir diupdate
15
16Cara maintain di git:
17  git log -- CLAUDE.md  # lihat history
18  git blame CLAUDE.md   # siapa yang add/change apa
19
20Monthly changelog:
21  Tambahkan summary perubahan bulan ini di header CLAUDE.md
22  Ini membantu semua developer tahu apa yang berubah

Memberi versi pada context file membuat perubahan behavior AI bisa di-rollback seperti kode biasa — ketika output AI tiba-tiba berubah, changelog jadi tempat pertama untuk mencari penyebabnya.


17.17 Monorepo Context untuk Tim Besar (20+ Developer)

Saat tim membesar, banyak orang ingin mengubah CLAUDE.md sekaligus. Model ownership berlapis berikut menjaga context tetap terkendali di tim 20+ developer.

text
 1Scaling challenges saat tim besar:
 2
 3Problem: 20 developer, 5 services, semua mau update CLAUDE.md
 4Solution: Layered ownership yang ketat
 5
 6Layer 1 — Root CLAUDE.md (Architecture Team only):
 7  - Tech lead dan arch team yang approve
 8  - Semua perubahan via PR
 9  - Monthly review mandatory
10
11Layer 2 — Service CLAUDE.md (Service Team):
12  - Service tech lead yang approve
13  - PR required, tapi lebih agile dari root
14  - Sprint end review
15
16Layer 3 — Personal notes (Individual):
17  - Developer masing-masing bisa punya NOTES.md lokal
18  - Tidak di-commit, hanya untuk personal context
19  - Tidak mempengaruhi team AI behavior
20
21Process untuk propose perubahan ke root CLAUDE.md:
221. Developer notice: AI sering generate wrong pattern X
232. Developer propose: "Tambahkan rule X ke CLAUDE.md"
243. Service tech lead: validate apakah ini service-specific atau universal
254. Architecture team: review dan approve jika universal
265. Merge: semua developer update CLAUDE.md
276. Monitor: apakah AI behavior berubah sesuai harapan?

Tiga lapis ownership ini mencegah “tragedy of the commons” pada context file: perubahan universal terjaga ketat, tapi developer tetap punya ruang untuk catatan pribadi yang tidak mengganggu tim.


17.18 Shared Infrastructure Context

Selain aturan arsitektur, context service juga perlu mendeskripsikan infrastruktur yang dipakainya. Bagian CLAUDE.md berikut mendokumentasikan database, cache, dan Kafka untuk order-service.

markdown
 1# services/order-service/CLAUDE.md — Infrastructure section
 2
 3## Infrastructure Context (Order Service)
 4Database: PostgreSQL 15 via pgx/v5 pool
 5  Connection pool: min 5, max 25 connections
 6  Transaction timeout: 30 seconds
 7
 8Cache: Redis 7 via go-redis/v9
 9  Key TTL defaults:
10    Short lived (locks): 30 seconds
11    Recent data: 5 minutes
12    Reference data: 1 hour
13
14Kafka: Confluent Kafka via confluent-kafka-go v2
15  Producer: async, max.in.flight.requests.per.connection=1
16  Consumer: at-least-once delivery (idempotent handlers required!)
17
18External APIs: None (order service communicates only via Kafka)
19
20## Idempotency Requirements
21ALL Kafka consumer handlers MUST be idempotent.
22Kafka delivery: at-least-once, same message may arrive multiple times.
23Use: DB unique constraint + "ON CONFLICT DO NOTHING" as primary strategy.

Mendokumentasikan infrastruktur di context membuat AI menghasilkan kode yang sesuai realita operasional — misalnya otomatis menambahkan idempotency karena tahu Kafka memakai at-least-once delivery.


17.19 Practical Exercise: Setup Monorepo Context dari Scratch

Cara terbaik memahami hierarki context adalah membangunnya sendiri. Skrip berikut menyiapkan root CLAUDE.md, service context, shared domain, dan go.work dalam satu langkah.

bash
 1# Tutorial: setup context hierarchy untuk monorepo baru
 2
 3# Step 1: Buat root CLAUDE.md
 4cat > CLAUDE.md << 'ROOTCTX'
 5# CLAUDE.md — Root Context (Universal Rules)
 6# Version: 1.0 | Updated: 2026-07-15
 7
 8## Go Version
 9Go 1.22 only. No 1.23+ features (range-over-func, slices.Collect, iter.Seq).
10
11## Architecture (All Services)
12handler → usecase → repository → domain
13
14Layer imports (STRICT):
15- handler: ONLY usecase interfaces
16- usecase: ONLY domain + repository interfaces
17- repository: ONLY domain + database drivers
18- domain: ZERO external imports (stdlib only)
19
20## Error Handling
21Repository not-found: return nil, nil (NEVER error)
22Error wrap: fmt.Errorf("packageName.MethodName: %w", err)
23HTTP error: {"error": "UPPERCASE_SNAKE_CASE_CODE"}
24
25## Money
26ALWAYS int64 cents via shared/domain/money.IDR
27NEVER float64, float32
28
29## Testing
30testify/suite + gomock pattern
31
32## Cross-Service (CRITICAL)
33NEVER import another service's internal packages
34Communication: Kafka events ONLY
35Shared types: shared/domain ONLY
36ROOTCTX
37
38# Step 2: Buat service context
39mkdir -p services/order-service
40cat > services/order-service/CLAUDE.md << 'SVCCTX'
41# services/order-service/CLAUDE.md
42# EXTENDS: ../../CLAUDE.md (all universal rules apply)
43
44## Service: order-service (Port: 8081)
45Purpose: Order lifecycle management
46
47## Kafka Topics
48Produces: order.created, order.confirmed, order.cancelled
49Consumes: payment.completed, inventory.reserved
50
51## Error Codes (Service-Specific)
52ORDER_NOT_FOUND, ORDER_NOT_CANCELLABLE, CANCEL_WINDOW_EXPIRED
53
54## SLO
55GET /orders/:id P99 < 50ms
56POST /orders P99 < 200ms
57SVCCTX
58
59# Step 3: Setup shared domain
60mkdir -p shared/domain/money shared/domain/event shared/domain/id
61
62# Step 4: Setup go.work
63cat > go.work << 'WORK'
64go 1.22
65
66use ./shared/domain
67use ./services/order-service
68WORK
69
70echo "Monorepo context hierarchy setup complete"
71echo "Developer guide: ALWAYS cd to service directory before AI session"

Setelah menjalankan skrip ini, kamu punya kerangka context hierarchy yang lengkap — tinggal isi shared domain packages dan tambahkan service berikutnya mengikuti pola yang sama.


17.20 Measuring Context Effectiveness di Monorepo

Setup context perlu diverifikasi apakah benar-benar bekerja. Empat tes berikut memeriksa isolasi service, penegakan aturan universal, pattern service-specific, dan boundary lintas-service.

text
 1Cara ukur apakah context hierarchy bekerja:
 2
 3Test 1: Service isolation
 4  cd services/order-service
 5  claude > "Implement CreateOrder"
 6  Expected: AI generate code yang import dari shared/domain/
 7            TIDAK generate cross-service import
 8  Jika AI generate wrong import: update service CLAUDE.md
 9
10Test 2: Universal rule enforcement
11  di semua services: coba trigger pattern yang dilanggar
12  claude > "Handle not found case in repository"
13  Expected: AI return (nil, nil), bukan error
14  Jika salah: root CLAUDE.md perlu di-strengthen
15
16Test 3: Service-specific pattern
17  di order-service:
18  claude > "What Kafka topics does this service produce?"
19  Expected: AI list topics dari service CLAUDE.md
20  Jika salah: service CLAUDE.md tidak di-load dengan benar
21
22Test 4: Cross-service boundary
23  claude > "Call payment-service API directly from order usecase"
24  Expected: AI refuse atau propose Kafka alternative
25  Jika AI generate direct call: rule belum cukup explicit

Empat tes ini mengubah pertanyaan subjektif “apakah context saya bagus?” menjadi verifikasi konkret — jika satu tes gagal, ia langsung menunjuk file mana yang perlu diperkuat.


17.21 Integrating External Tools dengan Monorepo Context

Aturan boundary sebaiknya juga ditegakkan oleh linter, bukan hanya AI. Konfigurasi golangci-lint berikut memblokir cross-service import lewat gomodguard dan depguard.

yaml
 1# golangci-lint config yang aware dengan monorepo boundaries
 2# .golangci.yml (root)
 3
 4linters-settings:
 5  gomodguard:
 6    blocked:
 7      modules:
 8        # Prevent cross-service imports
 9        - github.com/santekno/santekno-shop/services/payment-service:
10            recommendations:
11              - "Use Kafka events for cross-service communication"
12        - github.com/santekno/santekno-shop/services/order-service/internal:
13            recommendations:
14              - "Never import other service internal packages"
15
16  depguard:
17    rules:
18      prevent-cross-service:
19        deny:
20          - pkg: "github.com/santekno/santekno-shop/services/*/internal"
21            desc: "Cross-service internal imports are forbidden. Use Kafka events or shared/domain."
22
23linters:
24  enable:
25    - gomodguard
26    - depguard

Dengan depguard, boundary lintas-service ditegakkan oleh linter yang sudah jalan di setiap CI — memberi lapisan enforcement kedua yang independen dari skrip kustom maupun review AI.


17.22 Ringkasan

Context management di Go monorepo membutuhkan hierarki yang jelas dan disiplin konsisten. Setup yang benar: root CLAUDE.md (universal) + service CLAUDE.md (specific) + shared/domain (types) + go.work (workspace) = AI yang tahu boundaries dan context untuk setiap service.

Rule paling penting: cd services/order-service sebelum claude. Always.

Investasi 1-2 hari untuk menata hierarki context di awal memberi compounding value: setiap developer otomatis mendapat AI output yang sesuai service-nya tanpa mengulang aturan di setiap sesi. Setelah context tertata rapi, langkah berikutnya adalah membawa AI ke pipeline otomatis — quality gates di CI/CD.

Artikel Terkait

💬 Komentar