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>
93 lines
2.5 KiB
Python
Executable file
93 lines
2.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
Add Umami tracking script to all public HTML files
|
|
Excludes admin and koha directories
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
# Tracking script to insert
|
|
TRACKING_SCRIPT = '''
|
|
<!-- Privacy-Preserving Analytics (Umami - GDPR Compliant, No Cookies) -->
|
|
<script src="/js/components/umami-tracker.js"></script>
|
|
'''
|
|
|
|
def add_tracking_to_file(filepath):
|
|
"""Add tracking script before </head> tag if not already present"""
|
|
try:
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
# Check if tracking already exists
|
|
if 'umami-tracker.js' in content:
|
|
return None, 'Already has tracking'
|
|
|
|
# Check if </head> exists
|
|
if '</head>' not in content:
|
|
return None, 'No </head> tag found'
|
|
|
|
# Insert tracking script before </head>
|
|
updated_content = content.replace('</head>', TRACKING_SCRIPT + '</head>', 1)
|
|
|
|
# Write back to file
|
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
f.write(updated_content)
|
|
|
|
return True, 'Tracking added'
|
|
|
|
except Exception as e:
|
|
return False, f'Error: {str(e)}'
|
|
|
|
def main():
|
|
# Base directory
|
|
public_dir = Path('public')
|
|
|
|
# Find all HTML files
|
|
html_files = []
|
|
for root, dirs, files in os.walk(public_dir):
|
|
# Skip admin and koha directories
|
|
if 'admin' in root or 'koha' in root:
|
|
continue
|
|
|
|
for file in files:
|
|
if file.endswith('.html'):
|
|
html_files.append(Path(root) / file)
|
|
|
|
html_files.sort()
|
|
|
|
print("=" * 60)
|
|
print(" Adding Umami Tracking to Public Pages")
|
|
print("=" * 60)
|
|
print()
|
|
|
|
stats = {'added': 0, 'skipped': 0, 'errors': 0}
|
|
|
|
for filepath in html_files:
|
|
success, message = add_tracking_to_file(filepath)
|
|
|
|
if success is True:
|
|
print(f"✓ {filepath}: {message}")
|
|
stats['added'] += 1
|
|
elif success is None:
|
|
print(f"⊘ {filepath}: {message}")
|
|
stats['skipped'] += 1
|
|
else:
|
|
print(f"✗ {filepath}: {message}")
|
|
stats['errors'] += 1
|
|
|
|
print()
|
|
print("=" * 60)
|
|
print(" Summary")
|
|
print("=" * 60)
|
|
print(f"Files updated: {stats['added']}")
|
|
print(f"Files skipped: {stats['skipped']}")
|
|
print(f"Errors: {stats['errors']}")
|
|
print()
|
|
print("NOTE: Update website ID in public/js/components/umami-tracker.js")
|
|
print(" after completing Umami setup")
|
|
print("=" * 60)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|