feat: Refactor wiki page update logic for improved version control

- Enhanced the UpdatePage and UpdateMeta methods to differentiate between user-visible content changes and bookkeeping updates, ensuring the version number is only incremented for actual content modifications.
- Updated the WikiPage struct and associated interfaces to reflect the new versioning policy, improving clarity on when the version is modified.
- Improved documentation for methods to clarify their intended use and behavior regarding versioning and metadata updates.
This commit is contained in:
wizardchen
2026-04-22 21:28:20 +08:00
parent cf1c1d597d
commit ffc4eeaf57
5 changed files with 69 additions and 294 deletions

View File

@@ -1,272 +0,0 @@
================================================================================
WIKICONFIG UPDATE FIX - CHANGES SUMMARY
================================================================================
STATUS: ✅ COMPLETE AND COMMITTED
COMMIT HASH: b09893d5
DATE: April 7, 2026 15:19:53 UTC+8
================================================================================
PROBLEM
================================================================================
The wiki_config field could not be updated when modifying a knowledge base via
the REST API PUT endpoint. While KB creation worked fine, updates silently
dropped the wiki_config data, making it impossible to configure wiki settings
after KB creation.
ROOT CAUSE: The KnowledgeBaseConfig struct (used to deserialize PUT requests)
was missing the WikiConfig field, causing JSON unmarshaling to silently drop
any wiki_config data sent in requests.
================================================================================
SOLUTION
================================================================================
Implemented three complementary fixes across the system:
1. BACKEND TYPES (internal/types/knowledgebase.go)
- Added WikiConfig *WikiConfig field to KnowledgeBaseConfig struct
- Enables JSON unmarshaling of wiki_config from update requests
- Lines modified: 107-108
2. BACKEND SERVICE (internal/application/service/knowledgebase.go)
- Added persistence logic in UpdateKnowledgeBase method
- Code: if config.WikiConfig != nil { kb.WikiConfig = config.WikiConfig }
- Lines modified: 297-299
3. FRONTEND TYPES (frontend/src/api/knowledge-base/index.ts)
- Added WikiConfig type to createKnowledgeBase function signature
- Added WikiConfig type to updateKnowledgeBase config parameter
- Provides IDE autocomplete and type safety
- Lines modified: 31-37 (create), 49-64 (update)
================================================================================
CODE CHANGES
================================================================================
File 1: internal/types/knowledgebase.go
────────────────────────────────────────
Lines 107-108 (added):
// Wiki configuration (only for wiki-enabled knowledge bases)
WikiConfig *WikiConfig `yaml:"wiki_config" json:"wiki_config"`
File 2: internal/application/service/knowledgebase.go
───────────────────────────────────────────────────────
Lines 297-299 (added):
if config.WikiConfig != nil {
kb.WikiConfig = config.WikiConfig
}
File 3: frontend/src/api/knowledge-base/index.ts
───────────────────────────────────────────────
Lines 31-37 (added to createKnowledgeBase):
wiki_config?: {
enabled: boolean;
auto_ingest?: boolean;
synthesis_model_id?: string;
wiki_language?: string;
max_pages_per_ingest?: number;
};
Lines 49-64 (added to updateKnowledgeBase):
config?: {
chunking_config?: any;
image_processing_config?: any;
faq_config?: any;
wiki_config?: {
enabled: boolean;
auto_ingest?: boolean;
synthesis_model_id?: string;
wiki_language?: string;
max_pages_per_ingest?: number;
};
}
================================================================================
STATISTICS
================================================================================
Files Changed: 3
Lines Added: 43
Lines Removed: 20
Total Changes: 63 lines
Net Change: +23 lines
Breaking Changes: 0
Backward Compatible: Yes ✅
Database Migrations: 0 (not required)
Deployment Downtime: 0 (code-only change)
================================================================================
VERIFICATION
================================================================================
✓ Code changes implemented in all three layers
✓ Types properly defined for JSON marshaling/unmarshaling
✓ Service logic applies wiki_config updates
✓ Frontend types support IDE autocomplete
✓ Backward compatibility maintained (all new fields optional)
✓ No breaking changes to existing APIs
✓ Git commit created with proper attribution
================================================================================
TESTING REQUIREMENTS
================================================================================
Test Case 1: Create KB with wiki_config
Command: POST /api/v1/knowledge-bases
Expected: KB created with wiki_config populated
Test Case 2: Update KB with wiki_config (NOW WORKS)
Command: PUT /api/v1/knowledge-bases/{id}
Expected: KB updated, wiki_config persisted
Test Case 3: Verify persistence
Command: GET /api/v1/knowledge-bases/{id}
Expected: Response contains updated wiki_config
Test Case 4: Database level verification
Command: SELECT wiki_config FROM knowledge_bases WHERE id = '{id}';
Expected: JSONB column contains all wiki_config fields
================================================================================
DEPLOYMENT
================================================================================
Prerequisites:
- Code review approved
- All tests passing
- Backup of database (optional but recommended)
Steps:
1. Review: git show b09893d5
2. Test: go test ./internal/application/service/...
3. Deploy: git pull && deploy [commit]
4. Verify: curl http://localhost:8080/api/v1/knowledge-bases/test-id
Rollback:
If issues discovered: git revert b09893d5
(Database: No migration to rollback, column already exists)
================================================================================
DOCUMENTATION
================================================================================
Documentation Files Generated:
1. WIKI_CONFIG_FIX_COMPLETE.md - Complete overview (START HERE)
2. IMPLEMENTATION_SUMMARY.md - Detailed technical guide
3. WIKI_CONFIG_VERIFICATION.md - Testing and verification guide
4. README_WIKI_CONFIG_FIX.md - Documentation index
5. CHANGES_SUMMARY.txt - This file
Documentation Structure:
- For PM/Leads: WIKI_CONFIG_FIX_COMPLETE.md (summary + checklist)
- For Developers: WIKI_CONFIG_QUICK_REFERENCE.md + Implementation_SUMMARY.md
- For QA: WIKI_CONFIG_VERIFICATION.md (test cases)
- For DevOps: WIKI_CONFIG_FIX_COMPLETE.md (deployment checklist)
================================================================================
IMPACT ANALYSIS
================================================================================
What Works Now:
✓ Creating KB with wiki_config via API: POST /api/v1/knowledge-bases
✓ Updating KB wiki_config via API: PUT /api/v1/knowledge-bases/{id}
✓ Frontend IDE autocomplete for wiki_config in both functions
✓ Type safety for wiki_config in TypeScript
Backward Compatibility:
✓ Existing KB creation without wiki_config still works
✓ Existing KB updates without config.wiki_config still work
✓ All new fields are optional
✓ No existing code affected
Performance Impact:
✓ Minimal - one additional null check in service layer
✓ No database performance impact
✓ No frontend performance impact
================================================================================
SUCCESS CRITERIA ✅
================================================================================
- [x] Problem identified and root cause analyzed
- [x] Solution designed across all three system layers
- [x] Code changes implemented and verified
- [x] Backward compatibility confirmed
- [x] Git commit created with proper attribution
- [x] Comprehensive documentation generated
- [x] Ready for testing and deployment
================================================================================
COMMIT INFORMATION
================================================================================
Commit Hash: b09893d5a388d709ac144730f5d61bbc9cf460c8
Author: wizardchen <wizardchen@tencent.com>
Date: Tue Apr 7 15:19:53 2026 +0800
Files Modified: 3
Subject: fix: Enable wiki_config updates in knowledge base configuration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
View full commit: git show b09893d5
View diff: git diff b09893d5~1 b09893d5
================================================================================
NEXT STEPS
================================================================================
1. Code Review Phase
[ ] Project maintainer reviews commit
[ ] Code reviewer checks all changes
[ ] Approval granted
2. Testing Phase
[ ] Unit tests executed
[ ] Integration tests executed
[ ] Manual testing completed
[ ] All test cases pass
3. Deployment Phase
[ ] Deploy to staging environment
[ ] Verify in staging with test cases
[ ] Deploy to production
[ ] Monitor for issues
4. Closure Phase
[ ] Document testing results
[ ] Update project status
[ ] Plan for wiki feature enhancements
================================================================================
REFERENCES
================================================================================
Documentation:
- README_WIKI_CONFIG_FIX.md (documentation index)
- WIKI_CONFIG_FIX_COMPLETE.md (complete overview)
- IMPLEMENTATION_SUMMARY.md (technical details)
- WIKI_CONFIG_VERIFICATION.md (testing guide)
Code:
- git show b09893d5 (full commit with diffs)
- git diff b09893d5~1 b09893d5 (detailed changes)
- git log --oneline (commit history)
Related Files:
- internal/types/knowledgebase.go (type definitions)
- internal/application/service/knowledgebase.go (service logic)
- frontend/src/api/knowledge-base/index.ts (API functions)
================================================================================
✅ READY FOR PRODUCTION
Last Updated: April 7, 2026 15:19:53 UTC+8
Status: Complete and committed
Quality: Production-ready
Risk Level: Low (backward compatible, code-only change)
================================================================================

View File

@@ -59,19 +59,25 @@ func (r *wikiPageRepository) Update(ctx context.Context, page *types.WikiPage) e
return nil
}
// UpdateMeta updates only metadata fields (links, status, source_refs) WITHOUT
// incrementing the version number. Used for internal bookkeeping operations
// like link maintenance, status changes, and source ref updates.
// UpdateMeta updates bookkeeping / provenance fields WITHOUT incrementing the
// version number. "Content" for versioning purposes is the user-visible page
// body (title/content/summary/page_type/status); everything else — links,
// source refs, chunk refs, page_metadata — is considered bookkeeping and is
// refreshed here so the version counter only advances on real edits.
//
// Used by link maintenance, re-ingest (same-content case), and status changes.
func (r *wikiPageRepository) UpdateMeta(ctx context.Context, page *types.WikiPage) error {
result := r.db.WithContext(ctx).
Model(page).
Where("id = ?", page.ID).
Updates(map[string]interface{}{
"in_links": page.InLinks,
"out_links": page.OutLinks,
"status": page.Status,
"source_refs": page.SourceRefs,
"updated_at": page.UpdatedAt,
"in_links": page.InLinks,
"out_links": page.OutLinks,
"status": page.Status,
"source_refs": page.SourceRefs,
"chunk_refs": page.ChunkRefs,
"page_metadata": page.PageMetadata,
"updated_at": page.UpdatedAt,
})
if result.Error != nil {
return result.Error

View File

@@ -77,7 +77,16 @@ func (s *wikiPageService) CreatePage(ctx context.Context, page *types.WikiPage)
return page, nil
}
// UpdatePage updates an existing wiki page
// UpdatePage updates an existing wiki page.
//
// Version bump policy: the `version` column is intended to track the user-
// visible content revision, not every row rewrite. We therefore bump it only
// when at least one of the user-facing fields actually changes — title,
// content, summary, page_type, or status. Bookkeeping-only writes (refreshing
// source_refs after re-ingest when the body is identical, rebuilding the index
// page with the same directory, cross-link injection that ends up replacing
// nothing, etc.) still persist through `UpdateMeta` but leave `version`
// untouched so consumers can treat a bump as a real edit signal.
func (s *wikiPageService) UpdatePage(ctx context.Context, page *types.WikiPage) (*types.WikiPage, error) {
existing, err := s.repo.GetBySlug(ctx, page.KnowledgeBaseID, page.Slug)
if err != nil {
@@ -86,7 +95,14 @@ func (s *wikiPageService) UpdatePage(ctx context.Context, page *types.WikiPage)
oldOutLinks := existing.OutLinks
// Update fields (version is incremented by the repository's optimistic lock)
// Snapshot user-visible fields BEFORE mutation so we can decide whether
// this is a real content change or just bookkeeping.
contentChanged := existing.Title != page.Title ||
existing.Content != page.Content ||
existing.Summary != page.Summary ||
existing.PageType != page.PageType ||
existing.Status != page.Status
existing.Title = page.Title
existing.Content = page.Content
existing.Summary = page.Summary
@@ -97,14 +113,25 @@ func (s *wikiPageService) UpdatePage(ctx context.Context, page *types.WikiPage)
existing.Status = page.Status
existing.UpdatedAt = time.Now()
// Re-parse outbound links
// Outbound links are a pure derivative of content, so they only shift
// when content shifts. Re-parse unconditionally to stay consistent with
// the stored body.
existing.OutLinks = s.parseOutLinks(existing.Content)
if err := s.repo.Update(ctx, existing); err != nil {
return nil, fmt.Errorf("update wiki page: %w", err)
if contentChanged {
if err := s.repo.Update(ctx, existing); err != nil {
return nil, fmt.Errorf("update wiki page: %w", err)
}
} else {
// No user-visible change — persist bookkeeping fields but preserve
// the version so downstream consumers can rely on it.
if err := s.repo.UpdateMeta(ctx, existing); err != nil {
return nil, fmt.Errorf("update wiki page meta: %w", err)
}
}
// Update inbound links: remove old, add new
// Update inbound links: remove old, add new. If content didn't change,
// oldOutLinks == existing.OutLinks and these calls are effectively no-ops.
s.removeInLinks(ctx, existing.KnowledgeBaseID, existing.Slug, oldOutLinks)
s.updateInLinks(ctx, existing.KnowledgeBaseID, existing.Slug, existing.OutLinks)

View File

@@ -14,13 +14,17 @@ type WikiPageService interface {
// bidirectional link references, and syncs to chunks for retrieval.
CreatePage(ctx context.Context, page *types.WikiPage) (*types.WikiPage, error)
// UpdatePage updates an existing wiki page, re-parses links,
// updates bidirectional references, increments version, and re-syncs chunks.
// Use for content changes visible to the user.
// UpdatePage updates an existing wiki page, re-parses links, and updates
// bidirectional references. The `version` field is incremented only when
// a user-visible content field (title, content, summary, page_type,
// status) actually differs from the stored value — bookkeeping-only
// writes (e.g. refreshing source_refs after a same-content re-ingest) are
// persisted without bumping the version.
UpdatePage(ctx context.Context, page *types.WikiPage) (*types.WikiPage, error)
// UpdatePageMeta updates only metadata (status, source_refs) without
// incrementing version or re-parsing links. Use for publish/archive/source ref changes.
// UpdatePageMeta updates only metadata (status, source_refs, etc.) without
// incrementing version or re-parsing links. Use for publish/archive/source
// ref changes driven by internal reconciliation.
UpdatePageMeta(ctx context.Context, page *types.WikiPage) error
// GetPageBySlug retrieves a wiki page by its slug within a knowledge base.
@@ -87,10 +91,16 @@ type WikiPageRepository interface {
// Create inserts a new wiki page record.
Create(ctx context.Context, page *types.WikiPage) error
// Update updates an existing wiki page record (increments version — content changes).
// Update rewrites a wiki page record with optimistic locking and
// unconditionally increments `version`. Callers are responsible for
// deciding whether the edit is user-visible — the service layer uses
// UpdateMeta for bookkeeping-only writes instead.
Update(ctx context.Context, page *types.WikiPage) error
// UpdateMeta updates only metadata fields (links, status, source_refs) without version bump.
// UpdateMeta updates bookkeeping / provenance fields (in/out links,
// status, source_refs, chunk_refs, page_metadata, updated_at) without
// touching `version`. Safe for link maintenance, re-ingest with an
// unchanged body, and status-only transitions.
UpdateMeta(ctx context.Context, page *types.WikiPage) error
// GetByID retrieves a wiki page by its unique ID.

View File

@@ -84,7 +84,11 @@ type WikiPage struct {
OutLinks StringArray `json:"out_links" gorm:"type:json"`
// Arbitrary metadata (tags, categories, dates, etc.)
PageMetadata JSON `json:"page_metadata" gorm:"column:page_metadata;type:json"`
// Version number, incremented on each update
// Version number. Incremented only when a user-visible content field
// (title, content, summary, page_type, status) actually changes; pure
// bookkeeping writes (link maintenance, same-content re-ingest, status
// sync from background jobs) leave it untouched so it can be used as a
// real "the page was edited" signal.
Version int `json:"version" gorm:"default:1"`
// Creation time
CreatedAt time.Time `json:"created_at"`