Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EdgarJr30/proyecto-de-grado-cms/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Supabase provides the backend infrastructure for MLM CMMS, including authentication, database, storage, and Edge Functions. This guide covers the complete configuration process after database setup.
Complete the Database Setup before proceeding with this configuration.

Edge Function Deployment

Push Notification Worker

The send-push-from-outbox Edge Function processes the notification outbox and sends Web Push notifications.

Prerequisites

1

Install Supabase CLI

npm install -g supabase
2

Link Project

supabase link --project-ref <your-project-ref>
3

Generate VAPID Keys

If not already generated:
npx web-push generate-vapid-keys --json
Output:
{
  "publicKey": "BG7x...",
  "privateKey": "abc123..."
}

Configure Function Secrets

Set the required secrets for the Edge Function:
# Required secrets
supabase secrets set SUPABASE_URL=https://your-project.supabase.co
supabase secrets set SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
supabase secrets set VAPID_PUBLIC_KEY=BG7x...
supabase secrets set VAPID_PRIVATE_KEY=abc123...

# Optional secrets
supabase secrets set VAPID_SUBJECT=mailto:your-email@domain.com
supabase secrets set PUSH_OUTBOX_CRON_SECRET=random_secret_string
supabase secrets set PUSH_OUTBOX_MAX_ATTEMPTS=5
supabase secrets set PUSH_OUTBOX_BACKOFF_BASE_SECONDS=60
supabase secrets set PUSH_OUTBOX_BACKOFF_MAX_SECONDS=3600
supabase secrets set PUSH_OUTBOX_PROCESSING_LEASE_SECONDS=300
supabase secrets set PUSH_OUTBOX_MAX_PARALLEL_SENDS=10
Never commit the VAPID_PRIVATE_KEY or SUPABASE_SERVICE_ROLE_KEY to version control. These are sensitive secrets.

Deploy the Function

cd supabase/functions
supabase functions deploy send-push-from-outbox --project-ref <project-ref>
Verify deployment:
supabase functions list
Expected output:
┌─────────────────────────┬────────┬─────────────┐
│ NAME                    │ STATUS │ UPDATED AT  │
├─────────────────────────┼────────┼─────────────┤
│ send-push-from-outbox   │ ACTIVE │ 2 mins ago  │
└─────────────────────────┴────────┴─────────────┘

Notification Dispatch Configuration

The notification system uses two dispatch mechanisms for reliability: Configure database settings to trigger the Edge Function immediately when notifications are queued:
ALTER DATABASE postgres
SET app.settings.push_outbox_worker_url = 'https://<project-ref>.functions.supabase.co/send-push-from-outbox';

ALTER DATABASE postgres
SET app.settings.push_outbox_service_jwt = '<SUPABASE_SERVICE_ROLE_KEY>';

ALTER DATABASE postgres
SET app.settings.push_outbox_cron_secret = '<PUSH_OUTBOX_CRON_SECRET>';
If you receive “permission denied to set parameter”, use Option B (Database Webhook) instead.

Option B: Immediate Dispatch via Database Webhook (Fallback)

If ALTER DATABASE is not permitted, configure a Database Webhook:
1

Open Database Webhooks

In Supabase dashboard, go to Database > Webhooks.
2

Create New Webhook

Click Create a new webhook with these settings:
  • Name: Push Notification Dispatch
  • Table: public.notification_outbox
  • Events: INSERT
  • HTTP Method: POST
  • URL: https://<project-ref>.functions.supabase.co/send-push-from-outbox?limit=1
3

Add HTTP Headers

Authorization: Bearer <SUPABASE_SERVICE_ROLE_KEY>
apikey: <SUPABASE_SERVICE_ROLE_KEY>
x-cron-secret: <PUSH_OUTBOX_CRON_SECRET>
Content-Type: application/json
4

Enable Webhook

Save and enable the webhook.
Set up a cron job to process any stuck or failed notifications:
Execute in Supabase SQL Editor:
-- Schedule every minute
SELECT cron.schedule(
  'process-push-outbox',
  '* * * * *',
  $$
  SELECT net.http_post(
    url := 'https://<project-ref>.functions.supabase.co/send-push-from-outbox?limit=100',
    headers := jsonb_build_object(
      'Authorization', 'Bearer <SUPABASE_SERVICE_ROLE_KEY>',
      'apikey', '<SUPABASE_SERVICE_ROLE_KEY>',
      'x-cron-secret', '<PUSH_OUTBOX_CRON_SECRET>',
      'Content-Type', 'application/json'
    ),
    body := '{}'
  );
  $$
);

Storage Configuration

Configure Supabase Storage for file uploads:

Create Storage Buckets

The database setup script (14_storage.sql) should have created these buckets automatically:
  • ticket-attachments: Photos and files attached to tickets
  • user-avatars: User profile pictures
  • asset-photos: Fixed asset images
Verify buckets exist:
1

Check Storage Dashboard

Go to Storage in Supabase dashboard and verify buckets are listed.
2

Verify Public Access

Ensure ticket-attachments is set to Public if you want attachments visible without authentication.

Storage Policies

The SQL script automatically configures RLS policies for Storage:
-- Example policy from 14_storage.sql
CREATE POLICY "Users can upload to ticket-attachments"
ON storage.objects FOR INSERT
TO authenticated
WITH CHECK (bucket_id = 'ticket-attachments');

CREATE POLICY "Users can view ticket-attachments"
ON storage.objects FOR SELECT
TO authenticated
USING (bucket_id = 'ticket-attachments');
Verify policies in Storage > Policies section.

Realtime Configuration

Enable Realtime for Critical Tables

1

Access Replication Settings

Navigate to Database > Replication in Supabase dashboard.
2

Enable Tables

Ensure these tables are enabled in the supabase_realtime publication:
  • public.notification_deliveries
  • public.ticket_comments
  • public.tickets (optional, for live kanban updates)
  • public.work_orders (optional, for work order tracking)
3

Verify Replica Identity

Run in SQL Editor:
SELECT 
  schemaname, 
  tablename,
  CASE pg_class.relreplident
    WHEN 'd' THEN 'DEFAULT'
    WHEN 'f' THEN 'FULL'
    WHEN 'i' THEN 'INDEX'
    WHEN 'n' THEN 'NOTHING'
  END as replica_identity
FROM pg_tables
JOIN pg_class ON pg_tables.tablename = pg_class.relname
WHERE schemaname = 'public'
  AND tablename IN ('notification_deliveries', 'ticket_comments')
ORDER BY tablename;
Expected: Both should have FULL replica identity.
The database setup script (13_realtime.sql) should have configured replica identity automatically. This verification ensures it was applied correctly.

Realtime Security

Realtime subscriptions respect RLS policies. Users can only receive updates for rows they have permission to view. Example frontend subscription:
import { supabase } from './supabaseClient'

const channel = supabase
  .channel('notifications')
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'notification_deliveries',
      filter: `user_id=eq.${userId}`
    },
    (payload) => {
      console.log('New notification:', payload.new)
    }
  )
  .subscribe()

Authentication Configuration

Email Authentication

1

Configure Email Templates

Go to Authentication > Email Templates.Customize:
  • Confirmation email
  • Password reset email
  • Magic link email
2

Set Site URL

In Authentication > URL Configuration, set:
  • Site URL: https://your-domain.com
  • Redirect URLs: Add all valid redirect URLs for OAuth flows
3

Configure SMTP (Optional)

For production, configure custom SMTP in Project Settings > Auth > SMTP Settings.

Session Configuration

Recommended settings in Authentication > Settings:
  • JWT expiry: 3600 seconds (1 hour)
  • Refresh token rotation: Enabled
  • Reuse interval: 10 seconds
  • Session timeout: 604800 seconds (7 days)

API Configuration

Rate Limiting

Configure rate limits in Project Settings > API:
  • Anonymous requests: 100 per hour (restrictive)
  • Authenticated requests: 1000 per hour (generous for active users)

CORS Configuration

Add your production domain to allowed origins:
https://your-domain.com
https://www.your-domain.com
Do not use wildcard * for CORS in production. Specify exact domains.

Testing the Configuration

Smoke Test Script

Run the notifications smoke test to verify the entire pipeline:
SUPABASE_URL=https://your-project.supabase.co \
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key \
TEST_RECIPIENT_USER_ID=user_uuid \
TEST_ACTOR_USER_ID=actor_uuid \
node scripts/notifications-smoke.mjs
This script tests:
  • ✅ Notification creation
  • ✅ Delivery to user
  • ✅ Outbox processing
  • ✅ Push notification dispatch
  • ✅ Comment system integration

Manual UI Testing

1

Test In-App Notifications

  1. Navigate to /notificaciones
  2. Verify bell icon shows unread count
  3. Click notification to mark as read
  4. Swipe notification to toggle read/unread status
2

Test Admin Notifications

  1. Login as user with users:full_access or rbac:manage_permissions permission
  2. Use “Prueba Admin” button to send test notification
  3. Verify notification appears in bell dropdown
3

Test Comment Notifications

  1. Open a ticket detail page
  2. Add a comment
  3. Verify comment appears in UI
  4. Check that notification is created for ticket owner
  5. Click notification to navigate to ticket
4

Test Push Notifications

  1. Navigate to /notificaciones
  2. Click “Push en este dispositivo”
  3. Grant browser permission when prompted
  4. Send test push notification to yourself
  5. Verify notification appears as browser notification
  6. Check outbox status transitions from pendingprocessingsent

Verify Outbox Processing

Check notification outbox status:
-- View outbox status distribution
SELECT status, COUNT(*) as count
FROM public.notification_outbox
GROUP BY status
ORDER BY status;
Expected results:
  • Most messages in sent status
  • Few in pending (only recent ones)
  • None stuck in processing for more than 5 minutes
-- Check for stuck messages
SELECT id, status, attempts, last_error, created_at, next_attempt_at, sent_at
FROM public.notification_outbox
WHERE status IN ('pending', 'processing', 'failed')
ORDER BY created_at DESC
LIMIT 20;

Platform-Specific Push Notification Notes

Android

  • ✅ Chrome browser with granted notification permission
  • ✅ Works in regular browser tabs
  • ✅ Works in PWA installed mode

iOS

  • ⚠️ Requires app to be installed to home screen (PWA)
  • ⚠️ Only works in Safari (not Chrome or Firefox)
  • ⚠️ User must grant notification permission in iOS settings
  • ✅ iOS 16.4+ supports Web Push in PWAs

Desktop

  • ✅ Works in Chrome, Edge, Firefox
  • ✅ Requires system notification permission
  • ✅ Works in both browser tabs and PWAs
Web Push requires HTTPS in production. Test push notifications thoroughly on actual devices, not just in development.

Monitoring and Maintenance

Database Queries for Health Checks

-- Check auth function privileges
SELECT
  has_function_privilege('authenticated', 'public.create_notification_event(text,uuid,text,text,jsonb,uuid[],integer)', 'EXECUTE') 
    AS auth_can_create_event,
  has_function_privilege('service_role', 'public.create_notification_event(text,uuid,text,text,jsonb,uuid[],integer)', 'EXECUTE') 
    AS service_can_create_event;
-- Outbox health (last hour)
SELECT 
  status,
  COUNT(*) as count,
  MIN(created_at) as oldest,
  MAX(created_at) as newest,
  AVG(attempts) as avg_attempts
FROM public.notification_outbox
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY status;
-- Failed notifications requiring attention
SELECT id, attempts, last_error, created_at, next_attempt_at
FROM public.notification_outbox
WHERE status = 'failed'
  AND attempts >= 5
ORDER BY created_at DESC
LIMIT 50;

Set Up Monitoring Alerts

Recommended alerts:
  • ⚠️ Outbox processing rate drops below threshold
  • ⚠️ Failed notifications exceed 5% of total
  • ⚠️ Messages stuck in processing for >10 minutes
  • ⚠️ Edge Function errors increase
  • ⚠️ Database connection pool exhaustion

Troubleshooting

Edge Function Deployment Fails

# Check function logs
supabase functions logs send-push-from-outbox --project-ref <ref>

# Verify secrets are set
supabase secrets list --project-ref <ref>

# Redeploy
supabase functions deploy send-push-from-outbox --project-ref <ref> --no-verify-jwt

Notifications Not Sending

  1. Check outbox for stuck messages
  2. Verify Edge Function secrets are correct
  3. Check Edge Function logs for errors
  4. Verify cron job or webhook is triggering
  5. Test manual trigger:
    curl -X POST "https://<ref>.functions.supabase.co/send-push-from-outbox?limit=1" \
      -H "Authorization: Bearer <SERVICE_ROLE_KEY>" \
      -H "apikey: <SERVICE_ROLE_KEY>" \
      -H "x-cron-secret: <CRON_SECRET>"
    

Realtime Not Working

  1. Verify tables are in supabase_realtime publication
  2. Check replica identity is set to FULL
  3. Verify RLS policies allow user to SELECT rows
  4. Check browser console for WebSocket errors
  5. Verify Realtime is enabled in project settings

Storage Upload Fails

  1. Verify bucket exists and is correctly named
  2. Check RLS policies on storage.objects
  3. Verify file size is within limits (default 50MB)
  4. Check CORS configuration for your domain

Next Steps

Environment Setup

Review environment variable configuration for all environments

Production Build

Build and deploy the frontend application

Build docs developers (and LLMs) love