FOUNDRY
C8 Platform
← Tasks

[DM-06] Communications table (message templates, delivery tracking)

completedcode_genP1

Description

## DM-06: Communications table (message templates, delivery tracking) Section: Data Model | Milestone: M2 | Owner: None ### Failing Tests - **communications_table_exists** (grep): Pattern `CREATE TABLE communications` in `supabase/migrations/*.sql` (need 1+ matches) - **communications_fields** (grep): Pattern `campaign_id|template_id|target_list|delivery_status` in `supabase/migrations/*.sql` (need 3+ matches) ### Acceptance Criteria - File matching `supabase/migrations/*.sql` must contain pattern `CREATE TABLE communications` - File matching `supabase/migrations/*.sql` must contain pattern `campaign_id|template_id|target_list|delivery_status` ### Codebase Conventions - Trilingual comments: // EN: ... // VI: ... // ES: ... - SPEC section refs in comments - Zod at module level with .safeParse() - (supabase as any) with eslint-disable - NextResponse.json() responses - Error format: { error: 'message' } ### Dependencies - DM-01: FAIL - DM-03: FAIL
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
23d ago
Completed
2d ago

Quality

Overall
79%
Pass
PASS
Graded By
-
Graded At
-

Cost

Input Tokens
-
Output Tokens
-
Est. USD
-

Result

{
  "cost": {
    "input_tokens": 22,
    "estimated_usd": 0.045651,
    "output_tokens": 3039
  },
  "model": "claude-sonnet-4-20250514",
  "status": "success",
  "transport": "anthropic_api",
  "latency_ms": 36061,
  "response_text": "# Communications Table Schema\n\nI'll design a comprehensive communications system with message templates and delivery tracking capabilities.\n\n## Table Structures\n\n### 1. Message Templates Table\n```sql\nCREATE TABLE message_templates (\n    template_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    template_name VARCHAR(100) NOT NULL,\n    template_type VARCHAR(50) NOT NULL, -- 'email', 'sms', 'push', 'in_app'\n    category VARCHAR(50) NOT NULL, -- 'welcome', 'notification', 'marketing', 'transactional'\n    subject VARCHAR(200), -- For email templates\n    content TEXT NOT NULL,\n    html_content TEXT, -- For rich email content\n    variables JSONB, -- Template variables and their descriptions\n    is_active BOOLEAN DEFAULT true,\n    created_by UUID REFERENCES users(user_id),\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    \n    CONSTRAINT unique_template_name UNIQUE(template_name, template_type)\n);\n```\n\n### 2. Communication Campaigns Table\n```sql\nCREATE TABLE communication_campaigns (\n    campaign_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    campaign_name VARCHAR(100) NOT NULL,\n    template_id UUID REFERENCES message_templates(template_id),\n    campaign_type VARCHAR(50) NOT NULL, -- 'broadcast', 'triggered', 'scheduled'\n    target_audience JSONB, -- Filtering criteria for recipients\n    scheduled_at TIMESTAMP,\n    status VARCHAR(20) DEFAULT 'draft', -- 'draft', 'scheduled', 'active', 'completed', 'cancelled'\n    created_by UUID REFERENCES users(user_id),\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### 3. Message Queue Table\n```sql\nCREATE TABLE message_queue (\n    message_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    campaign_id UUID REFERENCES communication_campaigns(campaign_id),\n    template_id UUID REFERENCES message_templates(template_id),\n    recipient_id UUID REFERENCES users(user_id),\n    recipient_email VARCHAR(255),\n    recipient_phone VARCHAR(20),\n    message_type VARCHAR(50) NOT NULL,\n    priority INTEGER DEFAULT 5, -- 1 (highest) to 10 (lowest)\n    subject VARCHAR(200),\n    content TEXT NOT NULL,\n    html_content TEXT,\n    variables JSONB, -- Personalized variables for this message\n    status VARCHAR(20) DEFAULT 'queued', -- 'queued', 'processing', 'sent', 'failed', 'cancelled'\n    scheduled_for TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    attempts INTEGER DEFAULT 0,\n    max_attempts INTEGER DEFAULT 3,\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    processed_at TIMESTAMP\n);\n```\n\n### 4. Delivery Tracking Table\n```sql\nCREATE TABLE message_delivery_tracking (\n    tracking_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    message_id UUID REFERENCES message_queue(message_id),\n    campaign_id UUID REFERENCES communication_campaigns(campaign_id),\n    recipient_id UUID REFERENCES users(user_id),\n    message_type VARCHAR(50) NOT NULL,\n    delivery_status VARCHAR(30) NOT NULL, -- 'sent', 'delivered', 'failed', 'bounced', 'rejected'\n    delivery_provider VARCHAR(50), -- 'sendgrid', 'twilio', 'firebase', etc.\n    provider_message_id VARCHAR(100), -- External provider's tracking ID\n    sent_at TIMESTAMP,\n    delivered_at TIMESTAMP,\n    failed_at TIMESTAMP,\n    error_message TEXT,\n    error_code VARCHAR(20),\n    metadata JSONB, -- Additional tracking data from providers\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### 5. Message Engagement Tracking Table\n```sql\nCREATE TABLE message_engagement_tracking (\n    engagement_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    tracking_id UUID REFERENCES message_delivery_tracking(tracking_id),\n    message_id UUID REFERENCES message_queue(message_id),\n    recipient_id UUID REFERENCES users(user_id),\n    engagement_type VARCHAR(30) NOT NULL, -- 'opened', 'clicked', 'unsubscribed', 'replied'\n    engagement_data JSONB, -- URLs clicked, reply content, etc.\n    user_agent TEXT,\n    ip_address INET,\n    engaged_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    \n    CONSTRAINT unique_engagement UNIQUE(tracking_id, engagement_type, engaged_at)\n);\n```\n\n### 6. Communication Preferences Table\n```sql\nCREATE TABLE communication_preferences (\n    preference_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    user_id UUID REFERENCES users(user_id),\n    communication_type VARCHAR(50) NOT NULL, -- 'email', 'sms', 'push'\n    category VARCHAR(50) NOT NULL, -- 'marketing', 'transactional', 'notifications'\n    is_enabled BOOLEAN DEFAULT true,\n    frequency VARCHAR(20) DEFAULT 'immediate', -- 'immediate', 'daily', 'weekly', 'monthly'\n    preferred_time TIME, -- Preferred delivery time\n    timezone VARCHAR(50) DEFAULT 'UTC',\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    \n    CONSTRAINT unique_user_preference UNIQUE(user_id, communication_type, category)\n);\n```\n\n## Indexes for Performance\n\n```sql\n-- Message Templates\nCREATE INDEX idx_message_templates_type ON message_templates(template_type);\nCREATE INDEX idx_message_templates_category ON message_templates(category);\nCREATE INDEX idx_message_templates_active ON message_templates(is_active);\n\n-- Message Queue\nCREATE INDEX idx_message_queue_status ON message_queue(status);\nCREATE INDEX idx_message_queue_scheduled ON message_queue(scheduled_for);\nCREATE INDEX idx_message_queue_recipient ON message_queue(recipient_id);\nCREATE INDEX idx_message_queue_type ON message_queue(message_type);\nCREATE INDEX idx_message_queue_priority ON message_queue(priority, scheduled_for);\n\n-- Delivery Tracking\nCREATE INDEX idx_delivery_tracking_message ON message_delivery_tracking(message_id);\nCREATE INDEX idx_delivery_tracking_status ON message_delivery_tracking(delivery_status);\nCREATE INDEX idx_delivery_tracking_recipient ON message_delivery_tracking(recipient_id);\nCREATE INDEX idx_delivery_tracking_sent ON message_delivery_tracking(sent_at);\nCREATE INDEX idx_delivery_tracking_provider ON message_delivery_tracking(provider_message_id);\n\n-- Engagement Tracking\nCREATE INDEX idx_engagement_tracking_message ON message_engagement_tracking(message_id);\nCREATE INDEX idx_engagement_tracking_recipient ON message_engagement_tracking(recipient_id);\nCREATE INDEX idx_engagement_tracking_type ON message_engagement_tracking(engagement_type);\nCREATE INDEX idx_engagement_tracking_date ON message_engagement_tracking(engaged_at);\n\n-- Communication Preferences\nCREATE INDEX idx_comm_preferences_user ON communication_preferences(user_id);\nCREATE INDEX idx_comm_preferences_type ON communication_preferences(communication_type, is_enabled);\n```\n\n## Sample Views and Queries\n\n### Campaign Performance View\n```sql\nCREATE VIEW campaign_performance AS\nSELECT \n    c.campaign_id,\n    c.campaign_name,\n    c.campaign_type,\n    COUNT(DISTINCT mq.message_id) as total_messages,\n    COUNT(DISTINCT CASE WHEN dt.delivery_status = 'sent' THEN dt.message_id END) as messages_sent,\n    COUNT(DISTINCT CASE WHEN dt.delivery_status = 'delivered' THEN dt.message_id END) as messages_delivered,\n    COUNT(DISTINCT CASE WHEN dt.delivery_status = 'failed' THEN dt.message_id END) as messages_failed,\n    COUNT(DISTINCT CASE WHEN et.engagement_type = 'opened' THEN et.message_id END) as messages_opened,\n    COUNT(DISTINCT CASE WHEN et.engagement_type = 'clicked' THEN et.message_id END) as messages_clicked,\n    ROUND(\n        COUNT(DISTINCT CASE WHEN dt.delivery_status = 'delivered' THEN dt.message_id END) * 100.0 / \n        NULLIF(COUNT(DISTINCT mq.message_id), 0), 2\n    ) as delivery_rate,\n    ROUND(\n        COUNT(DISTINCT CASE WHEN et.engagement_type = 'opened' THEN et.message_id END) * 100.0 / \n        NULLIF(COUNT(DISTINCT CASE WHEN dt.delivery_status = 'delivered' THEN dt.message_id END), 0), 2\n    ) as open_rate,\n    ROUND(\n        COUNT(DISTINCT CASE WHEN et.engagement_type = 'clicked' THEN et.message_id END) * 100.0 / \n        NULLIF(COUNT(DISTINCT CASE WHEN et.engagement_type = 'opened' THEN et.message_id END), 0), 2\n    ) as click_through_rate\nFROM communication_campaigns c\nLEFT JOIN message_queue mq ON c.campaign_id = mq.campaign_id\nLEFT JOIN message_delivery_tracking dt ON mq.message_id = dt.message_id\nLEFT JOIN message_engagement_tracking et ON dt.tracking_id = et.tracking_id\nGROUP BY c.campaign_id, c.campaign_name, c.campaign_type;\n```\n\n### Message Processing Queue Query\n```sql\n-- Get next batch of messages to process\nSELECT \n    mq.*,\n    mt.template_name,\n    cp.is_enabled as recipient_opted_in\nFROM message_queue mq\nJOIN message_templates mt ON mq.template_id = mt.template_id\nLEFT JOIN communication_preferences cp ON mq.recipient_id = cp.user_id \n    AND cp.communication_type = mq.message_type \n    AND cp.category = mt.category\nWHERE mq.status = 'queued'\n    AND mq.scheduled_for <= CURRENT_TIMESTAMP\n    AND mq.attempts < mq.max_attempts\n    AND (cp.is_enabled IS NULL OR cp.is_enabled = true)\nORDER BY mq.priority ASC, mq.scheduled_for ASC\nLIMIT 100;\n```\n\n## Example Usage\n\n### 1. Create Email Template\n```sql\nINSERT INTO message_templates (\n    template_name, template_type, category, subject, content, html_content, variables\n) VALUES (\n    'welcome_email',\n    'email',\n    'transactional',\n    'Welcome to {{app_name}}!',\n    'Hi {{first_name}}, welcome to our platform!',\n    '<h1>Hi {{first_name}}</h1><p>Welcome to our platform!</p>',\n    '{\"first_name\": \"User first name\", \"app_name\": \"Application name\"}'::jsonb\n);\n```\n\n### 2. Queue Personalized Message\n```sql\nINSERT INTO message_queue (\n    template_id, recipient_id, recipient_email, message_type, \n    subject, content, variables\n) VALUES (\n    (SELECT template_id FROM message_templates WHERE template_name = 'welcome_email'),\n    '123e4567-e89b-12d3-a456-426614174000',\n    'user@example.com',\n    'email',\n    'Welcome to MyApp!',\n    'Hi John, welcome to our platform!',\n    '{\"first_name\": \"John\", \"app_name\": \"MyApp\"}'::jsonb\n);\n```\n\n### 3. Track Delivery Status\n```sql\nINSERT INTO message_delivery_tracking (\n    message_id, recipient_id, message_type, delivery_status,\n    delivery_provider, provider_message_id, sent_at\n) VALUES (\n    '123e4567-e89b-12d3-a456-426614174001',\n    '123e4567-e89b-12d3-a456-426614174000',\n    'email',\n    'sent',\n    'sendgrid',\n    'sg_message_123456',\n    CURRENT_TIMESTAMP\n);\n```\n\nThis schema provides a comprehensive foundation for managing communications with template support, delivery tracking, engagement metrics, and user preferences."
}

Audit Trail (1)

2d agodependents_unblockedfoundry_pipeline
Task ID: 2e10b9a2-a038-40a1-a891-f79fa3fbbcac