wip
This commit is contained in:
@@ -0,0 +1,511 @@
|
||||
'use client';
|
||||
|
||||
import { Clock, Mail, Bell, Calendar, Info, Timer, Repeat } from 'lucide-react';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
|
||||
export default function AutomationReferencePage() {
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">Automation Reference</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Quick reference for all automated emails, notifications, and scheduled jobs
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Scheduled Jobs */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Clock className="h-5 w-5" />
|
||||
Scheduled Jobs (Cron)
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Background jobs that run on a schedule. All times are in UTC.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Job</TableHead>
|
||||
<TableHead>Schedule</TableHead>
|
||||
<TableHead>Default Hour</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Task Reminders (Due Soon)</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="font-mono">0 20 * * *</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">Daily 8 PM UTC</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span className="font-mono">20:00</span> (8 PM)
|
||||
</TableCell>
|
||||
<TableCell className="max-w-md">
|
||||
<p className="text-sm">
|
||||
Sends frequency-aware "due soon" task reminders. Reminder schedule varies by task frequency
|
||||
(weekly: day-of only, monthly: 7 days + day-of, annual: 30/14/7 days + day-of).
|
||||
</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Overdue Reminders</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="font-mono">0 9 * * *</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">Daily 9 AM UTC</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span className="font-mono">09:00</span> (9 AM)
|
||||
</TableCell>
|
||||
<TableCell className="max-w-md">
|
||||
<p className="text-sm">
|
||||
Sends overdue task reminders with tapering: daily for days 1-3, every 3 days for days 4-14,
|
||||
then stops to avoid notification fatigue.
|
||||
</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Daily Digest</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="font-mono">0 11 * * *</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">Daily 11 AM UTC</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span className="font-mono">11:00</span> (11 AM)
|
||||
</TableCell>
|
||||
<TableCell className="max-w-md">
|
||||
<p className="text-sm">
|
||||
Summary push notification with overdue count and tasks due this week.
|
||||
Uses user's stored timezone for accurate overdue calculation.
|
||||
</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Onboarding Emails</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline" className="font-mono text-yellow-600">Not scheduled</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">Manual only</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span className="text-muted-foreground">-</span>
|
||||
</TableCell>
|
||||
<TableCell className="max-w-md">
|
||||
<p className="text-sm">
|
||||
Handler exists but not registered in scheduler. Can be triggered manually from admin.
|
||||
Sends emails to users who haven't created residences (2+ days) or tasks (5+ days).
|
||||
</p>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Push Notification Types */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Bell className="h-5 w-5" />
|
||||
Push Notification Types
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Types of push notifications and when they are sent
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Type</TableHead>
|
||||
<TableHead>Trigger</TableHead>
|
||||
<TableHead>User Preference</TableHead>
|
||||
<TableHead>Custom Time Field</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge>task_due_soon</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Smart Reminder job (tasks due within 2 days)</TableCell>
|
||||
<TableCell><code>task_due_soon</code></TableCell>
|
||||
<TableCell><code>task_due_soon_hour</code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="destructive">task_overdue</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Smart Reminder job (past due date)</TableCell>
|
||||
<TableCell><code>task_overdue</code></TableCell>
|
||||
<TableCell><code>task_overdue_hour</code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="secondary">task_completed</Badge>
|
||||
</TableCell>
|
||||
<TableCell>When another user completes a task</TableCell>
|
||||
<TableCell><code>task_completed</code></TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="secondary">task_assigned</Badge>
|
||||
</TableCell>
|
||||
<TableCell>When assigned to a task</TableCell>
|
||||
<TableCell><code>task_assigned</code></TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="secondary">residence_shared</Badge>
|
||||
</TableCell>
|
||||
<TableCell>When a residence is shared with user</TableCell>
|
||||
<TableCell><code>residence_shared</code></TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="outline">warranty_expiring</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Document warranty expiring (not yet implemented)</TableCell>
|
||||
<TableCell><code>warranty_expiring</code></TableCell>
|
||||
<TableCell><code>warranty_expiring_hour</code></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge className="bg-blue-500">daily_digest</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Daily Digest job (summary notification)</TableCell>
|
||||
<TableCell><code>daily_digest</code></TableCell>
|
||||
<TableCell><code>daily_digest_hour</code></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Email Templates */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Mail className="h-5 w-5" />
|
||||
Email Templates
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
All email templates and when they are sent
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="transactional" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="transactional" className="flex items-center gap-2">
|
||||
<Timer className="h-4 w-4" />
|
||||
Transactional Emails
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="onboarding" className="flex items-center gap-2">
|
||||
<Repeat className="h-4 w-4" />
|
||||
Onboarding Emails
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="transactional" className="mt-4">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead>Subject</TableHead>
|
||||
<TableHead>Trigger</TableHead>
|
||||
<TableHead>Expiry</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Welcome Email</TableCell>
|
||||
<TableCell>Welcome to Casera - Verify Your Email</TableCell>
|
||||
<TableCell>User registration (email/password)</TableCell>
|
||||
<TableCell>24 hours (verification code)</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Apple Welcome</TableCell>
|
||||
<TableCell>Welcome to Casera!</TableCell>
|
||||
<TableCell>Apple Sign In registration</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Google Welcome</TableCell>
|
||||
<TableCell>Welcome to Casera!</TableCell>
|
||||
<TableCell>Google Sign In registration</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Post-Verification</TableCell>
|
||||
<TableCell>You're All Set! Getting Started with Casera</TableCell>
|
||||
<TableCell>After email verification</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Verification Email</TableCell>
|
||||
<TableCell>Casera - Verify Your Email</TableCell>
|
||||
<TableCell>Resend verification code</TableCell>
|
||||
<TableCell>24 hours</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Password Reset</TableCell>
|
||||
<TableCell>Casera - Password Reset Request</TableCell>
|
||||
<TableCell>Password reset request</TableCell>
|
||||
<TableCell>15 minutes</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Password Changed</TableCell>
|
||||
<TableCell>Casera - Your Password Has Been Changed</TableCell>
|
||||
<TableCell>After password change</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Task Completed</TableCell>
|
||||
<TableCell>Casera - Task Completed: [Task Title]</TableCell>
|
||||
<TableCell>When task is completed (if email_task_completed = true)</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Tasks Report</TableCell>
|
||||
<TableCell>Casera - Tasks Report for [Residence]</TableCell>
|
||||
<TableCell>User requests PDF export</TableCell>
|
||||
<TableCell>-</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TabsContent>
|
||||
<TabsContent value="onboarding" className="mt-4">
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
Cron-triggered daily at 10:00 AM UTC. Each email type sent only once per user.
|
||||
</p>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Email Type</TableHead>
|
||||
<TableHead>Subject</TableHead>
|
||||
<TableHead>Criteria</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="outline">no_residence</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Get started with Casera - Add your first property</TableCell>
|
||||
<TableCell>2+ days since registration, no residence created</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">
|
||||
<Badge variant="outline">no_tasks</Badge>
|
||||
</TableCell>
|
||||
<TableCell>Stay on top of home maintenance with Casera</TableCell>
|
||||
<TableCell>5+ days since first residence, no tasks created</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Default Configuration */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Calendar className="h-5 w-5" />
|
||||
Scheduled Job Times
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Hardcoded cron schedules in internal/worker/scheduler.go (all times UTC)
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Cron Expression</TableHead>
|
||||
<TableHead>Hour (UTC)</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-mono">Cron: 0 20 * * *</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary">20</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">(8:00 PM UTC)</span>
|
||||
</TableCell>
|
||||
<TableCell>Task reminders (due soon) - hardcoded in scheduler.go</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-mono">Cron: 0 9 * * *</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary">9</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">(9:00 AM UTC)</span>
|
||||
</TableCell>
|
||||
<TableCell>Overdue reminders - hardcoded in scheduler.go</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-mono">Cron: 0 11 * * *</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary">11</Badge>
|
||||
<span className="text-xs text-muted-foreground ml-2">(11:00 AM UTC)</span>
|
||||
</TableCell>
|
||||
<TableCell>Daily digest - hardcoded in scheduler.go</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Smart Reminder Logic */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Info className="h-5 w-5" />
|
||||
Smart Reminder Logic
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
How the frequency-aware reminder system works
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="rounded-lg border p-4 space-y-3">
|
||||
<h4 className="font-medium">Reminder Stages by Frequency</h4>
|
||||
<p className="text-xs text-muted-foreground mb-2">
|
||||
Source: internal/notifications/reminder_config.go
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 text-sm">
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Once / Daily / Weekly:</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>Day-of only</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Bi-Weekly (14d):</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>1 day before</li>
|
||||
<li>Day-of</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Monthly (30d):</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>3 days before</li>
|
||||
<li>1 day before</li>
|
||||
<li>Day-of</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Quarterly (90d):</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>7 days before</li>
|
||||
<li>3 days before</li>
|
||||
<li>1 day before</li>
|
||||
<li>Day-of</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Semi-Annually (180d):</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>14 days before</li>
|
||||
<li>7 days before</li>
|
||||
<li>3 days before</li>
|
||||
<li>1 day before</li>
|
||||
<li>Day-of</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-muted-foreground">Annually (365d):</p>
|
||||
<ul className="list-disc list-inside mt-1 space-y-1">
|
||||
<li>30 days before</li>
|
||||
<li>14 days before</li>
|
||||
<li>7 days before</li>
|
||||
<li>3 days before</li>
|
||||
<li>1 day before</li>
|
||||
<li>Day-of</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border p-4 space-y-3">
|
||||
<h4 className="font-medium">Overdue Reminder Tapering</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Overdue reminders taper off to avoid notification fatigue (configured in reminder_config.go):
|
||||
</p>
|
||||
<ul className="list-disc list-inside text-sm space-y-1">
|
||||
<li><strong>Days 1-3:</strong> Daily reminders (DailyReminderDays: 3)</li>
|
||||
<li><strong>Days 4, 7, 10, 13:</strong> Every 3 days (TaperIntervalDays: 3)</li>
|
||||
<li><strong>After 14 days:</strong> No more reminders (MaxOverdueDays: 14)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border p-4 space-y-3">
|
||||
<h4 className="font-medium">Duplicate Prevention</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Each reminder is tracked in the <code className="bg-muted px-1 rounded">task_reminder_logs</code> table
|
||||
with task ID, user ID, due date, and stage. This prevents sending the same reminder twice.
|
||||
Logs older than 90 days are automatically cleaned up.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Timezone Handling */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Clock className="h-5 w-5" />
|
||||
Timezone Handling
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
How user timezones are captured and used
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="rounded-lg border p-4 space-y-3">
|
||||
<h4 className="font-medium">Auto-Capture</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The mobile app sends an <code className="bg-muted px-1 rounded">X-Timezone</code> header
|
||||
on every API request (IANA format, e.g., "America/Los_Angeles").
|
||||
The server captures this when the user fetches their tasks (happens on every app launch)
|
||||
and stores it in the <code className="bg-muted px-1 rounded">timezone</code> column of
|
||||
<code className="bg-muted px-1 rounded">notifications_notificationpreference</code>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border p-4 space-y-3">
|
||||
<h4 className="font-medium">Usage in Daily Digest</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The Daily Digest job uses the stored timezone to calculate "start of day" in the user's
|
||||
local time. This ensures the overdue task count matches what the user sees in the app's Kanban view.
|
||||
If no timezone is stored, UTC is used as fallback.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
Apple,
|
||||
Image,
|
||||
ImagePlus,
|
||||
Cog,
|
||||
} from 'lucide-react';
|
||||
import { useRouter, usePathname } from 'next/navigation';
|
||||
import { useAuthStore } from '@/store/auth';
|
||||
@@ -77,6 +78,7 @@ const limitationsItems = [
|
||||
|
||||
const settingsItems = [
|
||||
{ title: 'Monitoring', url: '/admin/monitoring', icon: Activity },
|
||||
{ title: 'Automation Reference', url: '/admin/automation-reference', icon: Cog },
|
||||
{ title: 'Lookup Tables', url: '/admin/lookups', icon: BookOpen },
|
||||
{ title: 'Task Templates', url: '/admin/task-templates', icon: LayoutTemplate },
|
||||
{ title: 'Admin Users', url: '/admin/admin-users', icon: UserCog },
|
||||
|
||||
Reference in New Issue
Block a user