diff --git a/CHANGES_SUMMARY.txt b/CHANGES_SUMMARY.txt deleted file mode 100644 index f179a51a..00000000 --- a/CHANGES_SUMMARY.txt +++ /dev/null @@ -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 -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) - -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) - -================================================================================ diff --git a/internal/application/repository/wiki_page.go b/internal/application/repository/wiki_page.go index 8c744dc8..c5eef574 100644 --- a/internal/application/repository/wiki_page.go +++ b/internal/application/repository/wiki_page.go @@ -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 diff --git a/internal/application/service/wiki_page.go b/internal/application/service/wiki_page.go index 29a33afe..4f1e2618 100644 --- a/internal/application/service/wiki_page.go +++ b/internal/application/service/wiki_page.go @@ -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) diff --git a/internal/types/interfaces/wiki_page.go b/internal/types/interfaces/wiki_page.go index 5af91469..f2d3ad7c 100644 --- a/internal/types/interfaces/wiki_page.go +++ b/internal/types/interfaces/wiki_page.go @@ -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. diff --git a/internal/types/wiki_page.go b/internal/types/wiki_page.go index 60b20cbc..28b91541 100644 --- a/internal/types/wiki_page.go +++ b/internal/types/wiki_page.go @@ -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"`