5.0 KiB
Data Models: WasaPrecruit MVP
This document describes the core data entities and their structures stored in the database (PostgreSQL) for the WasaPrecruit MVP.
Notation:
- Types follow TypeScript syntax.
PK: Primary KeyFK: Foreign Key?: Optional field
1. Aspirant
Represents a potential modeling aspirant who has interacted with the system via WhatsApp and potentially submitted the web form.
interface Aspirant {
id: string; // PK - Generated UUID or unique identifier
whatsappId: string; // Unique - Aspirant's WhatsApp phone number (e.g., E.164 format)
whatsappName?: string; // Name provided by WhatsApp profile (can be unreliable)
// Data from Web Form
firstName?: string;
lastName?: string;
email?: string; // Optional, depending on form
location?: string; // e.g., City/Region
preferredModelingType?: string[]; // Array of strings (e.g., ['Runway', 'Commercial'])
hasKids?: boolean;
preferredShift?: 'morning' | 'afternoon' | 'evening' | 'flexible' | 'any';
unavailableShifts?: ('morning' | 'afternoon' | 'evening')[];
notes?: string; // Any additional notes from the form
formSubmittedAt?: Date;
// System Data
photoUrl?: string; // URL to the photo stored in S3 (submitted via WhatsApp)
conversationId?: string; // FK to Conversation (might be implicitly linked via whatsappId)
createdAt: Date;
updatedAt: Date;
}
Indexes:
whatsappId(Unique)createdAtformSubmittedAt
2. Conversation
Represents a chat conversation between the system/recruiter and an aspirant.
interface Conversation {
id: string; // PK - Generated UUID
aspirantWhatsappId: string; // FK (conceptually) to Aspirant via whatsappId - identifies the participant
// OR alternatively: aspirantId: string; // FK to Aspirant.id if preferred
status: 'new' | 'open' | 'pending_form' | 'pending_photo' | 'needs_attention' | 'closed' | 'archived'; // Conversation status
assignedRecruiterId?: string; // FK to Recruiter/User (if assignment is implemented later)
lastMessageTimestamp?: Date; // Timestamp of the last message for sorting
unreadCount: number; // For recruiter view
createdAt: Date;
updatedAt: Date;
}
Indexes:
aspirantWhatsappIdstatuslastMessageTimestampassignedRecruiterId(if used)
Note: A conversation might be implicitly defined by messages associated with a unique aspirantWhatsappId. A separate Conversation table is useful for managing state (status, assignedRecruiterId, unreadCount) independent of individual messages.
3. Message
Represents a single message within a conversation.
interface Message {
id: string; // PK - Generated UUID or provider's message ID (if unique and suitable)
conversationId: string; // FK to Conversation
senderType: 'aspirant' | 'recruiter' | 'bot';
senderId?: string; // FK to Recruiter/User ID if senderType is 'recruiter'
aspirantWhatsappId: string; // Denormalized for easier querying by aspirant
text?: string; // Message content (if text)
mediaUrl?: string; // URL to media (e.g., photo in S3)
mediaType?: 'image' | 'video' | 'audio' | 'document'; // Type of media
providerMessageId?: string; // Original message ID from WhatsApp provider (e.g., Twilio SID)
status: 'sent' | 'delivered' | 'read' | 'failed'; // Status of outbound messages
timestamp: Date; // Time the message was sent/received
createdAt: Date;
}
Indexes:
conversationIdaspirantWhatsappIdtimestampsenderType
4. Recruiter (User Model)
Represents an agency recruiter using the platform (details depend on authentication provider like Cognito).
interface Recruiter {
id: string; // PK - Often corresponds to Cognito User Sub
name: string;
email: string; // Unique
// Add roles/permissions if needed later
createdAt: Date;
updatedAt: Date;
}
Indexes:
email(Unique)
Relationships
- One
Aspirantpotentially relates to oneConversation(based onwhatsappId). - One
Conversationcontains manyMessages. - One
Recruitercan send manyMessages.
Notes on Evolution
- Normalization: Some fields like
aspirantWhatsappIdare denormalized ontoMessagefor query performance. Assess trade-offs if data consistency becomes complex. - JSONB: Consider using PostgreSQL's JSONB type for flexible fields like
formDetailsif the web form structure is expected to change frequently, though explicit columns offer better indexing and type safety initially. - Scalability: Partitioning message tables by date or
conversationIdmight be necessary for very high volumes in the future.
Change Log
| Change | Date | Version | Description | Author |
|---|---|---|---|---|
| Initial draft | YYYY-MM-DD | 0.1 | Initial draft | {Agent/Person} |
| ... | ... | ... | ... | ... |