Initial v2 commit: complete rebuild with unified API + React admin

Phase 1-14 complete:
- Unified Express.js API (TypeScript, Prisma ORM, PostgreSQL 16)
- React Admin GUI (Vite + Ant Design + Zustand)
- JWT auth with refresh tokens
- Influence: Campaigns, Representatives, Responses, Email Queue
- Map: Locations, Cuts, Shifts, Canvassing System
- NAR data import infrastructure (2025 format)
- Listmonk newsletter integration
- Landing page builder (GrapesJS)
- MkDocs + Code Server integration
- Volunteer portal with GPS tracking
- Monitoring stack (Prometheus, Grafana, Alertmanager)
- Pangolin tunnel integration

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 10:05:04 -07:00
commit a77306fac2
590 changed files with 159852 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your Login Details</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f9f9f9;
border-radius: 8px;
padding: 30px;
border: 1px solid #e0e0e0;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
color: #a02c8d;
font-size: 24px;
font-weight: bold;
}
.content {
background-color: white;
padding: 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.credentials-box {
background-color: #f0f0f0;
padding: 15px;
border-radius: 4px;
margin: 20px 0;
border: 1px solid #ddd;
}
.credential-item {
margin: 10px 0;
}
.credential-label {
font-weight: bold;
display: inline-block;
width: 100px;
}
.credential-value {
font-family: monospace;
font-size: 16px;
color: #2c3e50;
}
.login-button {
display: inline-block;
background-color: #a02c8d;
color: white;
padding: 12px 24px;
text-decoration: none;
border-radius: 4px;
margin: 20px 0;
}
.footer {
text-align: center;
font-size: 12px;
color: #666;
margin-top: 30px;
}
.info {
color: #3498db;
font-size: 14px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">{{APP_NAME}}</div>
</div>
<div class="content">
<h2>Your Login Details</h2>
<p>Hello {{USER_NAME}},</p>
<p>Here are your login credentials for {{APP_NAME}}:</p>
<div class="credentials-box">
<div class="credential-item">
<span class="credential-label">Email:</span>
<span class="credential-value">{{USER_EMAIL}}</span>
</div>
<div class="credential-item">
<span class="credential-label">Password:</span>
<span class="credential-value">{{PASSWORD}}</span>
</div>
<div class="credential-item">
<span class="credential-label">Role:</span>
<span class="credential-value">{{USER_ROLE}}</span>
</div>
</div>
<p>You can log in using the link below:</p>
<p style="text-align: center;">
<a href="{{LOGIN_URL}}" class="login-button">Login to {{APP_NAME}}</a>
</p>
<p class="info">💡 For security reasons, we recommend changing your password after your first login.</p>
</div>
<div class="footer">
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
<p>If you have any questions, please contact your administrator.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,17 @@
Login Details - {{APP_NAME}}
Hello {{USER_NAME}},
Here are your login credentials for {{APP_NAME}}:
Email: {{USER_EMAIL}}
Password: {{PASSWORD}}
Role: {{USER_ROLE}}
You can log in at: {{LOGIN_URL}}
For security reasons, we recommend changing your password after your first login.
---
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
If you have any questions, please contact your administrator.

View File

@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your Password</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f9f9f9;
border-radius: 8px;
padding: 30px;
border: 1px solid #e0e0e0;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
color: #a02c8d;
font-size: 24px;
font-weight: bold;
}
.content {
background-color: white;
padding: 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.password-box {
background-color: #f0f0f0;
padding: 15px;
border-radius: 4px;
font-family: monospace;
font-size: 18px;
text-align: center;
margin: 20px 0;
border: 1px solid #ddd;
}
.footer {
text-align: center;
font-size: 12px;
color: #666;
margin-top: 30px;
}
.warning {
color: #e74c3c;
font-size: 14px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">{{APP_NAME}}</div>
</div>
<div class="content">
<h2>Password Recovery</h2>
<p>Hello {{USER_NAME}},</p>
<p>You requested your password for the account associated with <strong>{{USER_EMAIL}}</strong>.</p>
<p>Your password is:</p>
<div class="password-box">{{PASSWORD}}</div>
<p>You can use this password to log in at: <a href="{{LOGIN_URL}}">{{LOGIN_URL}}</a></p>
<p class="warning">⚠️ For security reasons, we recommend changing your password after logging in.</p>
</div>
<div class="footer">
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
<p>If you didn't request this password, please contact your administrator immediately.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,15 @@
Password Recovery - {{APP_NAME}}
Hello {{USER_NAME}},
You requested your password for the account associated with {{USER_EMAIL}}.
Your password is: {{PASSWORD}}
You can use this password to log in at: {{LOGIN_URL}}
WARNING: For security reasons, we recommend changing your password after logging in.
---
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
If you didn't request this password, please contact your administrator immediately.

View File

@@ -0,0 +1,182 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shift Signup Confirmation</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #f8f9fa;
}
.container {
background: white;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
border-bottom: 3px solid #28a745;
padding-bottom: 20px;
margin-bottom: 30px;
}
.header h1 {
color: #28a745;
margin: 0;
font-size: 28px;
}
.welcome-message {
background: #d4edda;
padding: 20px;
border-radius: 6px;
border-left: 4px solid #28a745;
margin: 20px 0;
}
.shift-details {
background: #f8f9fa;
padding: 20px;
border-radius: 6px;
margin: 20px 0;
}
.shift-details h2 {
color: #28a745;
margin-top: 0;
margin-bottom: 15px;
font-size: 22px;
}
.detail-row {
display: flex;
margin: 8px 0;
align-items: center;
}
.detail-label {
font-weight: bold;
min-width: 100px;
color: #666;
}
.actions {
text-align: center;
margin: 30px 0;
}
.button {
display: inline-block;
background: #28a745;
color: white;
padding: 12px 30px;
text-decoration: none;
border-radius: 5px;
font-weight: bold;
margin: 10px;
}
.button:hover {
background: #218838;
}
.secondary-link {
color: #28a745;
text-decoration: none;
}
.secondary-link:hover {
text-decoration: underline;
}
.footer {
text-align: center;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #dee2e6;
color: #666;
font-size: 14px;
}
.important {
background: #d1ecf1;
border: 1px solid #bee5eb;
border-radius: 4px;
padding: 15px;
margin: 20px 0;
color: #0c5460;
}
.important strong {
color: #0c5460;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>✅ Shift Signup Confirmed!</h1>
</div>
<div class="welcome-message">
<p><strong>Hi {{USER_NAME}},</strong></p>
<p>Great news! You've been successfully signed up for another volunteer shift with {{APP_NAME}}.</p>
</div>
<div class="shift-details">
<h2>📅 {{SHIFT_TITLE}}</h2>
<div class="detail-row">
<span class="detail-label">📅 Date:</span>
<span>{{SHIFT_DATE}}</span>
</div>
<div class="detail-row">
<span class="detail-label">⏰ Time:</span>
<span>{{SHIFT_TIME}}</span>
</div>
<div class="detail-row">
<span class="detail-label">📍 Location:</span>
<span>{{SHIFT_LOCATION}}</span>
</div>
{{#if SHIFT_DESCRIPTION}}
<div style="margin-top: 15px;">
<strong>Details:</strong><br>
{{SHIFT_DESCRIPTION}}
</div>
{{/if}}
</div>
<div class="important">
<strong>What's Next?</strong>
<ul style="margin: 10px 0; padding-left: 20px;">
<li>Mark your calendar for {{SHIFT_DATE}} at {{SHIFT_TIME}}</li>
<li>Login to your existing account using your current credentials</li>
<li>You can view or cancel your signup anytime from your account</li>
<li>We'll send you reminder details closer to the shift date</li>
</ul>
</div>
<div class="actions">
<a href="{{LOGIN_URL}}" class="button">🔐 Login to Your Account</a>
<br>
<p style="margin-top: 15px;">
Once logged in, visit <a href="{{SHIFTS_URL}}" class="secondary-link">My Shifts</a> to manage all your volunteer signups.
</p>
</div>
<div class="footer">
<p>Thank you for continuing to volunteer with {{APP_NAME}}!</p>
<p>Questions? Reply to this email and we'll help you out.</p>
<p><small>Sent on {{TIMESTAMP}}</small></p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,29 @@
Hi {{USER_NAME}},
✅ SHIFT SIGNUP CONFIRMED!
Great news! You've been successfully signed up for another volunteer shift with {{APP_NAME}}.
📅 SHIFT DETAILS
▸ Event: {{SHIFT_TITLE}}
▸ Date: {{SHIFT_DATE}}
▸ Time: {{SHIFT_TIME}}
▸ Location: {{SHIFT_LOCATION}}
{{#if SHIFT_DESCRIPTION}}
▸ Details: {{SHIFT_DESCRIPTION}}
{{/if}}
You can use your existing account credentials to:
• Login at: {{LOGIN_URL}}
• View all your shift signups at: {{SHIFTS_URL}}
• Cancel or modify your signups anytime from your account
Need help? Reply to this email or contact our volunteer coordinator.
Thank you for your continued support!
---
{{APP_NAME}} Volunteer Team
Sent: {{TIMESTAMP}}
This is an automated message. Please do not reply directly to this email.

View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<style>
/* ...email styles... */
</style>
</head>
<body>
<div class="container">
<h1>Welcome & Shift Confirmation</h1>
<p>Hi {{USER_NAME}},</p>
<p>Thank you for signing up to volunteer! Your account has been created and you're confirmed for:</p>
<div class="shift-details">
<h2>{{SHIFT_TITLE}}</h2>
<p><strong>Date:</strong> {{SHIFT_DATE}}</p>
<p><strong>Time:</strong> {{SHIFT_TIME}}</p>
<p><strong>Location:</strong> {{SHIFT_LOCATION}}</p>
</div>
<div class="credentials">
<h3>Your Login Details</h3>
<p><strong>Email:</strong> {{USER_EMAIL}}</p>
<p><strong>Temporary Password:</strong> <code>{{TEMP_PASSWORD}}</code></p>
<p class="note">This is a temporary account that expires after your shift.</p>
</div>
<div class="actions">
<a href="{{LOGIN_URL}}" class="button">Login to Your Account</a>
<p>Once logged in, visit <a href="{{SHIFTS_URL}}">My Shifts</a> to view or cancel your signup.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,33 @@
Hi {{USER_NAME}},
✅ SHIFT SIGNUP CONFIRMATION
Thank you for signing up to volunteer with {{APP_NAME}}! Your account has been created and you're confirmed for:
📅 SHIFT DETAILS
▸ Event: {{SHIFT_TITLE}}
▸ Date: {{SHIFT_DATE}}
▸ Time: {{SHIFT_TIME}}
▸ Location: {{SHIFT_LOCATION}}
{{#if SHIFT_DESCRIPTION}}
▸ Details: {{SHIFT_DESCRIPTION}}
{{/if}}
🔑 YOUR LOGIN CREDENTIALS
▸ Email: {{USER_EMAIL}}
▸ Temporary Password: {{TEMP_PASSWORD}}
This is a temporary account that expires after your shift. Keep these credentials safe!
WHAT'S NEXT:
• Mark your calendar for {{SHIFT_DATE}} at {{SHIFT_TIME}}
• Login at: {{LOGIN_URL}}
• Manage your signups at: {{SHIFTS_URL}}
• We'll send reminder details closer to the shift date
Questions? Reply to this email and we'll help you out.
Thank you for volunteering with {{APP_NAME}}!
---
Sent on {{TIMESTAMP}}

View File

@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Shift Details - {{SHIFT_TITLE}}</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f9f9f9;
border-radius: 8px;
padding: 30px;
border: 1px solid #e0e0e0;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
color: #a02c8d;
font-size: 24px;
font-weight: bold;
}
.content {
background-color: white;
padding: 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.shift-details-box {
background-color: #f8f9fa;
padding: 20px;
border-radius: 4px;
margin: 20px 0;
border: 1px solid #ddd;
}
.detail-row {
margin: 12px 0;
display: flex;
align-items: flex-start;
}
.detail-icon {
width: 30px;
font-size: 16px;
margin-right: 10px;
text-align: center;
}
.detail-label {
font-weight: bold;
min-width: 80px;
margin-right: 10px;
}
.detail-value {
color: #2c3e50;
flex: 1;
}
.description-section {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.footer {
text-align: center;
font-size: 12px;
color: #666;
margin-top: 30px;
}
.highlight {
background-color: #fff3cd;
padding: 15px;
border-left: 4px solid #ffc107;
margin: 15px 0;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
}
.status-open {
background-color: #d4edda;
color: #155724;
}
.status-full {
background-color: #fff3cd;
color: #856404;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">{{APP_NAME}}</div>
</div>
<div class="content">
<h2>Shift Details: {{SHIFT_TITLE}}</h2>
<p>Hello {{USER_NAME}},</p>
<p>Here are the details for your upcoming volunteer shift:</p>
<div class="shift-details-box">
<div class="detail-row">
<span class="detail-icon">📅</span>
<span class="detail-label">Date:</span>
<span class="detail-value">{{SHIFT_DATE}}</span>
</div>
<div class="detail-row">
<span class="detail-icon"></span>
<span class="detail-label">Time:</span>
<span class="detail-value">{{SHIFT_START_TIME}} - {{SHIFT_END_TIME}}</span>
</div>
<div class="detail-row">
<span class="detail-icon">📍</span>
<span class="detail-label">Location:</span>
<span class="detail-value">{{SHIFT_LOCATION}}</span>
</div>
<div class="detail-row">
<span class="detail-icon">👥</span>
<span class="detail-label">Volunteers:</span>
<span class="detail-value">{{CURRENT_VOLUNTEERS}}/{{MAX_VOLUNTEERS}} signed up</span>
</div>
<div class="detail-row">
<span class="detail-icon">📊</span>
<span class="detail-label">Status:</span>
<span class="detail-value">
<span class="status-badge status-{{SHIFT_STATUS_CLASS}}">{{SHIFT_STATUS}}</span>
</span>
</div>
</div>
<div class="description-section" id="description-section"{{DESCRIPTION_DISPLAY_STYLE}}>
<h3>Additional Information:</h3>
<p>{{SHIFT_DESCRIPTION}}</p>
</div>
<div class="highlight">
<p><strong>Important:</strong> Please arrive 10-15 minutes early and wear weather appropriate wear. If you need to cancel, please do so as early as possible to allow other volunteers to sign up.</p>
</div>
<p>Questions? Contact your shift coordinator or administrator.</p>
<p>Thank you for volunteering!</p>
</div>
<div class="footer">
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
<p>Volunteer shift management system</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,30 @@
Shift Details - {{SHIFT_TITLE}}
Hello {{USER_NAME}},
Here are the details for your upcoming volunteer shift:
SHIFT INFORMATION:
==================
Title: {{SHIFT_TITLE}}
Date: {{SHIFT_DATE}}
Time: {{SHIFT_START_TIME}} - {{SHIFT_END_TIME}}
Location: {{SHIFT_LOCATION}}
Volunteers: {{CURRENT_VOLUNTEERS}}/{{MAX_VOLUNTEERS}} signed up
Status: {{SHIFT_STATUS}}
{{SHIFT_DESCRIPTION_SECTION}}
IMPORTANT NOTES:
===============
- Please arrive 10-15 minutes early
- Bring photo ID
- If you need to cancel, please do so as early as possible to allow other volunteers to sign up
Questions? Contact your shift coordinator or administrator.
Thank you for volunteering!
---
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
Volunteer shift management system

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{EMAIL_SUBJECT}}</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: #f9f9f9;
border-radius: 8px;
padding: 30px;
border: 1px solid #e0e0e0;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
color: #a02c8d;
font-size: 24px;
font-weight: bold;
}
.content {
background-color: white;
padding: 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.message-content {
line-height: 1.6;
}
.message-content h1,
.message-content h2,
.message-content h3 {
color: #2c3e50;
margin-top: 25px;
margin-bottom: 15px;
}
.message-content h1 {
font-size: 24px;
border-bottom: 2px solid #e9ecef;
padding-bottom: 10px;
}
.message-content h2 {
font-size: 20px;
}
.message-content h3 {
font-size: 18px;
}
.message-content ul,
.message-content ol {
margin: 15px 0;
padding-left: 25px;
}
.message-content li {
margin: 8px 0;
}
.message-content a {
color: #a02c8d;
text-decoration: none;
}
.message-content a:hover {
text-decoration: underline;
}
.message-content strong {
font-weight: 600;
color: #2c3e50;
}
.message-content blockquote {
border-left: 4px solid #a02c8d;
margin: 20px 0;
padding: 10px 20px;
background-color: #f8f9fa;
font-style: italic;
}
.footer {
text-align: center;
font-size: 12px;
color: #666;
margin-top: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">{{APP_NAME}}</div>
</div>
<div class="content">
<p>Hello {{USER_NAME}},</p>
<div class="message-content">
{{EMAIL_CONTENT}}
</div>
</div>
<div class="footer">
<p>This email was sent from {{APP_NAME}} at {{TIMESTAMP}}</p>
<p>{{SENDER_NAME}} - System Administrator</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,9 @@
{{EMAIL_SUBJECT}}
Hello {{USER_NAME}},
{{EMAIL_CONTENT_TEXT}}
---
This email was sent from {{APP_NAME}} at {{TIMESTAMP}}
{{SENDER_NAME}} - System Administrator