Component Interactions Diagrams

This document shows how specific components interact within DocBuilder, focusing on theme configuration, forge integration, and change detection.

Last Updated: January 4, 2026 - Reflects Relearn-only configuration.

Relearn Theme Configuration

DocBuilder uses the Relearn theme exclusively with hardcoded default configuration.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Relearn Theme Configuration               β”‚
β”‚          (internal/hugo/config_writer.go)          β”‚
β”‚                                                    β”‚
β”‚  applyRelearnThemeDefaults(params)                 β”‚
β”‚                                                    β”‚
β”‚  Default Parameters:                               β”‚
β”‚  - themeVariant: ["auto", "zen-light", "zen-dark"]β”‚
β”‚  - themeVariantAuto: ["zen-light", "zen-dark"]    β”‚
β”‚  - showVisitedLinks: true                          β”‚
β”‚  - collapsibleMenu: true                           β”‚
β”‚  - alwaysopen: false                               β”‚
β”‚  - disableBreadcrumb: false                        β”‚
β”‚  - disableLandingPageButton: true                  β”‚
β”‚  - disableShortcutsTitle: false                    β”‚
β”‚  - disableLanguageSwitchingButton: true            β”‚
β”‚  - disableTagHiddenPages: false                    β”‚
β”‚  - disableGeneratorVersion: false                  β”‚
β”‚  - mermaid.enable: true                            β”‚
β”‚  - math.enable: true                               β”‚
β”‚  - enable_transitions: (if configured)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Generation Flow:
1. Load config β†’ title, baseURL, etc.
2. Apply Relearn defaults (via applyRelearnThemeDefaults)
3. User params deep merge (user values override defaults)
4. Add dynamic fields (build_date, doc_builder_version)
5. Add Hugo module: github.com/McShelby/hugo-theme-relearn
6. Configure i18n settings (defaultContentLanguage: "en")
7. Write hugo.yaml to staging directory

Configuration Merging Strategy

Deep Merge Algorithm:

For each key in user params:
    If value is map:
        Recursively merge with default map
    Else:
        Override default value

Example:
    Default:  { mermaid: { enable: true, theme: "default" } }
    User:     { mermaid: { theme: "dark" } }
    Result:   { mermaid: { enable: true, theme: "dark" } }

Non-Overridable Settings:

  • Hugo module path: Always github.com/McShelby/hugo-theme-relearn
  • Language configuration: Always English (en)
  • Markup configuration: Goldmark with specific extensions

Theme-Specific Features

Auto Theme Variant:

  • Detects OS light/dark preference
  • Switches between configured variants
  • Default: zen-light (light) / zen-dark (dark)

Mermaid Diagrams:

  • Enabled by default
  • Supports flowcharts, sequence diagrams, Gantt charts
  • Theme-aware styling

Math Support (MathJax):

  • Enabled by default
  • LaTeX-style equations
  • Inline: $equation$
  • Block: $$equation$$

Search:

  • Lunr.js-powered offline search
  • Searches titles, content, and tags
  • Automatically indexes all pages

Implementation Files

  • internal/hugo/config_writer.go - Configuration generation
  • internal/hugo/modules.go - Hugo module management
  • internal/config/typed/hugo_config.go - Configuration validation

Forge Integration

Forge clients provide repository metadata and edit link generation.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Forge Factory                      β”‚
β”‚      (internal/forge/factory.go)             β”‚
β”‚                                              β”‚
β”‚  NewForge(config) β†’ Forge                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”‚ Based on URL detection
               β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚          β”‚          β”‚
    β–Ό          β–Ό          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚GitHub  β”‚ β”‚GitLab  β”‚ β”‚Forgejo  β”‚
β”‚Client  β”‚ β”‚Client  β”‚ β”‚Client   β”‚
β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
    β”‚          β”‚           β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”‚ All compose
               β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚ BaseForge   β”‚
        β”‚             β”‚
        β”‚ HTTP Client β”‚
        β”‚ Auth Header β”‚
        β”‚ Base URL    β”‚
        β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”‚ Uses
               β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚http.Client  β”‚
        β”‚             β”‚
        β”‚- Timeout    β”‚
        β”‚- TLS Config β”‚
        β”‚- Transport  β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Forge Detection

URL-Based Detection:

Repository URL Analysis:
    β”‚
    β”œβ”€ Contains "github.com" β†’ GitHubClient
    β”œβ”€ Contains "gitlab.com" β†’ GitLabClient
    β”œβ”€ Contains "forgejo" β†’ ForgejoClient
    └─ Default β†’ GenericForge

Configuration Priority:

  1. Explicit forge.type in config (if provided)
  2. URL pattern matching
  3. API endpoint detection (if accessible)

Operation Flow

Edit Link Generation:

1. Document processed in pipeline
    β”‚
    β–Ό
2. addEditLink transform called
    β”‚
    β”œβ”€ Extract repository metadata
    β”‚   β”œβ”€ Repository URL
    β”‚   β”œβ”€ Source commit
    β”‚   └─ Source branch
    β”‚
    β”œβ”€ Detect forge type
    β”‚   └─ GitHubClient
    β”‚
    β”œβ”€ Build edit URL
    β”‚   β”œβ”€ Base: https://github.com/user/repo
    β”‚   β”œβ”€ Action: /edit/
    β”‚   β”œβ”€ Branch: main
    β”‚   └─ Path: /docs/file.md
    β”‚   Result: https://github.com/user/repo/edit/main/docs/file.md
    β”‚
    └─ Inject into front matter
        └─ editURL: https://...

API Integration (Future):

Forge Client
    β”‚
    β”œβ”€ Authenticate
    β”‚   β”œβ”€ Token header: "Authorization: Bearer {token}"
    β”‚   └─ Custom headers (API version, User-Agent)
    β”‚
    β”œβ”€ Fetch Repository Metadata
    β”‚   β”œβ”€ GET /repos/{owner}/{repo}
    β”‚   β”œβ”€ Parse response
    β”‚   └─ Return: name, description, default_branch
    β”‚
    └─ Fetch Commit Info
        β”œβ”€ GET /repos/{owner}/{repo}/commits/{sha}
        β”œβ”€ Parse response
        └─ Return: author, date, message

Forge-Specific Patterns

GitHub:

  • Edit URL: /{owner}/{repo}/edit/{branch}/{path}
  • API: https://api.github.com
  • Headers: X-GitHub-Api-Version: 2022-11-28

GitLab:

  • Edit URL: /{owner}/{repo}/-/edit/{branch}/{path}
  • API: https://gitlab.com/api/v4
  • Headers: PRIVATE-TOKEN: {token}

Forgejo:

  • Edit URL: /{owner}/{repo}/_edit/{branch}/{path}
  • API: https://forge.example.com/api/v1
  • Headers: Authorization: token {token}

Implementation Files

  • internal/forge/factory.go - Forge detection and creation
  • internal/forge/github/ - GitHub client
  • internal/forge/gitlab/ - GitLab client
  • internal/forge/forgejo/ - Forgejo client
  • internal/hugo/edit_link_resolver.go - Edit link generation

Change Detection System

Multi-level change detection optimizes incremental builds.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Change Detector                         β”‚
β”‚      (internal/hugo/doc_changes.go)              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”‚ DetectChanges(repos)
               β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  Load Previous State β”‚
    β”‚  - HEAD refs         β”‚
    β”‚  - Doc hashes        β”‚
    β”‚  - Commit dates      β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  For each repository β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”œβ”€ Level 1: HEAD Comparison
               β”‚  β”œβ”€ Read current HEAD
               β”‚  β”œβ”€ Compare to previous
               β”‚  β”œβ”€ Changed? β†’ Include
               β”‚  └─ Cost: O(1) - single git command
               β”‚
               β”œβ”€ Level 2: Quick Hash
               β”‚  β”œβ”€ Hash directory tree
               β”‚  β”œβ”€ Compare to previous
               β”‚  β”œβ”€ Changed? β†’ Include
               β”‚  └─ Cost: O(n) - filesystem scan
               β”‚
               β”œβ”€ Level 3: Doc Files Hash
               β”‚  β”œβ”€ Discover docs
               β”‚  β”œβ”€ Sort paths
               β”‚  β”œβ”€ SHA-256 hash
               β”‚  β”œβ”€ Compare to previous
               β”‚  β”œβ”€ Changed? β†’ Include
               β”‚  └─ Cost: O(n*m) - read file contents
               β”‚
               └─ Level 4: Deletion Detection
                  β”œβ”€ Compare file lists
                  β”œβ”€ Detect removed files
                  β”œβ”€ Deletions? β†’ Include
                  └─ Cost: O(n) - set difference
               
               β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚    ChangeSet         β”‚
    β”‚                      β”‚
    β”‚ - ChangedRepos: []   β”‚
    β”‚ - SkippedRepos: []   β”‚
    β”‚ - Reasons: map[]     β”‚
    β”‚ - RequiresRebuild    β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Change Detection Algorithm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
func DetectChanges(repos []Repository, prevState BuildState) ChangeSet {
    changeSet := NewChangeSet()
    
    for _, repo := range repos {
        // Level 1: HEAD comparison
        currentHEAD := git.GetHEAD(repo)
        previousHEAD := prevState.Commits[repo.Name]
        
        if currentHEAD != previousHEAD {
            changeSet.AddChanged(repo, "HEAD changed")
            continue
        }
        
        // Level 2: Quick directory hash
        dirHash := computeDirectoryHash(repo.Path)
        prevHash := prevState.DirectoryHashes[repo.Name]
        
        if dirHash != prevHash {
            changeSet.AddChanged(repo, "directory structure changed")
            continue
        }
        
        // Level 3: Documentation files hash
        docs := DiscoverDocs(repo)
        docHash := computeDocHash(docs)
        prevDocHash := prevState.DocHashes[repo.Name]
        
        if docHash != prevDocHash {
            changeSet.AddChanged(repo, "documentation changed")
            continue
        }
        
        // Level 4: Deletion detection
        prevDocs := prevState.DocsByRepo[repo.Name]
        if detectDeletions(docs, prevDocs) {
            changeSet.AddChanged(repo, "files deleted")
            continue
        }
        
        // No changes detected
        changeSet.AddSkipped(repo, "no changes")
    }
    
    return changeSet
}

Optimization Strategies

Early Exit:

  • Stop at first detected change
  • Don’t compute expensive hashes if HEAD differs
  • Saves computation time

Caching:

  • Cache HEAD references
  • Cache directory hashes
  • Cache file content hashes
  • Reuse across builds

Parallel Detection:

  • Check multiple repositories concurrently
  • Use worker pool pattern
  • Aggregate results

Implementation Files

  • internal/hugo/doc_changes.go - Change detection logic
  • internal/hugo/early_skip.go - Early skip evaluation
  • internal/state/git_state.go - State persistence
  • internal/git/git.go - HEAD reference reading

Build State Management

Build state tracks progress and enables incremental builds.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              BuildState                         β”‚
β”‚      (internal/hugo/build_state.go)             β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚          GitState                         β”‚  β”‚
β”‚  β”‚  - WorkspaceDir: /tmp/docbuilder-xyz/    β”‚  β”‚
β”‚  β”‚  - Repositories: []Repository            β”‚  β”‚
β”‚  β”‚  - Commits: map[repo]string              β”‚  β”‚
β”‚  β”‚  - CommitDates: map[repo]time.Time       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚          DocsState                        β”‚  β”‚
β”‚  β”‚  - Files: []DocFile                      β”‚  β”‚
β”‚  β”‚  - IsSingleRepo: bool                    β”‚  β”‚
β”‚  β”‚  - FilesByRepository: map[repo][]DocFile β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚          PipelineState                    β”‚  β”‚
β”‚  β”‚  - ConfigHash: string                    β”‚  β”‚
β”‚  β”‚  - ExecutedStages: []string              β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚          BuildReport                      β”‚  β”‚
β”‚  β”‚  - Status: BuildStatus                   β”‚  β”‚
β”‚  β”‚  - StageDurations: map[stage]Duration    β”‚  β”‚
β”‚  β”‚  - Errors: []BuildIssue                  β”‚  β”‚
β”‚  β”‚  - Warnings: []BuildIssue                β”‚  β”‚
β”‚  β”‚  - Summary: string                       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚          Generator                        β”‚  β”‚
β”‚  β”‚  - Reference to Hugo generator           β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

State Lifecycle

1. Initialization
    β”‚
    β”œβ”€ Create BuildState
    β”œβ”€ Initialize GitState
    β”œβ”€ Initialize DocsState
    β”œβ”€ Initialize PipelineState
    └─ Create BuildReport
    β”‚
    β–Ό
2. Stage Execution
    β”‚
    β”œβ”€ For each stage:
    β”‚   β”œβ”€ Record start time
    β”‚   β”œβ”€ Execute stage function
    β”‚   β”œβ”€ Update sub-states
    β”‚   β”œβ”€ Record duration
    β”‚   └─ Handle errors
    β”‚
    β–Ό
3. Persistence
    β”‚
    β”œβ”€ Serialize GitState
    β”œβ”€ Serialize DocsState
    β”œβ”€ Serialize PipelineState
    └─ Write to .docbuilder/state.json
    β”‚
    β–Ό
4. Next Build
    β”‚
    β”œβ”€ Load previous state
    β”œβ”€ Compare for changes
    └─ Decide incremental/full

State Update Patterns

GitState Updates:

1
2
3
4
5
6
// After cloning repository
bs.Git.Commits[repo.Name] = headCommit
bs.Git.CommitDates[repo.Name] = commitTime

// After all repos cloned
bs.Report.ClonedRepositories = len(bs.Git.Commits)

DocsState Updates:

1
2
3
4
5
6
7
// After discovery
bs.Docs.Files = discoveredFiles
bs.Docs.IsSingleRepo = (len(repos) == 1)
bs.Docs.FilesByRepository = groupByRepo(discoveredFiles)

// After processing
bs.Report.FilesProcessed = len(bs.Docs.Files)

PipelineState Updates:

1
2
3
4
5
// After config generation
bs.Pipeline.ConfigHash = computeHash(config)

// After each stage
bs.Pipeline.ExecutedStages = append(bs.Pipeline.ExecutedStages, stageName)

Implementation Files

  • internal/hugo/build_state.go - BuildState definition
  • internal/state/git_state.go - Git-specific state
  • internal/state/docs_state.go - Documentation-specific state
  • internal/state/pipeline_state.go - Pipeline metadata

References

permalink[component-interactions-diagrams](https://docs.home.luguber.info/_uid/36766002-6e10-4a98-9c90-981b15fa6f99/)