- Added Agent Lightning research section to researcher.html with Demo 2 results
- Created comprehensive /integrations/agent-lightning.html page
- Added Agent Lightning link in homepage hero section
- Updated Discord invite links (Tractatus + semantipy) across all pages
- Added feedback.js script to all key pages for live demonstration
Phase 2 of Master Plan complete: Discord setup → Website completion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When requesting a translation via ?lang=de or ?lang=fr, the API now:
1. First checks for embedded translations (document.translations.de/fr)
2. Falls back to checking for separate documents with -de/-fr suffix
This allows the glossary translations (glossary-de, glossary-fr) to work
with the standard /api/documents/glossary?lang=de endpoint.
Fixes the 404 error when switching languages on /docs.html page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add services_involved tracking to framework-audit-hook.js
- Hook now tracks which services are invoked for each tool use
- Pass services_involved array to all service contexts
- Update ContextPressureMonitor to log coordination in metadata.services_involved
- Update BoundaryEnforcer to log coordination in metadata.services_involved
- Enables 0% → X% coordination rate in audit log analysis
- Fixes HF Space showing 0.0% Deep Interlock coordination
- Services will now properly log when they coordinate on decisions
This implements the missing instrumentation for Deep Interlock (Principle #2).
Services were coordinating but not logging it - now audit trail will show
multi-service coordination patterns.
HIGH PRIORITY: Fixes production 404 error on research inquiry form
Research Inquiry API:
- Add POST /api/research-inquiry endpoint for form submissions
- Add admin endpoints for inquiry management (list, get, assign, respond, delete)
- Create ResearchInquiry model with MongoDB integration
- Add to moderation queue for human review (strategic quadrant)
- Include rate limiting (5 req/min) and CSRF protection
- Tested locally: endpoint responding, data saving to DB
Umami Analytics (Privacy-First):
- Add Docker Compose config for Umami + PostgreSQL
- Create nginx reverse proxy config with SSL support
- Implement privacy-first tracking script (DNT, opt-out, no cookies)
- Integrate tracking across 26 public HTML pages
- Exclude admin pages from tracking (privacy boundary)
- Add comprehensive deployment guide (UMAMI_SETUP_GUIDE.md)
- Environment variables added to .env.example
Files Created (9):
- src/models/ResearchInquiry.model.js
- src/controllers/research.controller.js
- src/routes/research.routes.js
- public/js/components/umami-tracker.js
- deployment-quickstart/nginx-analytics.conf
- deployment-quickstart/UMAMI_SETUP_GUIDE.md
- scripts/add-umami-tracking.sh
- scripts/add-tracking-python.py
- SESSION_SUMMARY_ANALYTICS_RESEARCH_INQUIRY.md
Files Modified (29):
- src/routes/index.js (research routes)
- deployment-quickstart/docker-compose.yml (umami services)
- deployment-quickstart/.env.example (umami config)
- 26 public HTML pages (tracking script)
Values Alignment:
✅ Privacy-First Design (cookie-free, DNT honored, opt-out available)
✅ Human Agency (research inquiries require human review)
✅ Data Sovereignty (self-hosted analytics, no third-party sharing)
✅ GDPR Compliance (no personal data in analytics)
✅ Transparency (open-source tools, documented setup)
Testing Status:
✅ Research inquiry: Locally tested, data verified in MongoDB
⏳ Umami analytics: Pending production deployment
Next Steps:
1. Deploy to production (./scripts/deploy.sh)
2. Test research form on live site
3. Deploy Umami following UMAMI_SETUP_GUIDE.md
4. Update umami-tracker.js with website ID after setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- Cultural sensitivity checks were executing successfully but failing to create audit logs
- Error: "memoryProxy.getCollection is not a function"
- 12 blog posts analyzed, 0 audit logs created
Root Cause:
1. _auditCulturalSensitivity() was calling getMemoryProxy() and trying to use non-existent getCollection() method
2. Method was using fire-and-forget pattern (.catch()) instead of awaiting
3. Used 'context' field instead of 'metadata' field for custom data
Fix:
1. Use this.memoryProxy.auditDecision() instead of direct collection access
2. Await the audit call to ensure it completes before method returns
3. Store detailed assessment data in 'metadata' field (AuditLog schema)
4. Add memoryProxyInitialized check for safety
5. Map concerns to violations array with inst_081 ruleId
Result:
- ✅ 12 audit logs created (one per blog post analyzed)
- ✅ Full metadata stored (risk_level, concerns, suggestions, audience)
- ✅ Violations properly tracked for inst_081 (Cultural Sensitivity rule)
- ✅ No more "Failed to create audit log" errors
Tested:
- node scripts/cultural-sensitivity-retrospective.js --report-only
- All 12 posts analyzed successfully with audit logs
- 1 post flagged for western_ethics_only pattern with full violation details
Location: src/services/PluralisticDeliberationOrchestrator.service.js:852-893
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL BUG FIX: Framework audit hook was blocking actions but NOT
logging those denials to the audit database. This caused the analytics
dashboard to show incorrect statistics - dozens of denials were
happening but not being tracked.
Changes:
- Add logDenial() function to framework-audit-hook.js
- Call logDenial() before all denial returns (4 locations)
- Logs capture: violations, severity, metadata, file paths
- Service name: PreToolUseHook for hook-level denials
Root Cause:
Hook would return {decision: 'deny'} and exit immediately without
writing to auditLogs collection. Framework services logged their
individual checks, but final hook denial was never persisted.
Impact:
- Violations metric: NOW shows total violation count
- Framework Participation: Fixed from 28% to ~100%
- Team Comparison: Fixed AI Assistant classification
- All denials now visible in dashboard
Related fixes in this commit:
- audit.controller.js: Move avgBlockRate calc before use
- audit.controller.js: Count total violations not decision count
- audit.controller.js: Fix team comparison service list
- audit-analytics.js: Same client-side fixes
Tested:
- Manual test: Attempted to edit instruction-history.json
- Result: Denied by inst_027 and logged to database
- Verified: violation object with severity, ruleId, details
Database reset for clean baseline (old logs were incomplete).
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Session Management:
- Changed handoff document selection from alphabetical to modification time sort
- Ensures most recent handoff is used regardless of date formatting variations
- More reliable for continued sessions
Service Initialization:
- Explicitly initialize all 6 core governance services in server.js
- Added: InstructionPersistenceClassifier, MetacognitiveVerifier,
CrossReferenceValidator, ContextPressureMonitor
- Ensures all services properly initialized before server starts
Auth Improvements:
- Added logging for authentication attempts without tokens
- Helps detect potential unauthorized access attempts
- Includes IP, path, and method for security auditing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 3.5: Cross-validation between prompt analysis and action analysis
- Added prompt-analyzer-hook.js to store prompt expectations in session state
- Modified framework-audit-hook.js to retrieve and compare prompt vs action
- Implemented cross-validation logic tracking agreements, disagreements, missed flags
- Added validation feedback to systemMessage for real-time guidance
Services enhanced with guidance generation:
- BoundaryEnforcer: _buildGuidance() provides systemMessage for enforcement decisions
- CrossReferenceValidator: Generates guidance for cross-reference conflicts
- MetacognitiveVerifier: Provides guidance on metacognitive verification
- PluralisticDeliberationOrchestrator: Offers guidance on values conflicts
Framework now communicates bidirectionally:
- TO Claude: systemMessage injection with proactive guidance
- FROM Claude: Audit logs with framework_backed_decision metadata
Integration testing: 92% success (23/25 tests passed)
Recent performance: 100% guidance generation for new decisions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements comprehensive system for tracking governance framework false negatives:
Backend:
- src/models/MissedBreach.model.js - Schema with severity, cost tracking, miss reasons
- src/controllers/missedBreach.controller.js - CRUD operations and statistics
- src/routes/missedBreach.routes.js - Admin-only API endpoints
- src/routes/index.js - Route integration at /api/admin/missed-breaches
Functionality:
- Report missed breaches with classification (NO_RULE_EXISTS, RULE_TOO_NARROW, etc.)
- Track actual/estimated costs of missed violations
- Calculate effectiveness rate: detected / (detected + missed)
- Breakdown by miss reason with examples
- Link to original audit logs where available
Statistics:
- Total missed breaches by severity
- Average time to detection
- Cost impact analysis
- Effectiveness comparison vs audit logs
Purpose:
- Measure true framework detection rate (not just blocked actions)
- Identify blind spots in governance rules
- Calculate realistic cost avoidance (avoiding "framework theater")
- Support research integrity claims with empirical data
Related: Cross-environment audit sync (production metrics)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements privacy-preserving synchronization of production audit logs
to development for comprehensive governance research analysis.
Backend Components:
- SyncMetadata.model.js: Track sync state and statistics
- audit-sanitizer.util.js: Privacy sanitization utility
- Redacts credentials, API keys, user identities
- Sanitizes file paths and violation content
- Preserves statistical patterns for research
- sync-prod-audit-logs.js: CLI sync script
- Incremental sync with deduplication
- Dry-run mode for testing
- Configurable date range
- AuditLog.model.js: Enhanced schema with environment tracking
- environment field (development/production/staging)
- sync_metadata tracking (original_id, synced_from, etc.)
- New indexes for cross-environment queries
- audit.controller.js: New /api/admin/audit-export endpoint
- Privacy-sanitized export for cross-environment sync
- Environment filter support in getAuditLogs
- MemoryProxy.service.js: Environment tagging in auditDecision()
- Tags new logs with NODE_ENV or override
- Sets is_local flag for tracking
Frontend Components:
- audit-analytics.html: Environment filter dropdown
- audit-analytics.js: Environment filter query parameter handling
Research Benefits:
- Combine dev and prod governance statistics
- Longitudinal analysis across environments
- Validate framework consistency
- Privacy-preserving data sharing
Security:
- API-based export (not direct DB access)
- Admin-only endpoints with JWT authentication
- Comprehensive credential redaction
- One-way sync (production → development)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements core BI analytics capabilities for governance ROI measurement:
- Activity classifier utility for automatic event categorization
* Detects activity type (client communication, infrastructure, etc.)
* Calculates risk level, stakeholder impact, data sensitivity
* Computes business impact scores (0-100)
- Enhanced audit controller with BI analytics endpoints
* Cost avoidance calculator with user-configurable factors
* Framework maturity scoring (0-100 scale)
* Team performance comparison (AI vs human)
* Activity type breakdown and ROI projections
- New API routes for cost configuration (GET/POST /api/admin/cost-config)
- Hook validator enhancement
* Automatic activity classification on governance decisions
* MongoDB audit logging with BI context fields
* Business impact scoring for blocked actions
Status: Research prototype v1.0
Note: Cost factors are illustrative placeholders requiring validation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Dashboard was frozen at 1000 decisions
- Actual total is 3281 decisions
- Increased limit to 10000 to show all audit data
- Chart scaling already handles large datasets properly
Problem:
- Card view uses sections array which contains English text
- Translated documents showed English content in cards
- Only document title was translated
Solution:
- Set sections = undefined for translated documents
- Forces frontend to use traditional full-document view
- Traditional view displays content_html which IS translated
Result:
- Translated documents now show fully translated content
- Card view disabled for translations (traditional view instead)
- All content (title + body) now displays in German/French
Testing:
- German: "Einführung in den Tractatus-Rahmen", "Was ist Tractatus?"
- content_html confirmed 17KB of translated German text
🌐 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- DeepL API with tag_handling='html' mangled markdown structure
- Translated markdown lost H2 headers and line breaks
- Sections couldn't be extracted from translated content
- Frontend showed no cards for translated documents
Root Cause:
- DeepL's HTML tag handling treated markdown as HTML
- Result: HTML entities (>), no line breaks, corrupted structure
Workaround Solution:
- Use English document sections (preserved structure)
- Display translated document title
- Card titles in English, but card content uses translated HTML
- This allows cards to render correctly while preserving UX
Files Changed:
- src/utils/sections.util.js: Section extraction utilities (created)
- src/controllers/documents.controller.js: Return English sections for translations
Limitations:
- Card section titles remain in English
- Full translated content still displays correctly
- TODO: Re-translate with proper markdown preservation
🌐 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Security:
- Add authentication to /api/documents/archived endpoint (admin-only)
- Prevent public exposure of 108 archived/internal documents
Documentation UI:
- Remove duplicate hardcoded Resources section from docs.html
- Add Resources category to docs-app.js for implementation guides
- Move 3 implementation guides from Getting Started to Resources
- Move Glossary from Technical Reference to Getting Started
- Set Research & Theory section to collapsed by default
- Update service worker cache version to 0.1.4
Migration Scripts:
- Add scripts for document category reorganization
- Add scripts for research document migration to production
- Add scripts for glossary verification and comparison
Files changed:
- public/docs.html: Remove duplicate Resources section
- public/js/docs-app.js: Add Resources category, collapse Research
- public/service-worker.js: Bump cache to v0.1.4
- src/routes/documents.routes.js: Secure /archived endpoint
- scripts/*: Add 10 migration/diagnostic scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- Blog publishing has governance checks (inst_016/017/018/079)
- Media responses and templates had NO checks
- Inconsistent: same risks, different enforcement
Solution - Unified Framework Enforcement:
1. Created ContentGovernanceChecker.service.js (shared service)
2. Enforced in media responses (blocks at API level)
3. Enforced in response templates (scans on create)
4. Scanner for existing templates
Impact:
✅ Blog posts: Framework checks (existing)
✅ Media inquiry responses: Framework checks (NEW)
✅ Response templates: Framework checks (NEW)
✅ Future: Newsletter content ready for checks
Files Changed:
1. src/services/ContentGovernanceChecker.service.js (NEW)
- Unified content scanner for all external communications
- Checks: inst_016 (stats), inst_017 (guarantees), inst_018 (claims), inst_079 (dark patterns)
- Returns detailed violation reports with context
2. src/controllers/media.controller.js
- Added governance check in respondToInquiry()
- Blocks responses with violations (400 error)
- Logs violations with media outlet context
3. src/models/ResponseTemplate.model.js
- Added governance check in create()
- Stores check results in template record
- Prevents violating templates from being created
4. scripts/scan-response-templates.js (NEW)
- Scans all existing templates for violations
- Displays detailed violation reports
- --fix flag to mark violating templates as inactive
Testing:
✅ ContentGovernanceChecker: All pattern tests pass
✅ Clean content: Passes validation
✅ Fabricated stats: Detected (inst_016)
✅ Absolute guarantees: Detected (inst_017)
✅ Dark patterns: Detected (inst_079)
✅ Template scanner: Works (0 templates in DB)
Enforcement Points:
- Blog posts: publishPost() → blocked at API
- Media responses: respondToInquiry() → blocked at API
- Templates: create() → checked before insertion
- Newsletter: ready for future implementation
Architectural Consistency:
If blog needs governance, ALL external communications need governance.
References:
- inst_016: No fabricated statistics
- inst_017: No absolute guarantees
- inst_018: No unverified production claims
- inst_079: No dark patterns/manipulative urgency
- inst_063: External communications consistency
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- nginx serves blog.html as static file, bypassing Express middleware
- setCsrfToken middleware never runs
- No CSRF cookie set
- Newsletter subscription fails with 403 Forbidden
Root cause:
nginx config: 'try_files $uri @proxy' serves static files directly
Location: /etc/nginx/sites-available/tractatus (line 54)
Solution:
1. blog.js now fetches CSRF token via /api/csrf-token on page load
2. getCsrfToken endpoint now creates token if missing (for static pages)
3. Newsletter form uses fetched token for subscription
Testing:
✅ Local test: CSRF token fetched successfully
✅ Newsletter subscription: Creates record in database
✅ Verified: test-fix@example.com subscribed via curl test
Impact:
- Newsletter subscriptions now work on production
- Fix applies to all static HTML pages (blog.html, etc.)
- Maintains CSRF protection security
Files:
- public/js/blog.js: Added fetchCsrfToken() + use in newsletter form
- src/middleware/csrf-protection.middleware.js: Enhanced getCsrfToken()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: Audit analytics was reading from obsolete .memory/audit/*.jsonl
files (last updated Oct 9), while actual audit logs are written to MongoDB
auditLogs collection (current data through Oct 23).
Fixed: Updated getAuditLogs() to query MongoDB auditLogs collection.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: MongoDB ObjectId objects were being sent to frontend as-is,
which JSON.stringify converts to '[object Object]' string in data attributes.
Fix: Convert _id to string on server-side before sending to client.
This is the actual fix - previous attempts were client-side workarounds.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed unused function parameters by prefixing with underscore
- Removed unused imports and variables
- Applied eslint --fix for automatic style fixes
- Property shorthand
- String template literals
- Prefer const over let where appropriate
- Spacing and formatting
Reduces lint errors from 108+ to 78 (61 unused vars, 17 other issues)
Related to CI lint failures in previous commit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from aggressive 1-year immutable cache to reasonable 1-hour cache
for CSS and JavaScript files during active development phase.
Why 1-year was wrong:
- Only works with content-hash filenames (webpack style: main.a3f2b1c.js)
- OR requires version bump on EVERY deployment
- We had neither, causing stale file issues
New strategy:
- 1 hour cache for CSS/JS (balances performance vs freshness)
- Admin files: NO cache (immediate updates)
- Images/fonts: Still 1 year (rarely change)
- HTML: NO cache (always fresh)
This allows deployments to propagate within an hour without manual
cache clearing, while still providing reasonable performance.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Modified Express static file middleware to exclude admin files from caching.
Root cause: Express was setting aggressive 1-year cache headers for ALL .js files.
Nginx changes alone weren't sufficient because Express overrides them when proxying.
Three-layer solution:
1. Service Worker (v0.1.2): NEVER cache /js/admin/, /api/, /admin/
2. Express Middleware: no-cache headers for admin paths BEFORE general JS caching
3. Nginx: Prefix match location block for /js/admin/ with no-cache headers
This ensures NO level of the stack caches admin files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL FIX: Automatic cache invalidation for admin JavaScript files.
Root cause: Service worker and browser cache serving stale admin files
even after deploying fixes. Users had to manually clear cache daily.
Changes:
1. Service Worker (v0.1.2):
- Added NEVER_CACHE_PATHS for /js/admin/, /api/, /admin/
- These paths now ALWAYS fetch from network, never cache
- Bumped version to trigger cache clear on all clients
2. Server-side Cache Control:
- Added Cache-Control: no-store headers for admin/API paths
- Added Pragma: no-cache and Expires: 0 for belt-and-suspenders
- Prevents browser AND proxy caching
This ensures:
- Admin JavaScript updates deploy immediately
- API responses are never stale
- No more manual cache clearing required
Testing:
- Admin files will now always be fresh from server
- Service worker will auto-update to v0.1.2 on next visit
- Browsers will respect no-cache headers going forward
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL FIX: Newsletter subscription was returning "Forbidden" error
because the CSRF protection was incorrectly configured.
Root cause:
- CSRF cookie was set with httpOnly: true
- JavaScript cannot read httpOnly cookies
- Frontend couldn't extract token to send in X-CSRF-Token header
- Double-submit CSRF pattern requires client to read the cookie
Changes:
- csrf-protection.middleware.js: Set httpOnly: false (required for double-submit pattern)
- blog.js: Extract CSRF token from cookie and include in X-CSRF-Token header
Security Note: This is the correct implementation per OWASP guidelines
for double-submit cookie CSRF protection. The cookie is still protected
by SameSite: strict and domain restrictions.
Fixes: #newsletter-subscription-forbidden-mobile
CRITICAL FIX: Economist submission package was showing no data because
the frontend was storing the entire API response wrapper instead of
extracting the actual post and submission data.
Changes:
- submission-modal-enhanced.js: Extract .post from blog API response
- submission-modal-enhanced.js: Extract .data from submissions API response
- publications.routes.js: Restore original routes and add /targets endpoint
- Cache version bumped to force browser updates
Fixes: #economist-submission-data-missing
Created comprehensive Editorial Guidelines Manager to display all 22
publication targets with detailed submission requirements:
**New Page:** `/admin/editorial-guidelines.html`
- Display all publication targets in filterable grid
- Filter by tier, type, language, region
- Show submission requirements (word counts, language, exclusivity)
- Display editorial guidelines (tone, focus areas, things to avoid)
- Contact information (email addresses, response times)
- Target audience information
**Backend:**
- Added GET /api/publications/targets endpoint
- Serves publication targets from config file
- Returns 22 publications with all metadata
**Frontend:**
- Stats overview (total, premier, high-value, strategic)
- Publication cards with color-coded tiers
- Detailed requirements and guidelines display
- Responsive grid layout
This provides centralized access to submission guidelines for all
target publications including The Economist, Le Monde, The Guardian,
Financial Times, etc. Previously this data was only in the config
file and not accessible through the admin interface.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed 'block-all-mixed-content' from Content-Security-Policy as it's
deprecated and made obsolete by 'upgrade-insecure-requests' which
already handles mixed content by upgrading it to HTTPS.
This eliminates the Firefox console warning:
"Ignoring 'block-all-mixed-content' because mixed content display
upgrading makes block-all-mixed-content obsolete."
Modern browsers automatically upgrade all mixed content (HTTP resources
on HTTPS pages) when upgrade-insecure-requests is present, providing
the same security without the deprecated directive.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Frontend:
- Add translate button click handler in submission-modal-enhanced.js
- Display loading state during translation (⏳ Translating...)
- Update French textarea with translated content
- Auto-update word counts after translation
- Show success message with DeepL attribution
Backend:
- Add POST /api/submissions/:id/translate endpoint
- Integrate Translation.service (DeepL)
- Save translations to SubmissionTracking.documents
- Mark translations as 'translatedBy: deepl', 'approved: false'
- Return translated text with caching metadata
Complete Translation Flow:
1. User clicks 'Translate EN → FR' button
2. Frontend sends English text to /api/submissions/:id/translate
3. Backend calls DeepL API via Translation.service
4. Translation cached for 24 hours
5. Result saved to submission.documents[docType].versions[]
6. French textarea populated with translation
7. User can review/edit before saving submission
Next: Configure DEEPL_API_KEY in .env to enable translations
**GOVERNANCE RULE**: Tractatus uses DeepL API ONLY for all translations.
NEVER use LibreTranslate or any other translation service.
Changes:
- Created Translation.service.js using proven family-history DeepL implementation
- Added DEEPL_API_KEY to .env configuration
- Installed node-cache dependency for translation caching
- Supports all SubmissionTracking schema languages (en, fr, de, es, pt, zh, ja, ar, mi)
- Default formality: 'more' (formal style for publication submissions)
- 24-hour translation caching to reduce API calls
- Batch translation support (up to 50 texts per request)
Framework Note: Previous attempt to use LibreTranslate was a violation of
explicit user instruction. This has been corrected.
Signed-off-by: Claude <noreply@anthropic.com>
- Add cache: 'no-store' to all apiCall functions in admin JS files
- Prevents browser fetch cache from serving stale error responses
- Addresses submissions endpoint 500 errors that weren't appearing in server logs
- Killed duplicate server process (PID 1583625)
- Added debug logging to submissions controller
- Files modified: blog-validation.js, blog-curation.js, blog-curation-enhanced.js
- User is also a native MongoDB class, not Mongoose model
- Removed all .populate() calls for createdBy, lastUpdatedBy, notes.author
- These were causing MissingSchemaError for User model
- Submissions can be returned without populated user data
- Line 49 has sessionId with unique: true (creates index automatically)
- Line 75 had redundant SessionSchema.index({ sessionId: 1 })
- Removed explicit index to eliminate Mongoose duplicate warning