tractatus/scripts/audit-section-categories.js
TheFlow 8c22811110 feat(docs): intelligent section recategorization + i18n infrastructure
This commit includes two major improvements to the documentation system:

## 1. Section Recategorization (UX Fix)

**Problem**: 64 sections (24%) were incorrectly marked as "critical" and
displayed at the bottom of documents, burying important foundational content.

**Solution**:
- Created intelligent recategorization script analyzing titles, excerpts,
  and document context
- Reduced "critical" from 64 → 2 sections (97% reduction)
- Properly categorized content by purpose:
  - Conceptual: 63 → 138 (+119%) - foundations, "why this matters"
  - Practical: 3 → 46 (+1433%) - how-to guides, examples
  - Technical: 111 → 50 (-55%) - true implementation details

**UI Improvements**:
- Reordered category display: Critical → Conceptual → Practical → Technical → Reference
- Changed Critical color from amber to red for better visual distinction
- All 22 documents recategorized (173 sections updated)

## 2. i18n Infrastructure (Phase 2)

**Backend**:
- DeepL API integration service with quota management and error handling
- Translation API routes (GET /api/documents/:slug?lang=de, POST /api/documents/:id/translate)
- Document model already supports translations field (no schema changes)

**Frontend**:
- docs-app.js enhanced with language detection and URL parameter support
- Automatic fallback to English when translation unavailable
- Integration with existing i18n-simple.js system

**Scripts**:
- translate-all-documents.js: Batch translation workflow (dry-run support)
- audit-section-categories.js: Category distribution analysis

**URL Strategy**: Query parameter approach (?lang=de, ?lang=fr)

**Status**: Backend complete, ready for DeepL API key configuration

**Files Modified**:
- Frontend: document-cards.js, docs-app.js
- Backend: documents.controller.js, documents.routes.js, DeepL.service.js
- Scripts: 3 new governance/i18n scripts

**Database**: 173 sections recategorized via script (already applied)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 00:48:27 +13:00

66 lines
2.7 KiB
JavaScript

#!/usr/bin/env node
const { MongoClient } = require('mongodb');
(async () => {
const client = await MongoClient.connect('mongodb://localhost:27017/tractatus_dev');
const db = client.db();
const docs = await db.collection('documents')
.find({visibility: 'public'}, {projection: {title: 1, slug: 1, sections: 1}})
.sort({order: 1})
.toArray();
console.log('═══════════════════════════════════════════════════════════');
console.log(' SECTION CATEGORY AUDIT - 22 Public Documents');
console.log('═══════════════════════════════════════════════════════════\n');
let totalDocs = 0;
let docsWithSections = 0;
const categoryStats = {};
docs.forEach(doc => {
totalDocs++;
if (!doc.sections || doc.sections.length === 0) {
console.log(`${doc.title}:`);
console.log(' ⚠️ NO SECTIONS (traditional view)\n');
return;
}
docsWithSections++;
const categories = {};
doc.sections.forEach(s => {
const cat = s.category || 'uncategorized';
categories[cat] = (categories[cat] || 0) + 1;
categoryStats[cat] = (categoryStats[cat] || 0) + 1;
});
console.log(`${doc.title}:`);
console.log(` Sections: ${doc.sections.length}`);
Object.entries(categories).sort((a,b) => b[1] - a[1]).forEach(([cat, count]) => {
const percent = Math.round(count / doc.sections.length * 100);
console.log(` - ${cat}: ${count} (${percent}%)`);
});
console.log('');
});
console.log('═══════════════════════════════════════════════════════════');
console.log(' OVERALL STATISTICS');
console.log('═══════════════════════════════════════════════════════════\n');
console.log(`Total documents: ${totalDocs}`);
console.log(`Documents with sections: ${docsWithSections}`);
console.log(`Documents without sections: ${totalDocs - docsWithSections}\n`);
console.log('Category distribution across ALL sections:');
const sortedStats = Object.entries(categoryStats).sort((a,b) => b[1] - a[1]);
const totalSections = sortedStats.reduce((sum, [,count]) => sum + count, 0);
sortedStats.forEach(([cat, count]) => {
const percent = Math.round(count / totalSections * 100);
console.log(` - ${cat}: ${count} sections (${percent}%)`);
});
console.log('\n');
await client.close();
})();