> ## Documentation Index
> Fetch the complete documentation index at: https://memberpulseptyltd.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Convex Integration

> Real-time backend platform for live data sync, serverless functions, and file storage

## Overview

Convex is a real-time backend platform that powers MemberPulse's live features including real-time notifications, live dashboards, collaborative features, and instant data synchronization across all connected clients.

<CardGroup cols={3}>
  <Card title="Real-time Sync" icon="rotate">
    Instant data updates across all clients
  </Card>

  <Card title="Serverless Functions" icon="bolt">
    Backend logic without infrastructure
  </Card>

  <Card title="File Storage" icon="cloud-arrow-up">
    Integrated file storage with CDN
  </Card>
</CardGroup>

***

## Why Convex?

| Feature                  | Benefit                                            |
| ------------------------ | -------------------------------------------------- |
| **Real-time by Default** | All queries automatically update when data changes |
| **ACID Transactions**    | Strong consistency guarantees for data integrity   |
| **TypeScript Native**    | End-to-end type safety from database to UI         |
| **Serverless**           | No infrastructure to manage, scales automatically  |
| **Built-in Auth**        | Integrates with existing auth providers            |

***

## Prerequisites

Before configuring Convex:

1. Create a Convex account at [convex.dev](https://convex.dev)
2. Install the Convex CLI: `npm install -g convex`
3. Initialize your project: `npx convex dev`

***

## Configuration

### Environment Variables

```bash theme={null}
# Backend
CONVEX_DEPLOYMENT=prod:memberpulse-xxxxx
CONVEX_DEPLOY_KEY=prod:xxxxxxxxxxxxxxxxxxxx

# Frontend
NEXT_PUBLIC_CONVEX_URL=https://memberpulse-xxxxx.convex.cloud
```

#### Acceptance Criteria

##### Frontend

* [ ] Environment Variables workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Environment Variables as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Platform Settings

Navigate to **Admin Portal > Platform Settings > Integrations > Convex**

| Setting          | Type   | Required | Description                    |
| ---------------- | ------ | -------- | ------------------------------ |
| Deployment URL   | URL    | Yes      | Convex deployment URL          |
| Deploy Key       | Secret | Yes      | Production deploy key          |
| Enable Real-time | Toggle | Yes      | Enable real-time features      |
| Sync Interval    | Number | No       | Fallback polling interval (ms) |

***

#### Acceptance Criteria

##### Frontend

* [ ] Platform Settings workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Platform Settings as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Architecture

### Data Flow

```mermaid theme={null}
graph LR
    A[React Client] -->|Subscribe| B[Convex Cloud]
    B -->|Real-time Updates| A
    C[Symfony API] -->|Mutations| B
    B -->|Webhooks| C
    B -->|Store| D[(Convex DB)]
    B -->|Files| E[Convex Storage]
```

#### Acceptance Criteria

##### Frontend

* [ ] Data Flow workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Data Flow as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Hybrid Architecture

MemberPulse uses a hybrid architecture:

| Data Type      | Storage              | Reason                           |
| -------------- | -------------------- | -------------------------------- |
| Core Data      | PostgreSQL (Symfony) | GDPR compliance, complex queries |
| Real-time Data | Convex               | Live updates, collaboration      |
| Files          | Convex Storage       | CDN delivery, easy uploads       |
| Sessions       | Convex               | Real-time presence               |

***

#### Acceptance Criteria

##### Frontend

* [ ] Hybrid Architecture workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Hybrid Architecture as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Real-time Features

### Live Notifications

```typescript theme={null}
// convex/notifications.ts
import { query, mutation } from "./_generated/server";
import { v } from "convex/values";

export const list = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("notifications")
      .withIndex("by_user", (q) => q.eq("userId", args.userId))
      .filter((q) => q.eq(q.field("read"), false))
      .order("desc")
      .take(50);
  },
});

export const markAsRead = mutation({
  args: { notificationId: v.id("notifications") },
  handler: async (ctx, args) => {
    await ctx.db.patch(args.notificationId, { read: true });
  },
});
```

```tsx theme={null}
// React component
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";

function NotificationBell() {
  const notifications = useQuery(api.notifications.list, { 
    userId: currentUser.id 
  });
  const markAsRead = useMutation(api.notifications.markAsRead);

  return (
    <DropdownMenu>
      <Badge count={notifications?.length || 0}>
        <BellIcon />
      </Badge>
      <DropdownContent>
        {notifications?.map((n) => (
          <NotificationItem 
            key={n._id} 
            notification={n}
            onRead={() => markAsRead({ notificationId: n._id })}
          />
        ))}
      </DropdownContent>
    </DropdownMenu>
  );
}
```

#### Acceptance Criteria

##### Frontend

* [ ] Live Notifications workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Live Notifications as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Live Dashboard Metrics

```typescript theme={null}
// convex/metrics.ts
export const dashboardStats = query({
  args: { organizationId: v.string() },
  handler: async (ctx, args) => {
    const [activeUsers, pendingApprovals, recentActivity] = await Promise.all([
      ctx.db
        .query("presence")
        .withIndex("by_org", (q) => q.eq("organizationId", args.organizationId))
        .filter((q) => q.gt(q.field("lastSeen"), Date.now() - 300000))
        .collect(),
      ctx.db
        .query("approvals")
        .withIndex("by_org_status", (q) => 
          q.eq("organizationId", args.organizationId).eq("status", "pending")
        )
        .collect(),
      ctx.db
        .query("activity")
        .withIndex("by_org", (q) => q.eq("organizationId", args.organizationId))
        .order("desc")
        .take(20),
    ]);

    return {
      activeUsersCount: activeUsers.length,
      pendingApprovalsCount: pendingApprovals.length,
      recentActivity,
    };
  },
});
```

#### Acceptance Criteria

##### Frontend

* [ ] Live Dashboard Metrics workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Live Dashboard Metrics as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Real-time Presence

Show who's online and what they're viewing:

```typescript theme={null}
// convex/presence.ts
export const heartbeat = mutation({
  args: {
    userId: v.string(),
    organizationId: v.string(),
    currentPage: v.string(),
  },
  handler: async (ctx, args) => {
    const existing = await ctx.db
      .query("presence")
      .withIndex("by_user", (q) => q.eq("userId", args.userId))
      .unique();

    if (existing) {
      await ctx.db.patch(existing._id, {
        lastSeen: Date.now(),
        currentPage: args.currentPage,
      });
    } else {
      await ctx.db.insert("presence", {
        ...args,
        lastSeen: Date.now(),
      });
    }
  },
});

export const getOnlineUsers = query({
  args: { organizationId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("presence")
      .withIndex("by_org", (q) => q.eq("organizationId", args.organizationId))
      .filter((q) => q.gt(q.field("lastSeen"), Date.now() - 60000))
      .collect();
  },
});
```

***

#### Acceptance Criteria

##### Frontend

* [ ] Real-time Presence workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Real-time Presence as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## File Storage

### Uploading Files

```typescript theme={null}
// convex/files.ts
export const generateUploadUrl = mutation(async (ctx) => {
  return await ctx.storage.generateUploadUrl();
});

export const saveFile = mutation({
  args: {
    storageId: v.id("_storage"),
    fileName: v.string(),
    fileType: v.string(),
    uploadedBy: v.string(),
    organizationId: v.string(),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert("files", {
      ...args,
      uploadedAt: Date.now(),
    });
  },
});
```

```tsx theme={null}
// React upload component
function FileUploader() {
  const generateUploadUrl = useMutation(api.files.generateUploadUrl);
  const saveFile = useMutation(api.files.saveFile);

  const handleUpload = async (file: File) => {
    // Get upload URL
    const uploadUrl = await generateUploadUrl();
    
    // Upload file to Convex storage
    const result = await fetch(uploadUrl, {
      method: "POST",
      headers: { "Content-Type": file.type },
      body: file,
    });
    const { storageId } = await result.json();
    
    // Save file metadata
    await saveFile({
      storageId,
      fileName: file.name,
      fileType: file.type,
      uploadedBy: currentUser.id,
      organizationId: currentOrg.id,
    });
  };

  return <DropZone onDrop={handleUpload} />;
}
```

#### Acceptance Criteria

##### Frontend

* [ ] Uploading Files workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Uploading Files as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Serving Files

```typescript theme={null}
// convex/files.ts
export const getFileUrl = query({
  args: { storageId: v.id("_storage") },
  handler: async (ctx, args) => {
    return await ctx.storage.getUrl(args.storageId);
  },
});
```

***

#### Acceptance Criteria

##### Frontend

* [ ] Serving Files workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Serving Files as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Scheduled Functions

### Cleanup Jobs

```typescript theme={null}
// convex/crons.ts
import { cronJobs } from "convex/server";
import { internal } from "./_generated/api";

const crons = cronJobs();

// Clean up old presence records every 5 minutes
crons.interval(
  "cleanup presence",
  { minutes: 5 },
  internal.presence.cleanup
);

// Clean up old notifications daily
crons.daily(
  "cleanup notifications",
  { hourUTC: 3, minuteUTC: 0 },
  internal.notifications.cleanup
);

export default crons;
```

```typescript theme={null}
// convex/presence.ts
export const cleanup = internalMutation({
  handler: async (ctx) => {
    const stalePresence = await ctx.db
      .query("presence")
      .filter((q) => q.lt(q.field("lastSeen"), Date.now() - 3600000))
      .collect();

    for (const record of stalePresence) {
      await ctx.db.delete(record._id);
    }
  },
});
```

***

#### Acceptance Criteria

##### Frontend

* [ ] Cleanup Jobs workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Cleanup Jobs as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Webhooks to Symfony

Sync real-time data back to the main database:

```typescript theme={null}
// convex/sync.ts
import { httpAction } from "./_generated/server";

export const syncToSymfony = httpAction(async (ctx, request) => {
  const { event, data } = await request.json();

  // Forward to Symfony webhook endpoint
  const response = await fetch(process.env.SYMFONY_WEBHOOK_URL!, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Convex-Signature": generateSignature(data),
    },
    body: JSON.stringify({ event, data }),
  });

  return new Response(null, { status: response.status });
});
```

***

## Schema Definition

```typescript theme={null}
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  notifications: defineTable({
    userId: v.string(),
    organizationId: v.string(),
    type: v.string(),
    title: v.string(),
    message: v.string(),
    link: v.optional(v.string()),
    read: v.boolean(),
    createdAt: v.number(),
  })
    .index("by_user", ["userId"])
    .index("by_org", ["organizationId"]),

  presence: defineTable({
    userId: v.string(),
    organizationId: v.string(),
    currentPage: v.string(),
    lastSeen: v.number(),
  })
    .index("by_user", ["userId"])
    .index("by_org", ["organizationId"]),

  activity: defineTable({
    organizationId: v.string(),
    userId: v.string(),
    action: v.string(),
    entityType: v.string(),
    entityId: v.string(),
    metadata: v.optional(v.any()),
    createdAt: v.number(),
  })
    .index("by_org", ["organizationId"])
    .index("by_user", ["userId"]),

  files: defineTable({
    storageId: v.id("_storage"),
    fileName: v.string(),
    fileType: v.string(),
    uploadedBy: v.string(),
    organizationId: v.string(),
    uploadedAt: v.number(),
  })
    .index("by_org", ["organizationId"])
    .index("by_user", ["uploadedBy"]),
});
```

***

## Authentication

Convex integrates with your existing auth:

```typescript theme={null}
// convex/auth.config.ts
export default {
  providers: [
    {
      domain: process.env.AUTH_DOMAIN,
      applicationID: process.env.AUTH_CLIENT_ID,
    },
  ],
};
```

```tsx theme={null}
// React provider setup
import { ConvexProviderWithAuth } from "convex/react";

function App() {
  return (
    <AuthProvider>
      <ConvexProviderWithAuth client={convex} useAuth={useAuthFromProvider}>
        <YourApp />
      </ConvexProviderWithAuth>
    </AuthProvider>
  );
}
```

***

## Deployment

### Development

```bash theme={null}
# Start local development
npx convex dev
```

#### Acceptance Criteria

##### Frontend

* [ ] Development workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Development as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Production

```bash theme={null}
# Deploy to production
npx convex deploy --prod
```

#### Acceptance Criteria

##### Frontend

* [ ] Production workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Production as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Environment Setup

```bash theme={null}
# Set environment variables
npx convex env set SYMFONY_WEBHOOK_URL https://api.memberpulse.com/webhooks/convex
npx convex env set AUTH_DOMAIN your-auth-domain.com
```

***

#### Acceptance Criteria

##### Frontend

* [ ] Environment Setup workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Environment Setup as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Monitoring

### Convex Dashboard

Access at [dashboard.convex.dev](https://dashboard.convex.dev):

* Real-time function logs
* Database explorer
* Storage usage
* Performance metrics
* Error tracking

#### Acceptance Criteria

##### Frontend

* [ ] Convex Dashboard workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Convex Dashboard as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

### Metrics to Monitor

| Metric                 | Target   | Alert Threshold |
| ---------------------- | -------- | --------------- |
| Query latency (p50)    | \< 50ms  | > 200ms         |
| Mutation latency (p50) | \< 100ms | > 500ms         |
| Active connections     | -        | > 10,000        |
| Storage usage          | -        | > 80% quota     |
| Function errors        | \< 0.1%  | > 1%            |

***

#### Acceptance Criteria

##### Frontend

* [ ] Metrics to Monitor workflow is implemented in the UI as described.

##### Backend / API

* [ ] Backend behavior supports Metrics to Monitor as documented.

##### Permissions

* [ ] Access is restricted per the Capabilities matrix on this page (or equivalent role rules).

##### Business Rules

* [ ] All business rules for this feature are enforced.

##### Error Handling

* [ ] Error states return clear messages and appropriate HTTP status codes.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Real-time updates not working">
    * Verify `NEXT_PUBLIC_CONVEX_URL` is correct
    * Check browser console for WebSocket errors
    * Ensure user is authenticated
    * Verify query is subscribed (not just called once)
  </Accordion>

  <Accordion title="File uploads failing">
    * Check file size limits (default 20MB)
    * Verify storage quota not exceeded
    * Ensure `generateUploadUrl` is called before upload
    * Check CORS configuration if uploading from browser
  </Accordion>

  <Accordion title="Functions timing out">
    * Convex functions have 60-second timeout
    * Break large operations into smaller chunks
    * Use scheduled functions for long-running tasks
    * Check for infinite loops in queries
  </Accordion>
</AccordionGroup>

***

## Security

<Warning>
  Never expose your Convex deploy key in client-side code. Use environment variables for all sensitive configuration.
</Warning>

* All data encrypted at rest and in transit
* Row-level security via authentication
* Automatic input validation via schema
* Rate limiting built-in
* GDPR-compliant data handling

## Features

### Convex Integration

#### Acceptance Criteria

##### Frontend

* [ ] Developer-facing configuration and usage is documented and internally consistent.

##### Backend / API

* [ ] Convex implementation matches the rules and contracts described on this page.

##### Permissions

* [ ] Tenant scoping and access controls are enforced as described.

##### Business Rules

* [ ] Domain rules/invariants are enforced as described.

##### Error Handling

* [ ] Access violations and validation failures produce deterministic errors.
