Data Model
This document describes the core entities and their relationships in Optare.
Entity Relationship Diagram
┌────────────────┐ ┌────────────────┐
│ User │ │ Organization │
├────────────────┤ ├────────────────┤
│ id │ │ id │
│ email │ │ name │
│ name │ │ slug │
│ avatarUrl │ │ logoUrl │
│ emailVerified │ │ settings │
└───────┬────────┘ └───────┬────────┘
│ │
│ ┌────────────────┐ │
└───│ Membership │───┘
├────────────────┤
│ userId │
│ organizationId │
│ role │
│ permissions │
└───────┬────────┘
│
┌───────────┴───────────┐
│ │
┌───────▼────────┐ ┌───────▼────────┐
│ Subscription │ │ Product │
├────────────────┤ ├────────────────┤
│ id │ │ id │
│ organizationId │◄────│ name │
│ productId │ │ slug │
│ status │ │ features │
│ seats │ │ description │
└────────────────┘ └────────────────┘Core Entities
User
A person who can authenticate.
interface User {
id: string; // Unique identifier
email: string; // Email address (unique)
name?: string; // Display name
avatarUrl?: string; // Profile picture
emailVerified: boolean;
createdAt: Date;
updatedAt: Date;
}Relationships:
- Has many Memberships (belongs to many Organizations)
- Has many Sessions
Organization
A tenant/customer account.
interface Organization {
id: string;
name: string; // Display name
slug: string; // URL-safe identifier (unique)
logoUrl?: string;
settings: OrgSettings;
createdAt: Date;
}
interface OrgSettings {
allowedDomains?: string[];
requireMfa?: boolean;
sessionTimeout?: number;
samlConfig?: SAMLConfig;
}Relationships:
- Has many Members (Users through Memberships)
- Has many Subscriptions
- Has many OAuth Clients
- Has many Invitations
Membership
Links Users to Organizations with a role.
interface Membership {
id: string;
userId: string;
organizationId: string;
role: 'owner' | 'admin' | 'member' | 'guest';
customPermissions?: string[];
createdAt: Date;
}Roles:
| Role | Description | Permissions |
|---|---|---|
| owner | Full control | All, including billing and delete |
| admin | Manage team | Invite, remove, settings |
| member | Use product | Standard access |
| guest | Limited access | Read-only |
Product
A software product or plan.
interface Product {
id: string;
name: string; // "Pro Plan"
slug: string; // "pro"
description?: string;
features: string[]; // ["sso", "analytics"]
metadata?: Record<string, any>;
}Subscription
Links an Organization to a Product.
interface Subscription {
id: string;
organizationId: string;
productId: string;
status: 'active' | 'trial' | 'cancelled' | 'expired';
totalSeats: number;
usedSeats: number;
pricePerSeat?: number;
billingCycle?: 'monthly' | 'yearly';
startDate: Date;
endDate?: Date;
}Session
An active user session.
interface Session {
id: string;
userId: string;
token: string;
expiresAt: Date;
ipAddress?: string;
userAgent?: string;
createdAt: Date;
}OAuth Client
An application registered for OAuth.
interface OAuthClient {
id: string;
organizationId: string;
name: string;
clientId: string; // Public identifier
clientSecret?: string; // For confidential clients
redirectUris: string[];
grantTypes: string[];
scopes: string[];
createdAt: Date;
}Query Patterns
Get User's Organizations
SELECT o.*, m.role
FROM organizations o
JOIN memberships m ON m.organization_id = o.id
WHERE m.user_id = $userId;Get Organization's Members
SELECT u.*, m.role
FROM users u
JOIN memberships m ON m.user_id = u.id
WHERE m.organization_id = $orgId;Check Feature Access
SELECT p.features
FROM subscriptions s
JOIN products p ON p.id = s.product_id
WHERE s.organization_id = $orgId
AND s.status = 'active';Validate Org Membership
SELECT role FROM memberships
WHERE user_id = $userId
AND organization_id = $orgId;Indexes
| Table | Index | Purpose |
|---|---|---|
| users | Login lookup | |
| memberships | user_id | User's orgs |
| memberships | organization_id | Org's members |
| subscriptions | organization_id | Org's products |
| sessions | token | Session validation |
| sessions | user_id | User's sessions |
Next Steps
- Multi-Tenancy - How organizations work
- RBAC - Permission system
- B2B Architecture - Design patterns