navidocs/intelligence/session-2/maintenance-log-spec.md
Claude d250dc334e
Session 2: Complete technical architecture from 11 Haiku agents
All 11 agents (S2-H01 through S2-H09 + S2-H03A + S2-H07A) have completed
their technical specifications:

- S2-H01: NaviDocs codebase architecture analysis
- S2-H02: Inventory tracking system (€15K-€50K value recovery)
- S2-H03: Maintenance log & reminder system
- S2-H04: Camera & Home Assistant integration
- S2-H05: Contact management system
- S2-H06: Accounting module & receipt OCR integration
- S2-H07: Impeccable search UX (Meilisearch facets)
- S2-H08: WhatsApp Business API + AI agent integration
- S2-H09: Document versioning with IF.TTT compliance
- S2-H03A: VAT/tax jurisdiction tracking & compliance
- S2-H07A: Multi-calendar system (4 calendar types)

Total: ~15,600 lines of technical specifications
Status: Ready for S2-H10 synthesis (awaiting Session 1 completion)
IF.bus: All inter-agent communications documented
2025-11-13 01:57:25 +00:00

28 KiB

Maintenance Log & Reminder System (S2-H03)

System Overview

The Maintenance Log & Reminder System provides comprehensive tracking of marine vessel maintenance activities with intelligent reminder generation based on both calendar dates and engine hours. This system integrates with contact management (S2-H05) and calendar systems (S2-H07A) to provide a complete maintenance lifecycle management solution.


1. Database Schema

Primary Table: maintenance_log

CREATE TABLE maintenance_log (
  -- Primary Keys & Foreign Keys
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  boat_id BIGINT NOT NULL,

  -- Service Information
  service_type ENUM(
    'engine',
    'electronics',
    'hull',
    'deck',
    'safety_equipment',
    'antifouling',
    'survey'
  ) NOT NULL,

  -- Date & Time Tracking
  date DATE NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  -- Maintenance Details
  cost DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
  provider VARCHAR(255) NOT NULL,
  notes TEXT,
  receipt_url VARCHAR(500),

  -- Engine Hours at Service
  engine_hours INT,

  -- Next Service Scheduling
  next_due_date DATE,
  next_due_engine_hours INT,

  -- Soft Delete for Audit Trail
  is_deleted BOOLEAN DEFAULT FALSE,
  deleted_at TIMESTAMP NULL,

  -- Indexing for Performance
  INDEX idx_boat_id (boat_id),
  INDEX idx_service_type (service_type),
  INDEX idx_date (date),
  INDEX idx_next_due_date (next_due_date),
  INDEX idx_engine_hours (engine_hours),
  INDEX idx_boat_service_type (boat_id, service_type),
  CONSTRAINT fk_boat_id FOREIGN KEY (boat_id) REFERENCES boats(id)
);

Supporting Table: maintenance_service_intervals

Defines standard service intervals for each service type:

CREATE TABLE maintenance_service_intervals (
  id INT PRIMARY KEY AUTO_INCREMENT,
  service_type ENUM(
    'engine',
    'electronics',
    'hull',
    'deck',
    'safety_equipment',
    'antifouling',
    'survey'
  ) NOT NULL UNIQUE,

  -- Standard intervals
  months_interval INT,
  engine_hours_interval INT,
  description VARCHAR(500),

  -- Notification rules
  days_before_due INT DEFAULT 7,

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  INDEX idx_service_type (service_type)
);

Sample Data:

INSERT INTO maintenance_service_intervals VALUES
  (1, 'engine', 6, 100, 'Engine oil and filter change', 14),
  (2, 'engine', 12, 500, 'Impeller replacement', 14),
  (3, 'electronics', 12, NULL, 'Electronics systems check', 7),
  (4, 'hull', 24, NULL, 'Hull inspection and antifouling check', 30),
  (5, 'deck', 12, NULL, 'Deck hardware and fasteners inspection', 7),
  (6, 'safety_equipment', 12, NULL, 'Safety equipment certification', 30),
  (7, 'antifouling', 12, NULL, 'Haul-out and antifouling paint', 60),
  (8, 'survey', 60, NULL, 'Professional marine survey', 90);

Supporting Table: maintenance_reminders

Tracks reminder notifications sent to users:

CREATE TABLE maintenance_reminders (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  maintenance_log_id BIGINT NOT NULL,
  boat_id BIGINT NOT NULL,

  -- Reminder Configuration
  days_before_due INT NOT NULL,
  reminder_type ENUM('date_based', 'engine_hours_based', 'hybrid') NOT NULL,

  -- Notification Status
  notification_status ENUM('pending', 'sent', 'dismissed', 'snoozed') DEFAULT 'pending',
  sent_at TIMESTAMP NULL,
  dismissed_at TIMESTAMP NULL,
  snoozed_until TIMESTAMP NULL,

  -- Tracking
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  INDEX idx_boat_id (boat_id),
  INDEX idx_maintenance_log_id (maintenance_log_id),
  INDEX idx_notification_status (notification_status),
  INDEX idx_days_before_due (days_before_due),
  CONSTRAINT fk_maintenance_log FOREIGN KEY (maintenance_log_id) REFERENCES maintenance_log(id),
  CONSTRAINT fk_boat_id_reminders FOREIGN KEY (boat_id) REFERENCES boats(id)
);

Supporting Table: maintenance_service_history

Audit log for historical service patterns per boat and service type:

CREATE TABLE maintenance_service_history (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  boat_id BIGINT NOT NULL,
  service_type VARCHAR(50) NOT NULL,

  -- Historical Aggregates
  last_service_date DATE,
  last_service_engine_hours INT,
  total_services INT DEFAULT 0,
  average_cost DECIMAL(10, 2),
  total_cost DECIMAL(12, 2),

  -- Performance Metrics
  average_days_between_service INT,
  average_hours_between_service INT,

  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  UNIQUE KEY uk_boat_service (boat_id, service_type),
  INDEX idx_boat_id (boat_id),
  CONSTRAINT fk_boat_id_history FOREIGN KEY (boat_id) REFERENCES boats(id)
);

2. API Endpoints

2.1 Maintenance Log CRUD Operations

CREATE: Add New Maintenance Record

POST /api/v1/boats/{boatId}/maintenance
Content-Type: application/json

Request Body:
{
  "service_type": "engine",
  "date": "2024-11-13",
  "cost": 450.00,
  "provider": "West Marine",
  "notes": "Oil change and filter replacement",
  "receipt_url": "https://storage.example.com/receipt-123.pdf",
  "engine_hours": 2450,
  "next_due_date": "2025-05-13",
  "next_due_engine_hours": 2550
}

Response (201 Created):
{
  "id": 1001,
  "boat_id": 5,
  "service_type": "engine",
  "date": "2024-11-13",
  "cost": 450.00,
  "provider": "West Marine",
  "notes": "Oil change and filter replacement",
  "receipt_url": "https://storage.example.com/receipt-123.pdf",
  "engine_hours": 2450,
  "next_due_date": "2025-05-13",
  "next_due_engine_hours": 2550,
  "created_at": "2024-11-13T14:32:00Z",
  "reminders": [
    {
      "id": 5001,
      "days_before_due": 60,
      "reminder_type": "date_based",
      "notification_status": "pending"
    }
  ]
}

READ: Get Maintenance Records

GET /api/v1/boats/{boatId}/maintenance
Query Parameters:
  - service_type: Optional filter (engine, electronics, hull, deck, safety_equipment, antifouling, survey)
  - start_date: ISO 8601 date
  - end_date: ISO 8601 date
  - status: pending, completed, overdue
  - limit: 50 (default), max 500
  - offset: 0 (default)

Response (200 OK):
{
  "total": 47,
  "limit": 50,
  "offset": 0,
  "records": [
    {
      "id": 1001,
      "boat_id": 5,
      "service_type": "engine",
      "date": "2024-11-13",
      "cost": 450.00,
      "provider": "West Marine",
      "engine_hours": 2450,
      "next_due_date": "2025-05-13",
      "next_due_engine_hours": 2550,
      "created_at": "2024-11-13T14:32:00Z"
    }
  ]
}

UPDATE: Modify Maintenance Record

PATCH /api/v1/boats/{boatId}/maintenance/{maintenanceId}
Content-Type: application/json

Request Body:
{
  "cost": 475.00,
  "notes": "Oil change, filter replacement, coolant top-up"
}

Response (200 OK):
{
  "id": 1001,
  "boat_id": 5,
  "service_type": "engine",
  "date": "2024-11-13",
  "cost": 475.00,
  "provider": "West Marine",
  "notes": "Oil change, filter replacement, coolant top-up",
  "updated_at": "2024-11-13T15:45:00Z"
}

DELETE: Remove Maintenance Record

DELETE /api/v1/boats/{boatId}/maintenance/{maintenanceId}

Response (204 No Content)

2.2 Smart Reminder Endpoints

Get Upcoming Reminders

GET /api/v1/boats/{boatId}/maintenance/reminders/upcoming
Query Parameters:
  - days_window: 30 (default, look ahead 30 days)
  - include_engine_hours: true/false
  - sort_by: days_remaining, date, engine_hours

Response (200 OK):
{
  "total": 5,
  "upcoming_reminders": [
    {
      "id": 5001,
      "service_type": "engine",
      "last_service_date": "2024-11-13",
      "next_due_date": "2025-05-13",
      "next_due_engine_hours": 2550,
      "current_engine_hours": 2480,
      "days_until_due": 181,
      "hours_until_due": 70,
      "reminder_type": "hybrid",
      "due_trigger": "engine_hours",
      "provider": "West Marine",
      "estimated_cost": 450.00
    }
  ]
}

Trigger Reminder Notification

POST /api/v1/boats/{boatId}/maintenance/reminders/{reminderId}/send
Request Body: {}

Response (200 OK):
{
  "id": 5001,
  "notification_status": "sent",
  "sent_at": "2024-11-13T14:32:00Z",
  "notification_channels": ["push", "email", "sms"]
}

Update Reminder Status

PATCH /api/v1/boats/{boatId}/maintenance/reminders/{reminderId}
Content-Type: application/json

Request Body:
{
  "notification_status": "dismissed"
}

Response (200 OK):
{
  "id": 5001,
  "notification_status": "dismissed",
  "dismissed_at": "2024-11-13T15:00:00Z"
}

Snooze Reminder

POST /api/v1/boats/{boatId}/maintenance/reminders/{reminderId}/snooze
Content-Type: application/json

Request Body:
{
  "snooze_days": 7
}

Response (200 OK):
{
  "id": 5001,
  "notification_status": "snoozed",
  "snoozed_until": "2024-11-20T14:32:00Z"
}

2.3 Service Provider Auto-Suggest (S2-H05 Integration)

Get Provider Suggestions

GET /api/v1/boats/{boatId}/maintenance/providers/suggest
Query Parameters:
  - service_type: Required (engine, electronics, hull, deck, safety_equipment, antifouling, survey)
  - limit: 10 (default)

Response (200 OK):
{
  "service_type": "engine",
  "suggestions": [
    {
      "id": "provider_123",
      "name": "West Marine",
      "type": "marine_service",
      "contact_id": "contact_456",
      "phone": "+1-555-0100",
      "email": "service@westmarine.com",
      "address": "123 Harbor St, Marina City",
      "last_used": "2024-11-13",
      "times_used": 8,
      "average_cost": 450.00,
      "rating": 4.8
    },
    {
      "id": "provider_124",
      "name": "Marina Services Inc",
      "type": "marine_service",
      "contact_id": "contact_457",
      "phone": "+1-555-0101",
      "email": "info@marinaservices.com",
      "address": "456 Dock Ave, Marina City",
      "last_used": "2024-09-22",
      "times_used": 3,
      "average_cost": 500.00,
      "rating": 4.5
    }
  ]
}

2.4 Expense Rollup Endpoints

Year-to-Date Expenses

GET /api/v1/boats/{boatId}/maintenance/expenses/ytd
Query Parameters:
  - year: 2024 (optional, defaults to current year)

Response (200 OK):
{
  "year": 2024,
  "start_date": "2024-01-01",
  "end_date": "2024-11-13",
  "total_ytd": 8450.00,
  "by_service_type": {
    "engine": {
      "count": 4,
      "total": 1800.00,
      "average": 450.00
    },
    "electronics": {
      "count": 2,
      "total": 2100.00,
      "average": 1050.00
    },
    "hull": {
      "count": 1,
      "total": 3500.00,
      "average": 3500.00
    },
    "deck": {
      "count": 1,
      "total": 300.00,
      "average": 300.00
    },
    "safety_equipment": {
      "count": 0,
      "total": 0.00
    },
    "antifouling": {
      "count": 0,
      "total": 0.00
    },
    "survey": {
      "count": 0,
      "total": 0.00
    }
  },
  "by_provider": {
    "West Marine": 3500.00,
    "Marina Services Inc": 2450.00,
    "Electronics Pro": 2500.00
  }
}

Annual Budget Analysis

GET /api/v1/boats/{boatId}/maintenance/expenses/annual-analysis
Query Parameters:
  - year: 2024 (optional)

Response (200 OK):
{
  "year": 2024,
  "total_annual": 8450.00,
  "projected_annual": 11200.00,
  "budget_health": {
    "status": "on_track",
    "months_data": [
      {
        "month": "January",
        "month_number": 1,
        "total": 450.00,
        "vs_average": -42.50
      },
      {
        "month": "February",
        "month_number": 2,
        "total": 0.00,
        "vs_average": -492.50
      }
    ]
  }
}

All-Time Maintenance Summary

GET /api/v1/boats/{boatId}/maintenance/expenses/all-time
Response (200 OK):
{
  "boat_id": 5,
  "boat_name": "Sea Dream",
  "all_time_total": 42350.00,
  "record_count": 127,
  "first_service": "2018-03-15",
  "last_service": "2024-11-13",
  "average_annual_spend": 5293.75,
  "most_expensive_service": {
    "id": 950,
    "service_type": "survey",
    "date": "2022-06-10",
    "cost": 5500.00
  },
  "most_common_service": {
    "service_type": "engine",
    "count": 34,
    "total_cost": 15300.00,
    "average_cost": 450.00
  }
}

3. Reminder Calculation Algorithm

3.1 Core Algorithm: Dual-Trigger Reminder Logic

The reminder system calculates when maintenance is due based on either calendar date or engine hours, whichever comes first.

/**
 * Calculate maintenance reminder status
 * @param {Object} maintenance - Maintenance record
 * @param {Date} referenceDate - Current date (default: today)
 * @param {number} currentEngineHours - Current engine hours on boat
 * @returns {Object} Reminder status and trigger information
 */
function calculateReminderStatus(maintenance, referenceDate = new Date(), currentEngineHours) {
  const nextDueDate = new Date(maintenance.next_due_date);
  const nextDueEngineHours = maintenance.next_due_engine_hours;

  // Calculate days until due
  const daysUntilDue = Math.floor((nextDueDate - referenceDate) / (1000 * 60 * 60 * 24));

  // Calculate hours until due
  const hoursUntilDue = nextDueEngineHours ? (nextDueEngineHours - currentEngineHours) : Infinity;

  // Determine which trigger fires first
  const isDateTriggered = daysUntilDue <= 0;
  const isHoursTriggered = hoursUntilDue <= 0;

  // Determine primary trigger when both exist
  let primaryTrigger = 'pending';
  let daysToAlert = daysUntilDue;

  if (isDateTriggered && isHoursTriggered) {
    primaryTrigger = daysUntilDue >= hoursUntilDue ? 'engine_hours' : 'date';
  } else if (isDateTriggered) {
    primaryTrigger = 'date';
  } else if (isHoursTriggered) {
    primaryTrigger = 'engine_hours';
  } else {
    // Calculate which will trigger first
    const daysToHours = hoursUntilDue / 25; // Assuming 25 hours per day average usage
    primaryTrigger = daysUntilDue <= daysToHours ? 'date' : 'engine_hours';
    daysToAlert = Math.min(daysUntilDue, Math.ceil(daysToHours));
  }

  // Determine alert status based on days remaining
  let alertStatus = 'on_schedule';
  if (daysUntilDue <= 0 || hoursUntilDue <= 0) {
    alertStatus = 'overdue';
  } else if (daysUntilDue <= 7) {
    alertStatus = 'critical';
  } else if (daysUntilDue <= 14) {
    alertStatus = 'urgent';
  } else if (daysUntilDue <= 30) {
    alertStatus = 'approaching';
  }

  return {
    maintenance_id: maintenance.id,
    service_type: maintenance.service_type,
    status: alertStatus,
    due_trigger: primaryTrigger,
    reminder_type: 'hybrid',
    next_due_date: nextDueDate.toISOString().split('T')[0],
    next_due_engine_hours: nextDueEngineHours,
    current_engine_hours: currentEngineHours,
    days_until_due: daysUntilDue,
    hours_until_due: hoursUntilDue,
    should_notify: alertStatus !== 'on_schedule'
  };
}

/**
 * Generate reminder records for upcoming maintenance
 * @param {Array} maintenanceRecords - Array of maintenance records
 * @param {number} currentEngineHours - Current engine hours
 * @param {Date} referenceDate - Current date
 * @returns {Array} Array of reminder records to persist
 */
function generateReminderRecords(maintenanceRecords, currentEngineHours, referenceDate = new Date()) {
  const reminders = [];
  const alertThresholds = [60, 30, 14, 7]; // Days before due

  maintenanceRecords.forEach(record => {
    const status = calculateReminderStatus(record, referenceDate, currentEngineHours);

    if (status.should_notify) {
      // Generate reminder for each threshold that applies
      alertThresholds.forEach(threshold => {
        if (status.days_until_due <= threshold && status.days_until_due > (threshold - 7)) {
          reminders.push({
            maintenance_log_id: record.id,
            boat_id: record.boat_id,
            days_before_due: threshold,
            reminder_type: status.due_trigger === 'engine_hours' ? 'engine_hours_based' : 'date_based',
            alert_status: status.status,
            due_trigger: status.due_trigger
          });
        }
      });
    }
  });

  return reminders;
}

3.2 Scheduling Algorithm: When to Send Notifications

/**
 * Determine notification schedule for maintenance
 * @param {number} daysUntilDue - Days until maintenance is due
 * @returns {Object} Notification configuration
 */
function getNotificationSchedule(daysUntilDue) {
  const schedules = [
    { threshold: 60, interval: 'weekly', priority: 'low', message: 'Maintenance approaching' },
    { threshold: 30, interval: 'bi-weekly', priority: 'medium', message: 'Maintenance needed soon' },
    { threshold: 14, interval: 'weekly', priority: 'high', message: 'Maintenance due in 2 weeks' },
    { threshold: 7, interval: 'daily', priority: 'urgent', message: 'Maintenance due in 1 week' },
    { threshold: 0, interval: 'daily', priority: 'critical', message: 'OVERDUE: Maintenance required now' }
  ];

  return schedules.find(s => daysUntilDue <= s.threshold) || schedules[0];
}

4. Expense Rollup Queries

4.1 Year-to-Date Total by Service Type

SELECT
  ml.service_type,
  COUNT(*) as service_count,
  SUM(ml.cost) as total_cost,
  AVG(ml.cost) as average_cost,
  MIN(ml.cost) as min_cost,
  MAX(ml.cost) as max_cost
FROM maintenance_log ml
WHERE ml.boat_id = ?
  AND YEAR(ml.date) = YEAR(CURDATE())
  AND ml.is_deleted = FALSE
GROUP BY ml.service_type
ORDER BY total_cost DESC;

4.2 Monthly Breakdown

SELECT
  DATE_TRUNC('month', ml.date) as month,
  COUNT(*) as service_count,
  SUM(ml.cost) as total_cost,
  GROUP_CONCAT(DISTINCT ml.service_type) as service_types
FROM maintenance_log ml
WHERE ml.boat_id = ?
  AND ml.is_deleted = FALSE
GROUP BY DATE_TRUNC('month', ml.date)
ORDER BY month DESC;

4.3 Provider Expense Analysis

SELECT
  ml.provider,
  COUNT(*) as service_count,
  SUM(ml.cost) as total_cost,
  AVG(ml.cost) as average_cost,
  MAX(ml.date) as last_service_date,
  GROUP_CONCAT(DISTINCT ml.service_type) as service_types
FROM maintenance_log ml
WHERE ml.boat_id = ?
  AND ml.is_deleted = FALSE
GROUP BY ml.provider
ORDER BY total_cost DESC;

4.4 Projected Annual Maintenance Cost

SELECT
  YEAR(ml.date) as year,
  COUNT(*) as service_count,
  SUM(ml.cost) as annual_total,
  AVG(ml.cost) as average_service_cost,
  (SELECT AVG(annual_costs.yearly_total)
   FROM (
     SELECT SUM(ml2.cost) as yearly_total
     FROM maintenance_log ml2
     WHERE ml2.boat_id = ?
       AND ml2.is_deleted = FALSE
     GROUP BY YEAR(ml2.date)
   ) annual_costs) as historical_average
FROM maintenance_log ml
WHERE ml.boat_id = ?
  AND ml.is_deleted = FALSE
GROUP BY YEAR(ml.date)
ORDER BY year DESC;

4.5 Service Interval Performance

SELECT
  ml.service_type,
  COUNT(*) as total_services,
  AVG(DATEDIFF(ml.date, LAG(ml.date) OVER (PARTITION BY ml.service_type ORDER BY ml.date))) as avg_days_between_service,
  AVG(ml.engine_hours - LAG(ml.engine_hours) OVER (PARTITION BY ml.service_type ORDER BY ml.date)) as avg_hours_between_service,
  MAX(ml.date) as last_service,
  AVG(ml.cost) as average_cost
FROM maintenance_log ml
WHERE ml.boat_id = ?
  AND ml.is_deleted = FALSE
GROUP BY ml.service_type;

5. Integration Points

5.1 Integration with S2-H05 (Contact Management)

Data Flow: maintenance_log.provider → contacts

The Maintenance Log system pulls service provider contacts from S2-H05 to:

  • Auto-suggest service providers based on past services
  • Display provider contact information (phone, email, address)
  • Track provider reliability and ratings
  • Link maintenance records to specific provider contacts

Required S2-H05 API Endpoints:

GET /api/v1/boats/{boatId}/contacts/providers
  - Filter by service_type
  - Return contact details with contact_id

GET /api/v1/contacts/{contactId}
  - Return full contact information
  - Include communication preferences
  - Return provider ratings/history

Maintenance Log Data Provided to S2-H05:

{
  "contact_id": "provider_123",
  "last_used": "2024-11-13",
  "times_used": 8,
  "average_cost": 450.00,
  "service_types_offered": ["engine", "electronics"]
}

5.2 Integration with S2-H07A (Calendar System)

Data Flow: maintenance_log.next_due_date → calendar

The Maintenance Log system exports service due dates to S2-H07A calendar to:

  • Display scheduled maintenance on boat calendar
  • Sync with mobile calendar applications
  • Generate calendar notifications
  • Track historical maintenance events

Required S2-H07A API Endpoints:

POST /api/v1/boats/{boatId}/calendar/events
  - Create maintenance event
  - Set event type: "maintenance"
  - Set due date and recurrence

DELETE /api/v1/boats/{boatId}/calendar/events/{eventId}
  - Remove maintenance event when complete

PATCH /api/v1/boats/{boatId}/calendar/events/{eventId}
  - Update event details when maintenance is rescheduled

Calendar Event Payload:

{
  "title": "Oil Change Due",
  "description": "Engine oil and filter change - West Marine",
  "event_type": "maintenance",
  "service_type": "engine",
  "due_date": "2025-05-13",
  "due_engine_hours": 2550,
  "location": "West Marine, 123 Harbor St",
  "priority": "high",
  "alert_days": [7, 14, 30, 60],
  "provider_contact_id": "provider_123"
}

6. Mobile Notification Design

6.1 Notification Schedule

Notifications are triggered based on time-to-due thresholds:

Days Before Due Notification Type Frequency Priority Message Template
60+ In-app badge Weekly Low "{ServiceType} maintenance approaching"
30-59 Push + Email Bi-weekly Medium "{ServiceType} service needed in {days} days"
14-29 Push + Email + SMS Weekly High "Schedule {ServiceType} - due in {days} days"
7-13 Push + Email + SMS Daily Urgent "URGENT: {ServiceType} due in {days} days"
<7 Push + Email + SMS + In-App Daily Critical "OVERDUE: {ServiceType} maintenance required"

6.2 Push Notification Templates

60-Day Reminder

Title: Maintenance Ahead
Body: Oil change coming up in 60 days (May 13)
Action: View Details → Maintenance Log Entry

30-Day Reminder

Title: Schedule Maintenance
Body: Engine service needed in 30 days. Call West Marine to book.
Action: Call Provider | Snooze 7 Days | View Details

14-Day Reminder

Title: Maintenance Due Soon
Body: Oil change due May 13 (14 days). Booked with West Marine?
Action: Confirm Scheduled | Reschedule | View Details

7-Day Reminder (Urgent)

Title: URGENT - Maintenance Due
Body: Oil change is due in 7 days. Schedule immediately.
Action: Book Now | Contact Provider | View Details

Overdue

Title: OVERDUE MAINTENANCE
Body: Oil change is overdue as of May 13. Service immediately.
Action: Mark Complete | Acknowledge | View Details

6.3 Email Notification Template

Subject: Maintenance Reminder: {ServiceType} Due {DaysRemaining} Days

---

Hi {OwnerName},

This is a reminder that maintenance is coming up for {BoatName}:

SERVICE TYPE: {ServiceType}
DUE DATE: {DueDate} ({DaysRemaining} days from now)
NEXT DUE ENGINE HOURS: {EngineHours}
RECOMMENDED PROVIDER: {ProviderName}
ESTIMATED COST: ${EstimatedCost}

LAST SERVICE:
- Date: {LastServiceDate}
- Provider: {LastProviderName}
- Cost: ${LastCost}

PROVIDER CONTACT:
- Name: {ProviderName}
- Phone: {ProviderPhone}
- Email: {ProviderEmail}
- Address: {ProviderAddress}

ACTION REQUIRED:
1. Review maintenance details
2. Contact provider to schedule service
3. Confirm appointment in maintenance log

Questions? Reply to this email or visit the Maintenance Log in your NaviDocs app.

---
Sent by NaviDocs Maintenance Tracking System

6.4 SMS Notification Template

NaviDocs: {ServiceType} maintenance due {DaysRemaining} days ({DueDate}).
Provider: {ProviderName} {ProviderPhone}.
Confirm: [link-to-app]

6.5 In-App Notification Design

Approaching (60+ days)

┌─────────────────────────────────┐
│ 📋 Maintenance Approaching      │
├─────────────────────────────────┤
│ Oil Change                      │
│ Due: May 13, 2025 (60 days)    │
│                                 │
│ [View Details] [Dismiss]       │
└─────────────────────────────────┘

Urgent (7-14 days)

┌─────────────────────────────────┐
│ ⚠️  URGENT - Schedule Now       │
├─────────────────────────────────┤
│ Engine Service                  │
│ Due: May 13, 2025 (7 days)     │
│ Current Hours: 2480/2550        │
│                                 │
│ West Marine: (555) 0100        │
│ Est. Cost: $450                │
│                                 │
│ [Book Now] [Snooze] [Dismiss]  │
└─────────────────────────────────┘

Overdue (0 days or less)

┌─────────────────────────────────┐
│ 🚨 OVERDUE - Action Required   │
├─────────────────────────────────┤
│ Hull Inspection                 │
│ DUE: April 15, 2024 (213 DAYS)  │
│ Status: OVERDUE                 │
│                                 │
│ [Mark Complete] [Schedule Now]  │
│ [View History] [Dismiss]        │
└─────────────────────────────────┘

6.6 Notification Preferences API

GET /api/v1/users/{userId}/notification-preferences/maintenance

Response:
{
  "email_enabled": true,
  "sms_enabled": true,
  "push_enabled": true,
  "in_app_enabled": true,
  "alert_thresholds": {
    "60_days": { "enabled": true, "channels": ["in_app", "email"] },
    "30_days": { "enabled": true, "channels": ["in_app", "email"] },
    "14_days": { "enabled": true, "channels": ["push", "email"] },
    "7_days": { "enabled": true, "channels": ["push", "email", "sms"] },
    "overdue": { "enabled": true, "channels": ["push", "email", "sms"] }
  },
  "quiet_hours": {
    "enabled": true,
    "start": "22:00",
    "end": "07:00"
  }
}

PATCH /api/v1/users/{userId}/notification-preferences/maintenance
Content-Type: application/json

Request Body:
{
  "alert_thresholds": {
    "14_days": { "enabled": false }
  }
}

7. Implementation Notes

7.1 Engine Hours Tracking

  • Engine hours must be manually entered at each service
  • System stores cumulative engine hours (not hours since last service)
  • Engine hours validation: must be >= previous record
  • Estimated usage: 25 hours/day (customizable per boat)

7.2 Service Interval Customization

  • Standard intervals defined in maintenance_service_intervals table
  • Boat-specific intervals can be defined in boat_maintenance_config table
  • Owners can override standard intervals based on usage patterns

7.3 Reminder Audit Trail

  • All reminder actions logged for compliance
  • Snoozed reminders re-queue automatically
  • Dismissed reminders can be restored within 30 days
  • Email/SMS delivery tracked via notification_log table

7.4 Data Retention

  • Deleted maintenance records soft-deleted (retained for audit)
  • Hard delete only after 7 years for compliance
  • Expense reports include deleted records for historical accuracy

8. Security Considerations

  • All maintenance records require boat ownership verification
  • Receipt URLs stored with encryption at rest
  • Provider contact data access controlled per user role
  • Sensitive cost data masked for multi-user accounts
  • All API endpoints require authentication and rate limiting

9. Success Metrics

  • Reminder delivery rate: >95% within 24 hours of trigger
  • API response time: <200ms for maintenance list queries
  • Expense calculation accuracy: 100% (automated validation)
  • User reminder completion: >75% services completed within 7 days of due date
  • Provider contact accuracy: 98% phone/email validation rate