tractatus/public/js/components/umami-tracker.js
TheFlow d32be2c673 feat(api): implement research inquiry endpoint and Umami analytics
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>
2025-10-29 01:31:02 +13:00

132 lines
4 KiB
JavaScript

/**
* Umami Analytics - Privacy-First Tracking
* No cookies, no personal data, GDPR-compliant
*
* Features:
* - Respects Do Not Track (DNT) browser setting
* - Honors user opt-out preference
* - Disabled in development environment
* - Lightweight async loading
*/
(function() {
'use strict';
// Configuration
const CONFIG = {
// NOTE: Replace this with actual website ID from Umami dashboard after setup
websiteId: 'REPLACE_WITH_ACTUAL_WEBSITE_ID',
domain: 'agenticgovernance.digital',
scriptSrc: 'https://analytics.agenticgovernance.digital/script.js',
autoTrack: true
};
// Development environment check
const isDevelopment =
window.location.hostname === 'localhost' ||
window.location.hostname === '127.0.0.1' ||
window.location.hostname === '' ||
window.location.port === '9000'; // Local dev server
if (isDevelopment) {
console.log('[Umami Analytics] Disabled in development environment');
return;
}
// Respect Do Not Track (DNT) browser setting
const dnt = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
const dntEnabled = dnt === '1' || dnt === 'yes' || dnt === 'on';
if (dntEnabled) {
console.log('[Umami Analytics] Tracking disabled - Do Not Track enabled');
return;
}
// Check for user opt-out preference (localStorage)
try {
const optedOut = localStorage.getItem('umami.disabled') === 'true';
if (optedOut) {
console.log('[Umami Analytics] Tracking disabled - User opted out');
return;
}
} catch (e) {
// localStorage may not be available (privacy mode, etc.)
console.warn('[Umami Analytics] Cannot check opt-out preference:', e);
}
// Website ID validation
if (CONFIG.websiteId === 'REPLACE_WITH_ACTUAL_WEBSITE_ID') {
console.warn('[Umami Analytics] Website ID not configured. Update umami-tracker.js after Umami setup.');
return;
}
// Load Umami tracking script
const script = document.createElement('script');
script.async = true;
script.defer = true;
script.src = CONFIG.scriptSrc;
script.setAttribute('data-website-id', CONFIG.websiteId);
script.setAttribute('data-domains', CONFIG.domain);
script.setAttribute('data-auto-track', CONFIG.autoTrack.toString());
// Error handling
script.onerror = function() {
console.error('[Umami Analytics] Failed to load tracking script from:', CONFIG.scriptSrc);
};
// Success callback
script.onload = function() {
console.log('[Umami Analytics] Tracking initialized (privacy-first, cookie-free)');
};
// Append script to head
document.head.appendChild(script);
// Expose opt-out function for privacy page
window.umamiOptOut = function() {
try {
localStorage.setItem('umami.disabled', 'true');
console.log('[Umami Analytics] User opted out successfully');
alert('Analytics tracking has been disabled. Reload the page to apply changes.');
return true;
} catch (e) {
console.error('[Umami Analytics] Failed to save opt-out preference:', e);
alert('Failed to save opt-out preference. Please ensure cookies/localStorage is enabled.');
return false;
}
};
// Expose opt-in function (to reverse opt-out)
window.umamiOptIn = function() {
try {
localStorage.removeItem('umami.disabled');
console.log('[Umami Analytics] User opted in successfully');
alert('Analytics tracking has been enabled. Reload the page to apply changes.');
return true;
} catch (e) {
console.error('[Umami Analytics] Failed to save opt-in preference:', e);
return false;
}
};
// Expose status check function
window.umamiStatus = function() {
const status = {
enabled: true,
development: isDevelopment,
dnt: dntEnabled,
optedOut: false,
websiteId: CONFIG.websiteId
};
try {
status.optedOut = localStorage.getItem('umami.disabled') === 'true';
} catch (e) {
status.optedOut = null;
}
console.table(status);
return status;
};
})();