Data Models & Database Schema
Complete documentation of the Toto ecosystem's data structure, relationships, and business logic with comprehensive seeding system.
π Overviewβ
The Toto ecosystem uses Firestore as its primary database with a well-structured data model that supports:
- Case Management - Pet rescue cases with donation tracking
- User Management - Multi-role user system (users, guardians, admins, investors, partners)
- Support System - Comprehensive support ticket management
- Donation System - Fundraising with Stellar wallet integration
- Audit Logging - Complete system activity tracking
- Security - Role-based access control and data isolation
ποΈ Collection Structureβ
Core Collectionsβ
users/ - User accounts and profiles (all roles)
cases/ - Pet rescue cases and campaigns
donations/ - Donation records with Stellar integration
updates/ - Case updates and progress tracking
follows/ - User subscriptions to cases
support_tickets/ - Support ticket management system
notifications/ - User notification system
audit_logs/ - System audit trail and activity logs
Deprecated Collections (Removed)β
waitlist/ - External waitlist entries (now handled in users collection)
ticket_updates/ - Support ticket updates (now handled in support_tickets)
sharedPosts/ - Social media integration (removed)
pets/ - Pet records (removed)
statusUpdates/ - Status updates (removed)
π₯ User Managementβ
User Roles & Permissionsβ
User Typesβ
user- Basic platform user, can donate and follow casesguardian- Case owner, can create and manage casesadmin- Platform administrator with full accessinvestor- Financial backers and stakeholderspartner- Business partners and collaborators
User Statusβ
active- Fully functional user accountinactive- Temporarily disabled accountpending- Awaiting approval or completionwaitlist- On waitlist for platform access
Enhanced User Interface (User)β
interface User {
id: string; // Normalized ID (e.g., "usr_abc123")
email: string; // User's email address
name: string; // Display name
role: UserRole; // 'user' | 'guardian' | 'admin' | 'investor' | 'partner'
status: UserStatus; // 'active' | 'inactive' | 'pending' | 'waitlist'
imageUrl?: string; // Profile picture URL
createdAt: string; // ISO 8601 timestamp
updatedAt: string; // ISO 8601 timestamp
lastLoginAt?: string; // Last login timestamp
firebaseUid?: string; // Firebase Auth UID
// Enhanced profile fields
bio?: string; // User description
location?: string; // Geographic location
phone?: string; // Phone number (Argentina format)
organization?: string; // Organization (guardians/admins)
department?: string; // Department (role-based)
timeSinceJoined?: string; // Time since joining (guardians)
// Activity tracking
activityRate?: number; // User activity score (0-100)
// Permissions (role-based)
permissions?: string[]; // Array of permission strings
// Contact information
contactInfo?: {
phone?: string; // Phone number
website?: string; // Personal/organization website
socialLinks?: {
facebook?: string; // Facebook profile
instagram?: string; // Instagram profile
twitter?: string; // Twitter profile
}
};
// Banking information (for guardians)
bankingAccountAlias?: string; // Primary banking account alias (kept for backward compatibility)
bankingAccountAliases?: string[]; // Multiple banking account aliases for donations
// User preferences
preferences?: {
notifications: boolean; // Push notification preference
emailUpdates: boolean; // Email update preference
caseTypes: string[]; // Preferred case categories
};
}
User Role Typesβ
type UserRole = 'user' | 'guardian' | 'admin' | 'investor' | 'partner';
type UserStatus = 'active' | 'inactive' | 'pending' | 'waitlist';
Authentication State (AuthState)β
interface AuthState {
user: User | null; // Current authenticated user
isLoading: boolean; // Authentication loading state
error: string | null; // Authentication error message
isAuthenticated: boolean; // Authentication status
}
π Case Managementβ
Enhanced Case Interface (Case)β
interface Case {
id: string; // Normalized ID (e.g., "cas_abc123")
name: string; // Case title
description: string; // Detailed case description
imageUrl: string; // Primary case image
additionalImages?: string[]; // Additional case images
status: CaseStatus; // 'active' | 'urgent' | 'completed' | 'draft'
priority: CasePriority; // 'urgent' | 'normal'
category: CaseCategory; // 'rescue' | 'surgery' | 'treatment' | 'transit' | 'foster'
guardianId: string; // Guardian's user ID
guardianName: string; // Guardian's display name
// Financial tracking
donationGoal: number; // Target amount in cents
donationsReceived: number; // Current amount received
// Timestamps (ISO 8601)
createdAt: string; // Case creation timestamp
updatedAt: string; // Last update timestamp
// Analytics (calculated, not seeded)
followersCount?: number; // Number of followers
sharesCount?: number; // Number of shares
viewsCount?: number; // Number of views
commentsCount?: number; // Number of comments
}
Case Typesβ
type CaseStatus = 'active' | 'urgent' | 'completed' | 'draft';
type CasePriority = 'urgent' | 'normal';
type CaseCategory = 'rescue' | 'surgery' | 'treatment' | 'transit' | 'foster';
Guardian Interface (Guardian)β
interface Guardian {
id: string; // Guardian's user ID
name: string; // Guardian's display name
imageUrl: string; // Guardian's profile image
description?: string; // Guardian's bio/description
}
π° Donation System (Stellar Integration)β
Enhanced Donation Interface (Donation)β
interface Donation {
id: string; // Normalized ID (e.g., "don_abc123")
caseId: string; // Related case ID
guardianId: string; // Guardian ID (for direct donations)
userId?: string; // Donor's user ID (optional for anonymous)
userName?: string; // Donor's display name
userEmail?: string; // Donor's email
// Financial details
amount: number; // Donation amount in cents
currency: string; // Currency code (ARS, USD)
originalAmount: number; // Original amount before conversion
convertedAmount: number; // Amount after currency conversion
// Payment processing
paymentProvider: string; // Payment provider (MoonPay, etc.)
transactionId: string; // Internal transaction ID
partnerTransactionId: string; // Partner transaction ID
// Status and metadata
status: DonationStatus; // 'pending' | 'completed' | 'failed' | 'refunded'
message?: string; // Optional donor message
isAnonymous: boolean; // Public visibility preference
// Timestamps (ISO 8601)
createdAt: string; // Donation creation timestamp
completedAt?: string; // Payment completion timestamp
}
Donation Typesβ
type DonationStatus = 'pending' | 'completed' | 'failed' | 'refunded';
π Case Updates & Progressβ
Case Update Interface (CaseUpdate)β
interface CaseUpdate {
id: string; // Unique update identifier
caseId: string; // Related case ID
type: UpdateType; // 'status_change' | 'note' | 'comment' | 'milestone'
status?: CaseStatus; // New case status
previousStatus?: string; // Previous case status
notes?: string; // Update description
updatedBy: string; // User ID who made the update
updatedByName: string; // User's display name
createdAt: Date; // Update timestamp
metadata?: { // Extended update information
attachmentUrl?: string; // File attachment URL
tags?: string[]; // Update tags
priority?: 'low' | 'medium' | 'high';
}
}
Update Typesβ
type UpdateType = 'status_change' | 'note' | 'comment' | 'milestone';
π« Support Systemβ
Support Ticket Interface (SupportTicket)β
interface SupportTicket {
id: string; // Normalized ID (e.g., "spt_abc123")
ticketNumber: string; // Human-readable ticket number
title: string; // Ticket title
description: string; // Detailed description
status: TicketStatus; // 'open' | 'in_progress' | 'resolved' | 'closed'
priority: TicketPriority; // 'low' | 'medium' | 'high' | 'urgent'
category: string; // Ticket category
// Assignment
assignedTo?: string; // Assigned admin user ID
assignedToName?: string; // Assigned admin name
// Requester information
requesterId?: string; // Requester user ID
requesterEmail: string; // Requester email
requesterName?: string; // Requester name
// Timestamps (ISO 8601)
createdAt: string; // Ticket creation timestamp
updatedAt: string; // Last update timestamp
dueDate: string; // Due date timestamp
resolvedAt?: string; // Resolution timestamp
closedAt?: string; // Closure timestamp
// Additional data
tags: string[]; // Ticket tags
attachments: string[]; // Attachment URLs
internalNotes?: string; // Internal admin notes
}
Support Typesβ
type TicketStatus = 'open' | 'in_progress' | 'resolved' | 'closed';
type TicketPriority = 'low' | 'medium' | 'high' | 'urgent';
π Notification Systemβ
Notification Interface (Notification)β
interface Notification {
id: string; // Normalized ID (e.g., "not_abc123")
userId: string; // Target user ID
userEmail: string; // Target user email
type: NotificationType; // Notification type
category: string; // Notification category
priority: NotificationPriority; // 'low' | 'medium' | 'high' | 'urgent'
title: string; // Notification title
message: string; // Notification message
actionUrl?: string; // Action URL
isRead: boolean; // Read status
createdAt: string; // ISO 8601 timestamp
metadata?: { // Additional data
caseId?: string; // Related case ID
ticketId?: string; // Related ticket ID
[key: string]: any; // Flexible metadata
}
}
Notification Typesβ
type NotificationType = 'case_update' | 'donation_received' | 'ticket_assigned' | 'system_alert';
type NotificationPriority = 'low' | 'medium' | 'high' | 'urgent';
π Audit Logging Systemβ
Audit Log Interface (AuditLog)β
interface AuditLog {
id: string; // Normalized ID (e.g., "aud_abc123")
timestamp: string; // ISO 8601 timestamp
userId: string; // User who performed the action
userEmail: string; // User email
userRole: string; // User role
action: string; // Action performed
resource: string; // Resource type
resourceId: string; // Resource ID
details: { // Action details
before?: any; // State before action
after?: any; // State after action
ipAddress?: string; // User IP address
userAgent?: string; // User agent string
reason?: string; // Action reason
[key: string]: any; // Additional details
};
severity: AuditSeverity; // 'low' | 'medium' | 'high' | 'critical'
category: AuditCategory; // Audit category
}
Audit Typesβ
type AuditSeverity = 'low' | 'medium' | 'high' | 'critical';
type AuditCategory = 'user' | 'case' | 'donation' | 'system' | 'security' | 'support' | 'notification';
π± Social Media Integrationβ
Shared Post Interface (SharedPost)β
interface SharedPost {
id: string; // Unique post identifier
caseId: string; // Related case ID
guardianId: string; // Guardian who shared the post
platform: SocialPlatform; // Social media platform
originalPostUrl: string; // Original post URL
embedCode?: string; // Optional embed code
description?: string; // Post description
createdAt: Date; // Sharing timestamp
updatedAt?: Date; // Last update timestamp
approvalStatus?: ApprovalStatus; // 'pending' | 'approved' | 'rejected'
}
Social Platformsβ
type SocialPlatform = 'facebook' | 'instagram' | 'twitter' | 'tiktok' | 'other';
type ApprovalStatus = 'pending' | 'approved' | 'rejected';
π± Seeding Systemβ
Comprehensive Seeding Scriptβ
The system includes a complete seeding script (/api/init-staging-final) that generates:
- 27 Users - All roles and statuses including waitlist users
- 15 Support Tickets - Complete support system with assignments
- 10 Cases - All categories and priorities
- 50 Donations - Stellar wallet integration with multiple currencies
- 30 Follows - User-case relationships
- 30 Notifications - User-specific notifications
- 36 Case Updates - Progress tracking
- 200 Audit Logs - System activity tracking
Seeding Featuresβ
- Normalized IDs - Consistent ID format across all entities
- ISO 8601 Timestamps - Standardized time format
- Realistic Data - Argentina phone numbers, realistic names
- Role-based Data - Appropriate fields based on user roles
- Conditional Fields - No undefined values in Firestore
- Modular Design - Separate modules for each entity type
ID Generation Systemβ
// ID prefixes
const ENTITY_PREFIXES = {
USER: 'usr',
CASE: 'cas',
DONATION: 'don',
FOLLOW: 'flw',
NOTIFICATION: 'not',
AUDIT_LOG: 'aud',
SUPPORT_TICKET: 'spt',
UPDATE: 'upd'
};
// Example IDs
// usr_abc123def456
// cas_xyz789ghi012
// don_mno345pqr678
π Security & Access Controlβ
Firestore Security Rulesβ
User Data Isolationβ
// Users can only access their own data
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
Case Access Controlβ
// Public read access, guardian/admin write access
match /cases/{caseId} {
allow read: if true;
allow create: if request.auth != null &&
request.auth.uid == request.resource.data.guardianId;
allow update, delete: if request.auth != null &&
(request.auth.uid == resource.data.guardianId ||
request.auth.token.admin == true);
}
Donation Privacyβ
// Donors can see their own donations, guardians see case donations
match /donations/{donationId} {
allow read: if request.auth != null && (
request.auth.uid == resource.data.donorId ||
// Guardian of related case
get(/databases/$(database)/documents/cases/$(resource.data.caseId))
.data.guardianId == request.auth.uid
);
}
π Data Relationshipsβ
Primary Relationshipsβ
User (1) ββ (Many) Cases (as guardian)
User (1) ββ (Many) Donations (as donor)
User (1) ββ (Many) Follows (as follower)
User (1) ββ (Many) Notifications (as recipient)
User (1) ββ (Many) AuditLogs (as actor)
Case (1) ββ (Many) Donations
Case (1) ββ (Many) Updates
Case (1) ββ (Many) Follows
SupportTicket (1) ββ (Many) AuditLogs
Collection Dependenciesβ
- Cases depend on Users (guardian relationship)
- Donations depend on Cases and optionally Users
- Updates depend on Cases and Users
- Notifications depend on Users
- AuditLogs depend on Users and various resources
π Performance Considerationsβ
Indexing Strategyβ
- User queries: Index on
role,status,createdAt - Case queries: Index on
status,priority,category,guardianId - Donation queries: Index on
caseId,status,createdAt - Support queries: Index on
status,priority,assignedTo - Audit queries: Index on
userId,category,timestamp
Query Optimizationβ
- Use compound indexes for complex queries
- Limit result sets with pagination
- Cache frequently accessed data
- Use subcollection queries for related data
π Migration & Versioningβ
Schema Evolutionβ
- All fields are optional where possible for backward compatibility
- Use metadata fields for future extensibility
- Version control through Firestore document versions
- Gradual migration strategies for breaking changes
Data Validationβ
- Client-side validation for immediate feedback
- Server-side validation for data integrity
- Firestore rules for access control validation
- TypeScript interfaces for compile-time checking
π API Integrationβ
Data Flowβ
- Client β API β Firestore (Create/Update)
- Firestore β API β Client (Read)
- Real-time updates via Firestore listeners
- Offline support with local caching
CRUD Operationsβ
- Create: New cases, users, donations
- Read: Public case data, user-specific data
- Update: Case progress, user profiles
- Delete: Soft deletes preferred over hard deletes
π Monitoring & Analyticsβ
Key Metricsβ
- Case completion rates by category and urgency
- Donation patterns and fundraising success
- User engagement and retention
- System performance and response times
Data Exportβ
- CSV exports for guardian reports
- Analytics dashboards for admins
- API endpoints for external integrations
- Backup strategies for data preservation
This documentation covers the complete data model for the Toto ecosystem. For implementation details, see the API Reference and Development Setup.