Phase 1 & 2: Authentication and Children Management
Completed Features:
- Full JWT authentication system with refresh tokens
- User registration and login with device fingerprinting
- Child profile CRUD operations with permission-based access
- Family management with roles and permissions
- Database migrations for core auth and family structure
- Comprehensive test coverage (37 unit + E2E tests)
Tech Stack:
- NestJS backend with TypeORM
- PostgreSQL database
- JWT authentication with Passport
- bcrypt password hashing
- Docker Compose for infrastructure
🤖 Generated with Claude Code
This commit is contained in:
551
docs/maternal-app-ai-context.md
Normal file
551
docs/maternal-app-ai-context.md
Normal file
@@ -0,0 +1,551 @@
|
||||
# AI Context & Prompting Templates - Maternal Organization App
|
||||
|
||||
## LangChain Configuration
|
||||
|
||||
### Core Setup
|
||||
```typescript
|
||||
// services/ai/langchainConfig.ts
|
||||
import { ChatOpenAI } from 'langchain/chat_models/openai';
|
||||
import { ConversationSummaryMemory } from 'langchain/memory';
|
||||
import { PromptTemplate } from 'langchain/prompts';
|
||||
import { LLMChain } from 'langchain/chains';
|
||||
|
||||
export const initializeLangChain = () => {
|
||||
const model = new ChatOpenAI({
|
||||
modelName: 'gpt-4-turbo-preview',
|
||||
temperature: 0.7,
|
||||
maxTokens: 1000,
|
||||
openAIApiKey: process.env.OPENAI_API_KEY,
|
||||
callbacks: [
|
||||
{
|
||||
handleLLMStart: async (llm, prompts) => {
|
||||
logger.info('LLM request started', { promptLength: prompts[0].length });
|
||||
},
|
||||
handleLLMEnd: async (output) => {
|
||||
logger.info('LLM request completed', { tokensUsed: output.llmOutput?.tokenUsage });
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const memory = new ConversationSummaryMemory({
|
||||
memoryKey: 'chat_history',
|
||||
llm: model,
|
||||
maxTokenLimit: 2000,
|
||||
});
|
||||
|
||||
return { model, memory };
|
||||
};
|
||||
```
|
||||
|
||||
### Context Window Management
|
||||
```typescript
|
||||
class ContextManager {
|
||||
private maxContextTokens = 4000;
|
||||
private priorityWeights = {
|
||||
currentQuery: 1.0,
|
||||
recentActivities: 0.8,
|
||||
childProfile: 0.7,
|
||||
historicalPatterns: 0.6,
|
||||
generalGuidelines: 0.4,
|
||||
};
|
||||
|
||||
async buildContext(
|
||||
query: string,
|
||||
childId: string,
|
||||
userId: string
|
||||
): Promise<AIContext> {
|
||||
const contexts = await Promise.all([
|
||||
this.getChildProfile(childId),
|
||||
this.getRecentActivities(childId, 48), // Last 48 hours
|
||||
this.getPatterns(childId),
|
||||
this.getParentPreferences(userId),
|
||||
this.getPreviousConversation(userId, childId),
|
||||
]);
|
||||
|
||||
return this.prioritizeContext(contexts, query);
|
||||
}
|
||||
|
||||
private prioritizeContext(
|
||||
contexts: ContextPart[],
|
||||
query: string
|
||||
): AIContext {
|
||||
// Token counting
|
||||
let currentTokens = this.countTokens(query);
|
||||
const prioritizedContexts: ContextPart[] = [];
|
||||
|
||||
// Sort by relevance and priority
|
||||
const sorted = contexts
|
||||
.map(ctx => ({
|
||||
...ctx,
|
||||
score: this.calculateRelevance(ctx, query) * this.priorityWeights[ctx.type],
|
||||
}))
|
||||
.sort((a, b) => b.score - a.score);
|
||||
|
||||
// Add contexts until token limit
|
||||
for (const context of sorted) {
|
||||
const tokens = this.countTokens(context.content);
|
||||
if (currentTokens + tokens <= this.maxContextTokens) {
|
||||
prioritizedContexts.push(context);
|
||||
currentTokens += tokens;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
query,
|
||||
contexts: prioritizedContexts,
|
||||
totalTokens: currentTokens,
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## System Prompts
|
||||
|
||||
### Base System Prompt
|
||||
```typescript
|
||||
const BASE_SYSTEM_PROMPT = `You are a knowledgeable, empathetic AI assistant helping parents care for their children aged 0-6 years.
|
||||
|
||||
Core Guidelines:
|
||||
1. SAFETY FIRST: Never provide medical diagnoses. Always recommend consulting healthcare providers for medical concerns.
|
||||
2. EVIDENCE-BASED: Provide advice based on pediatric best practices and research.
|
||||
3. PARENT-SUPPORTIVE: Be encouraging and non-judgmental. Every family is different.
|
||||
4. PRACTICAL: Give actionable, realistic suggestions that work for busy parents.
|
||||
5. CULTURALLY AWARE: Respect diverse parenting approaches and cultural practices.
|
||||
|
||||
You have access to:
|
||||
- The child's recent activity data (feeding, sleep, diapers)
|
||||
- Developmental milestones for their age
|
||||
- Pattern analysis from their historical data
|
||||
- Family preferences and routines
|
||||
|
||||
Response Guidelines:
|
||||
- Keep responses concise (under 150 words unless asked for detail)
|
||||
- Use simple, clear language (avoid medical jargon)
|
||||
- Provide specific, actionable suggestions
|
||||
- Acknowledge parent concerns with empathy
|
||||
- Include relevant safety warnings when appropriate`;
|
||||
```
|
||||
|
||||
### Child-Specific Context Template
|
||||
```typescript
|
||||
const CHILD_CONTEXT_TEMPLATE = `Child Profile:
|
||||
- Name: {childName}
|
||||
- Age: {ageInMonths} months ({ageInYears} years)
|
||||
- Developmental Stage: {developmentalStage}
|
||||
- Known Conditions: {medicalConditions}
|
||||
- Allergies: {allergies}
|
||||
|
||||
Recent Patterns (last 7 days):
|
||||
- Average sleep: {avgSleepHours} hours/day
|
||||
- Feeding frequency: Every {feedingInterval} hours
|
||||
- Growth trajectory: {growthPercentile} percentile
|
||||
|
||||
Current Concerns:
|
||||
{parentConcerns}
|
||||
|
||||
Recent Activities (last 24 hours):
|
||||
{recentActivities}`;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prompt Templates by Scenario
|
||||
|
||||
### Sleep-Related Queries
|
||||
```typescript
|
||||
const SLEEP_PROMPT = PromptTemplate.fromTemplate(`
|
||||
${BASE_SYSTEM_PROMPT}
|
||||
|
||||
Context:
|
||||
{childContext}
|
||||
|
||||
Sleep-Specific Data:
|
||||
- Recent bedtimes: {recentBedtimes}
|
||||
- Wake windows today: {wakeWindows}
|
||||
- Nap schedule: {napSchedule}
|
||||
- Sleep regression risk: {regressionRisk}
|
||||
|
||||
Parent Question: {question}
|
||||
|
||||
Provide practical sleep advice considering:
|
||||
1. Age-appropriate wake windows
|
||||
2. Recent sleep patterns
|
||||
3. Common sleep regressions at this age
|
||||
4. Environmental factors
|
||||
|
||||
Response:
|
||||
`);
|
||||
```
|
||||
|
||||
### Feeding Queries
|
||||
```typescript
|
||||
const FEEDING_PROMPT = PromptTemplate.fromTemplate(`
|
||||
${BASE_SYSTEM_PROMPT}
|
||||
|
||||
Context:
|
||||
{childContext}
|
||||
|
||||
Feeding-Specific Data:
|
||||
- Feeding type: {feedingType}
|
||||
- Recent intake: {recentIntake}
|
||||
- Growth trend: {growthTrend}
|
||||
- Solid foods status: {solidsStatus}
|
||||
|
||||
Parent Question: {question}
|
||||
|
||||
Provide feeding guidance considering:
|
||||
1. Age-appropriate feeding amounts
|
||||
2. Growth patterns
|
||||
3. Feeding milestones
|
||||
4. Any mentioned concerns
|
||||
|
||||
Response:
|
||||
`);
|
||||
```
|
||||
|
||||
### Developmental Milestones
|
||||
```typescript
|
||||
const MILESTONE_PROMPT = PromptTemplate.fromTemplate(`
|
||||
${BASE_SYSTEM_PROMPT}
|
||||
|
||||
Context:
|
||||
{childContext}
|
||||
|
||||
Developmental Data:
|
||||
- Expected milestones: {expectedMilestones}
|
||||
- Achieved milestones: {achievedMilestones}
|
||||
- Areas of focus: {developmentalFocus}
|
||||
|
||||
Parent Question: {question}
|
||||
|
||||
Provide developmental guidance:
|
||||
1. What's typical for this age
|
||||
2. Activities to encourage development
|
||||
3. When to consult professionals
|
||||
4. Celebrate achievements while avoiding comparison
|
||||
|
||||
Response:
|
||||
`);
|
||||
```
|
||||
|
||||
### Behavioral Concerns
|
||||
```typescript
|
||||
const BEHAVIOR_PROMPT = PromptTemplate.fromTemplate(`
|
||||
${BASE_SYSTEM_PROMPT}
|
||||
|
||||
Context:
|
||||
{childContext}
|
||||
|
||||
Behavioral Patterns:
|
||||
- Recent behaviors: {recentBehaviors}
|
||||
- Triggers identified: {triggers}
|
||||
- Sleep/hunger status: {physiologicalState}
|
||||
|
||||
Parent Question: {question}
|
||||
|
||||
Provide behavioral guidance:
|
||||
1. Age-appropriate expectations
|
||||
2. Positive parenting strategies
|
||||
3. Understanding underlying needs
|
||||
4. Consistency and routine importance
|
||||
|
||||
Response:
|
||||
`);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Safety Boundaries
|
||||
|
||||
### Medical Disclaimer Triggers
|
||||
```typescript
|
||||
const MEDICAL_TRIGGERS = [
|
||||
'diagnose', 'disease', 'syndrome', 'disorder',
|
||||
'medication', 'dosage', 'prescription',
|
||||
'emergency', 'urgent', 'bleeding', 'unconscious',
|
||||
'seizure', 'fever over 104', 'difficulty breathing',
|
||||
];
|
||||
|
||||
const MEDICAL_DISCLAIMER = `I understand you're concerned about {concern}. This seems like a medical issue that requires professional evaluation. Please contact your pediatrician or healthcare provider immediately. If this is an emergency, call your local emergency number.
|
||||
|
||||
For reference, here are signs requiring immediate medical attention:
|
||||
- Difficulty breathing or bluish skin
|
||||
- Unresponsiveness or difficulty waking
|
||||
- High fever (over 104°F/40°C)
|
||||
- Severe dehydration
|
||||
- Head injury with vomiting or confusion`;
|
||||
```
|
||||
|
||||
### Mental Health Support
|
||||
```typescript
|
||||
const MENTAL_HEALTH_PROMPT = `I hear that you're going through a difficult time. Your feelings are valid and important.
|
||||
|
||||
Here are some immediate resources:
|
||||
- Postpartum Support International: 1-800-4-PPD-MOMS
|
||||
- Crisis Text Line: Text HOME to 741741
|
||||
- Local support groups: {localResources}
|
||||
|
||||
Please consider reaching out to:
|
||||
- Your healthcare provider
|
||||
- A mental health professional
|
||||
- Trusted family or friends
|
||||
|
||||
Remember: Seeking help is a sign of strength, not weakness. Your wellbeing matters for both you and your baby.`;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response Formatting
|
||||
|
||||
### Structured Response Template
|
||||
```typescript
|
||||
interface AIResponse {
|
||||
mainAnswer: string;
|
||||
keyPoints?: string[];
|
||||
actionItems?: string[];
|
||||
safetyNotes?: string[];
|
||||
relatedResources?: Resource[];
|
||||
confidenceLevel: 'high' | 'medium' | 'low';
|
||||
shouldEscalate: boolean;
|
||||
}
|
||||
|
||||
const formatResponse = (raw: string, metadata: ResponseMetadata): AIResponse => {
|
||||
return {
|
||||
mainAnswer: extractMainAnswer(raw),
|
||||
keyPoints: extractBulletPoints(raw),
|
||||
actionItems: extractActionItems(raw),
|
||||
safetyNotes: extractSafetyWarnings(raw),
|
||||
relatedResources: findRelevantResources(metadata),
|
||||
confidenceLevel: calculateConfidence(metadata),
|
||||
shouldEscalate: checkEscalationTriggers(raw),
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Localized Response Generation
|
||||
```typescript
|
||||
const LOCALIZED_PROMPTS = {
|
||||
'en-US': {
|
||||
greeting: "I understand your concern about {topic}.",
|
||||
transition: "Based on {childName}'s patterns,",
|
||||
closing: "Remember, every baby is different.",
|
||||
},
|
||||
'es-ES': {
|
||||
greeting: "Entiendo tu preocupación sobre {topic}.",
|
||||
transition: "Basándome en los patrones de {childName},",
|
||||
closing: "Recuerda, cada bebé es diferente.",
|
||||
},
|
||||
'fr-FR': {
|
||||
greeting: "Je comprends votre inquiétude concernant {topic}.",
|
||||
transition: "D'après les habitudes de {childName},",
|
||||
closing: "Rappelez-vous, chaque bébé est unique.",
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Personalization Engine
|
||||
|
||||
### Learning from Feedback
|
||||
```typescript
|
||||
class PersonalizationEngine {
|
||||
async updateResponsePreferences(
|
||||
userId: string,
|
||||
feedback: UserFeedback
|
||||
) {
|
||||
const preferences = await this.getUserPreferences(userId);
|
||||
|
||||
// Update preference weights
|
||||
if (feedback.helpful) {
|
||||
preferences.preferredResponseLength = feedback.responseLength;
|
||||
preferences.preferredDetailLevel = feedback.detailLevel;
|
||||
preferences.preferredTone = feedback.tone;
|
||||
}
|
||||
|
||||
// Learn from negative feedback
|
||||
if (!feedback.helpful && feedback.reason) {
|
||||
this.adjustPromptTemplate(preferences, feedback.reason);
|
||||
}
|
||||
|
||||
await this.saveUserPreferences(userId, preferences);
|
||||
}
|
||||
|
||||
private adjustPromptTemplate(
|
||||
preferences: UserPreferences,
|
||||
reason: string
|
||||
): PromptTemplate {
|
||||
const adjustments = {
|
||||
'too_technical': { jargonLevel: 'minimal', explanationStyle: 'simple' },
|
||||
'too_general': { specificityLevel: 'high', includeExamples: true },
|
||||
'too_long': { maxLength: 100, bulletPoints: true },
|
||||
'not_actionable': { focusOnActions: true, includeSteps: true },
|
||||
};
|
||||
|
||||
return this.applyAdjustments(preferences, adjustments[reason]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chain of Thought for Complex Queries
|
||||
|
||||
### Multi-Step Reasoning
|
||||
```typescript
|
||||
const COMPLEX_REASONING_PROMPT = `Let me analyze this step-by-step:
|
||||
|
||||
Step 1: Understanding the Situation
|
||||
{situationAnalysis}
|
||||
|
||||
Step 2: Identifying Patterns
|
||||
Looking at {childName}'s recent data:
|
||||
{patternAnalysis}
|
||||
|
||||
Step 3: Considering Age-Appropriate Norms
|
||||
For a {ageInMonths}-month-old:
|
||||
{developmentalNorms}
|
||||
|
||||
Step 4: Practical Recommendations
|
||||
Based on the above:
|
||||
{recommendations}
|
||||
|
||||
Step 5: What to Monitor
|
||||
Keep track of:
|
||||
{monitoringPoints}`;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conversation Memory Management
|
||||
|
||||
### Memory Summarization
|
||||
```typescript
|
||||
class ConversationMemory {
|
||||
private maxConversationLength = 10;
|
||||
|
||||
async summarizeConversation(
|
||||
messages: Message[],
|
||||
childId: string
|
||||
): Promise<string> {
|
||||
if (messages.length <= 3) {
|
||||
return messages.map(m => m.content).join('\n');
|
||||
}
|
||||
|
||||
const summary = await this.llm.summarize({
|
||||
messages,
|
||||
focusPoints: [
|
||||
'Main concerns discussed',
|
||||
'Advice given',
|
||||
'Action items suggested',
|
||||
'Follow-up needed',
|
||||
],
|
||||
});
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
async getRelevantHistory(
|
||||
userId: string,
|
||||
childId: string,
|
||||
currentQuery: string
|
||||
): Promise<string> {
|
||||
const history = await this.fetchHistory(userId, childId);
|
||||
|
||||
// Semantic search for relevant past conversations
|
||||
const relevant = await this.semanticSearch(history, currentQuery);
|
||||
|
||||
return this.formatHistory(relevant);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prompt Injection Protection
|
||||
|
||||
### Security Filters
|
||||
```typescript
|
||||
const INJECTION_PATTERNS = [
|
||||
/ignore previous instructions/i,
|
||||
/system:/i,
|
||||
/admin mode/i,
|
||||
/bypass safety/i,
|
||||
/pretend you are/i,
|
||||
];
|
||||
|
||||
const sanitizeUserInput = (input: string): string => {
|
||||
// Check for injection attempts
|
||||
for (const pattern of INJECTION_PATTERNS) {
|
||||
if (pattern.test(input)) {
|
||||
logger.warn('Potential prompt injection detected', { input });
|
||||
return 'Please ask a question about childcare.';
|
||||
}
|
||||
}
|
||||
|
||||
// Escape special characters
|
||||
return input
|
||||
.replace(/[<>]/g, '')
|
||||
.substring(0, 500); // Limit length
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Prompt Effectiveness
|
||||
|
||||
### Prompt Evaluation Metrics
|
||||
```typescript
|
||||
interface PromptMetrics {
|
||||
relevance: number; // 0-1: Response answers the question
|
||||
safety: number; // 0-1: Appropriate medical disclaimers
|
||||
actionability: number; // 0-1: Practical suggestions provided
|
||||
empathy: number; // 0-1: Supportive tone
|
||||
accuracy: number; // 0-1: Factually correct
|
||||
}
|
||||
|
||||
const evaluatePromptResponse = async (
|
||||
prompt: string,
|
||||
response: string,
|
||||
expectedQualities: PromptMetrics
|
||||
): Promise<EvaluationResult> => {
|
||||
const evaluation = await this.evaluatorLLM.evaluate({
|
||||
prompt,
|
||||
response,
|
||||
criteria: expectedQualities,
|
||||
});
|
||||
|
||||
return {
|
||||
passed: evaluation.overall > 0.8,
|
||||
metrics: evaluation,
|
||||
suggestions: evaluation.improvements,
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Test Cases
|
||||
```typescript
|
||||
const promptTestCases = [
|
||||
{
|
||||
scenario: 'Sleep regression concern',
|
||||
input: 'My 4-month-old suddenly won\'t sleep',
|
||||
expectedResponse: {
|
||||
containsMention: ['4-month sleep regression', 'normal', 'temporary'],
|
||||
includesActions: ['consistent bedtime', 'wake windows'],
|
||||
avoidsMedical: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
scenario: 'Feeding amount worry',
|
||||
input: 'Is 4oz enough for my 2-month-old?',
|
||||
expectedResponse: {
|
||||
containsMention: ['varies by baby', 'weight gain', 'wet diapers'],
|
||||
includesActions: ['track intake', 'consult pediatrician'],
|
||||
providesRanges: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
```
|
||||
939
docs/maternal-app-api-spec.md
Normal file
939
docs/maternal-app-api-spec.md
Normal file
@@ -0,0 +1,939 @@
|
||||
# API Specification Document - Maternal Organization App
|
||||
|
||||
## API Architecture Overview
|
||||
|
||||
### Base Configuration
|
||||
- **Base URL**: `https://api.{domain}/api/v1`
|
||||
- **GraphQL Endpoint**: `https://api.{domain}/graphql`
|
||||
- **WebSocket**: `wss://api.{domain}/ws`
|
||||
- **API Style**: Hybrid (REST for CRUD, GraphQL for complex queries)
|
||||
- **Versioning**: URL path versioning (`/api/v1/`)
|
||||
- **Rate Limiting**: 100 requests/minute per user
|
||||
- **Pagination**: Cursor-based with consistent structure
|
||||
|
||||
### Standard Headers
|
||||
```http
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
Accept-Language: en-US,en;q=0.9
|
||||
X-Client-Version: 1.0.0
|
||||
X-Device-ID: uuid-device-fingerprint
|
||||
X-Timezone: America/New_York
|
||||
Authorization: Bearer {access_token}
|
||||
X-Refresh-Token: {refresh_token}
|
||||
```
|
||||
|
||||
### Device Fingerprinting
|
||||
```json
|
||||
{
|
||||
"deviceId": "uuid",
|
||||
"platform": "ios|android",
|
||||
"model": "iPhone14,2",
|
||||
"osVersion": "16.5",
|
||||
"appVersion": "1.0.0",
|
||||
"pushToken": "fcm_or_apns_token"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication Endpoints
|
||||
|
||||
### POST `/api/v1/auth/register`
|
||||
Create new user account with family setup.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "SecurePass123!",
|
||||
"phone": "+1234567890",
|
||||
"name": "Jane Doe",
|
||||
"locale": "en-US",
|
||||
"timezone": "America/New_York",
|
||||
"deviceInfo": {
|
||||
"deviceId": "uuid",
|
||||
"platform": "ios",
|
||||
"model": "iPhone14,2",
|
||||
"osVersion": "16.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": {
|
||||
"id": "usr_2n4k8m9p",
|
||||
"email": "user@example.com",
|
||||
"name": "Jane Doe",
|
||||
"locale": "en-US",
|
||||
"emailVerified": false
|
||||
},
|
||||
"family": {
|
||||
"id": "fam_7h3j9k2m",
|
||||
"shareCode": "ABC123",
|
||||
"role": "parent"
|
||||
},
|
||||
"tokens": {
|
||||
"accessToken": "eyJhbGc...",
|
||||
"refreshToken": "eyJhbGc...",
|
||||
"expiresIn": 3600
|
||||
},
|
||||
"deviceRegistered": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/auth/login`
|
||||
Authenticate existing user with device registration.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "SecurePass123!",
|
||||
"deviceInfo": {
|
||||
"deviceId": "uuid",
|
||||
"platform": "ios",
|
||||
"model": "iPhone14,2",
|
||||
"osVersion": "16.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": {
|
||||
"id": "usr_2n4k8m9p",
|
||||
"email": "user@example.com",
|
||||
"families": ["fam_7h3j9k2m"]
|
||||
},
|
||||
"tokens": {
|
||||
"accessToken": "eyJhbGc...",
|
||||
"refreshToken": "eyJhbGc...",
|
||||
"expiresIn": 3600
|
||||
},
|
||||
"requiresMFA": false,
|
||||
"deviceTrusted": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/auth/refresh`
|
||||
Refresh access token using refresh token.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"refreshToken": "eyJhbGc...",
|
||||
"deviceId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"accessToken": "eyJhbGc...",
|
||||
"refreshToken": "eyJhbGc...",
|
||||
"expiresIn": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/auth/logout`
|
||||
Logout and revoke tokens for specific device.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"deviceId": "uuid",
|
||||
"allDevices": false
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Successfully logged out"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Family Management Endpoints
|
||||
|
||||
### POST `/api/v1/families/invite`
|
||||
Generate invitation for family member.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"email": "partner@example.com",
|
||||
"role": "parent|caregiver|viewer",
|
||||
"permissions": {
|
||||
"canAddChildren": true,
|
||||
"canEditChildren": true,
|
||||
"canLogActivities": true,
|
||||
"canViewReports": true
|
||||
},
|
||||
"message": "Join our family on the app!"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"invitationId": "inv_8k3m9n2p",
|
||||
"shareCode": "XYZ789",
|
||||
"expiresAt": "2024-01-15T00:00:00Z",
|
||||
"invitationUrl": "app://join/XYZ789"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/families/join`
|
||||
Join family using share code.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"shareCode": "XYZ789"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"familyId": "fam_7h3j9k2m",
|
||||
"familyName": "The Doe Family",
|
||||
"role": "parent",
|
||||
"members": [
|
||||
{
|
||||
"id": "usr_2n4k8m9p",
|
||||
"name": "Jane Doe",
|
||||
"role": "parent"
|
||||
}
|
||||
],
|
||||
"children": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/families/{familyId}/members`
|
||||
Get all family members with their permissions.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"members": [
|
||||
{
|
||||
"id": "usr_2n4k8m9p",
|
||||
"name": "Jane Doe",
|
||||
"email": "jane@example.com",
|
||||
"role": "parent",
|
||||
"permissions": {
|
||||
"canAddChildren": true,
|
||||
"canEditChildren": true,
|
||||
"canLogActivities": true,
|
||||
"canViewReports": true
|
||||
},
|
||||
"joinedAt": "2024-01-01T00:00:00Z",
|
||||
"lastActive": "2024-01-10T15:30:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Children Management Endpoints
|
||||
|
||||
### POST `/api/v1/children`
|
||||
Add a new child to the family.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"familyId": "fam_7h3j9k2m",
|
||||
"name": "Emma",
|
||||
"birthDate": "2023-06-15",
|
||||
"gender": "female",
|
||||
"bloodType": "O+",
|
||||
"allergies": ["peanuts", "dairy"],
|
||||
"medicalConditions": ["eczema"],
|
||||
"pediatrician": {
|
||||
"name": "Dr. Smith",
|
||||
"phone": "+1234567890"
|
||||
},
|
||||
"photo": "base64_encoded_image"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "chd_9m2k4n8p",
|
||||
"familyId": "fam_7h3j9k2m",
|
||||
"name": "Emma",
|
||||
"birthDate": "2023-06-15",
|
||||
"ageInMonths": 7,
|
||||
"developmentalStage": "infant",
|
||||
"photoUrl": "https://storage.api/photos/chd_9m2k4n8p.jpg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/children/{childId}`
|
||||
Get child details with calculated metrics.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "chd_9m2k4n8p",
|
||||
"name": "Emma",
|
||||
"birthDate": "2023-06-15",
|
||||
"ageInMonths": 7,
|
||||
"developmentalStage": "infant",
|
||||
"currentWeight": {
|
||||
"value": 8.2,
|
||||
"unit": "kg",
|
||||
"percentile": 75,
|
||||
"recordedAt": "2024-01-10T10:00:00Z"
|
||||
},
|
||||
"currentHeight": {
|
||||
"value": 68,
|
||||
"unit": "cm",
|
||||
"percentile": 80,
|
||||
"recordedAt": "2024-01-10T10:00:00Z"
|
||||
},
|
||||
"todaySummary": {
|
||||
"feedings": 5,
|
||||
"sleepHours": 14.5,
|
||||
"diapers": 6,
|
||||
"lastFeedingAt": "2024-01-10T14:30:00Z",
|
||||
"lastSleepAt": "2024-01-10T13:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Activity Tracking Endpoints (REST)
|
||||
|
||||
### POST `/api/v1/activities/feeding`
|
||||
Log a feeding activity.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"type": "breast|bottle|solid",
|
||||
"startTime": "2024-01-10T14:30:00Z",
|
||||
"endTime": "2024-01-10T14:45:00Z",
|
||||
"details": {
|
||||
"breastSide": "left|right|both",
|
||||
"amount": 120,
|
||||
"unit": "ml|oz",
|
||||
"foodType": "formula|breastmilk|puree"
|
||||
},
|
||||
"notes": "Good feeding session",
|
||||
"mood": "happy|fussy|sleepy"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 201:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "act_3k9n2m4p",
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"type": "feeding",
|
||||
"timestamp": "2024-01-10T14:30:00Z",
|
||||
"duration": 15,
|
||||
"createdBy": "usr_2n4k8m9p",
|
||||
"syncedToFamily": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/activities/sleep`
|
||||
Log sleep activity.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"startTime": "2024-01-10T13:00:00Z",
|
||||
"endTime": "2024-01-10T14:30:00Z",
|
||||
"type": "nap|night",
|
||||
"location": "crib|stroller|car|bed",
|
||||
"quality": "good|restless|interrupted",
|
||||
"notes": "Went down easily"
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/activities/diaper`
|
||||
Log diaper change.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"timestamp": "2024-01-10T15:00:00Z",
|
||||
"type": "wet|dirty|both",
|
||||
"consistency": "normal|loose|hard",
|
||||
"color": "normal|green|yellow",
|
||||
"hasRash": false,
|
||||
"notes": "Applied diaper cream"
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/activities`
|
||||
Get activities with cursor pagination.
|
||||
|
||||
**Query Parameters:**
|
||||
- `childId`: Filter by child (required)
|
||||
- `type`: Filter by activity type
|
||||
- `startDate`: ISO date string
|
||||
- `endDate`: ISO date string
|
||||
- `cursor`: Pagination cursor
|
||||
- `limit`: Items per page (default: 20, max: 100)
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"activities": [
|
||||
{
|
||||
"id": "act_3k9n2m4p",
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"type": "feeding",
|
||||
"timestamp": "2024-01-10T14:30:00Z",
|
||||
"details": {},
|
||||
"createdBy": "usr_2n4k8m9p"
|
||||
}
|
||||
],
|
||||
"cursor": {
|
||||
"next": "eyJpZCI6ImFjdF8za...",
|
||||
"hasMore": true,
|
||||
"total": 150
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI Assistant Endpoints
|
||||
|
||||
### POST `/api/v1/ai/chat`
|
||||
Send message to AI assistant.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"message": "Why won't my baby sleep?",
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"conversationId": "conv_8n2k4m9p",
|
||||
"context": {
|
||||
"includeRecentActivities": true,
|
||||
"includeSleepPatterns": true,
|
||||
"includeDevelopmentalInfo": true
|
||||
},
|
||||
"locale": "en-US"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"conversationId": "conv_8n2k4m9p",
|
||||
"messageId": "msg_7k3n9m2p",
|
||||
"response": "Based on Emma's recent sleep patterns...",
|
||||
"suggestions": [
|
||||
"Try starting bedtime routine 15 minutes earlier",
|
||||
"Check room temperature (ideal: 68-72°F)"
|
||||
],
|
||||
"relatedArticles": [
|
||||
{
|
||||
"title": "7-Month Sleep Regression",
|
||||
"url": "/resources/sleep-regression-7-months"
|
||||
}
|
||||
],
|
||||
"confidenceScore": 0.92
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/ai/voice`
|
||||
Process voice command.
|
||||
|
||||
**Request Body (multipart/form-data):**
|
||||
```
|
||||
audio: [audio file - wav/mp3]
|
||||
childId: chd_9m2k4n8p
|
||||
locale: en-US
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"transcription": "Baby fed 4 ounces at 3pm",
|
||||
"interpretation": {
|
||||
"action": "log_feeding",
|
||||
"childId": "chd_9m2k4n8p",
|
||||
"parameters": {
|
||||
"amount": 4,
|
||||
"unit": "oz",
|
||||
"time": "15:00"
|
||||
}
|
||||
},
|
||||
"executed": true,
|
||||
"activityId": "act_9k2m4n3p"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Analytics & Insights Endpoints
|
||||
|
||||
### GET `/api/v1/insights/{childId}/patterns`
|
||||
Get AI-detected patterns for a child.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"sleepPatterns": {
|
||||
"averageNightSleep": 10.5,
|
||||
"averageDaySleep": 3.5,
|
||||
"optimalBedtime": "19:30",
|
||||
"wakeWindows": [90, 120, 150, 180],
|
||||
"trend": "improving",
|
||||
"insights": [
|
||||
"Emma sleeps 45 minutes longer when put down before 7:30 PM",
|
||||
"Morning wake time is consistently between 6:30-7:00 AM"
|
||||
]
|
||||
},
|
||||
"feedingPatterns": {
|
||||
"averageIntake": 28,
|
||||
"feedingIntervals": [2.5, 3, 3, 4],
|
||||
"preferredSide": "left",
|
||||
"insights": [
|
||||
"Feeding intervals increasing - may be ready for longer stretches"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/insights/{childId}/predictions`
|
||||
Get predictive suggestions.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"nextNapTime": {
|
||||
"predicted": "2024-01-10T16:30:00Z",
|
||||
"confidence": 0.85,
|
||||
"wakeWindow": 120
|
||||
},
|
||||
"nextFeedingTime": {
|
||||
"predicted": "2024-01-10T17:30:00Z",
|
||||
"confidence": 0.78
|
||||
},
|
||||
"growthSpurt": {
|
||||
"likelihood": 0.72,
|
||||
"expectedIn": "5-7 days",
|
||||
"symptoms": ["increased feeding", "fussiness", "disrupted sleep"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GraphQL Queries for Complex Data
|
||||
|
||||
### GraphQL Endpoint
|
||||
`POST https://api.{domain}/graphql`
|
||||
|
||||
### Family Dashboard Query
|
||||
```graphql
|
||||
query FamilyDashboard($familyId: ID!, $date: Date!) {
|
||||
family(id: $familyId) {
|
||||
id
|
||||
name
|
||||
children {
|
||||
id
|
||||
name
|
||||
age
|
||||
todaySummary(date: $date) {
|
||||
feedings {
|
||||
count
|
||||
totalAmount
|
||||
lastAt
|
||||
}
|
||||
sleep {
|
||||
totalHours
|
||||
naps
|
||||
nightSleep
|
||||
currentStatus
|
||||
}
|
||||
diapers {
|
||||
count
|
||||
lastAt
|
||||
}
|
||||
}
|
||||
upcomingEvents {
|
||||
type
|
||||
scheduledFor
|
||||
description
|
||||
}
|
||||
aiInsights {
|
||||
message
|
||||
priority
|
||||
actionable
|
||||
}
|
||||
}
|
||||
members {
|
||||
id
|
||||
name
|
||||
lastActive
|
||||
recentActivities(limit: 5) {
|
||||
type
|
||||
childName
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Weekly Report Query
|
||||
```graphql
|
||||
query WeeklyReport($childId: ID!, $startDate: Date!, $endDate: Date!) {
|
||||
child(id: $childId) {
|
||||
weeklyReport(startDate: $startDate, endDate: $endDate) {
|
||||
sleep {
|
||||
dailyAverages {
|
||||
date
|
||||
nightHours
|
||||
napHours
|
||||
totalHours
|
||||
}
|
||||
patterns {
|
||||
consistentBedtime
|
||||
averageWakeTime
|
||||
longestStretch
|
||||
}
|
||||
}
|
||||
feeding {
|
||||
dailyTotals {
|
||||
date
|
||||
numberOfFeedings
|
||||
totalVolume
|
||||
}
|
||||
trends {
|
||||
direction
|
||||
averageInterval
|
||||
}
|
||||
}
|
||||
growth {
|
||||
measurements {
|
||||
date
|
||||
weight
|
||||
height
|
||||
percentiles
|
||||
}
|
||||
}
|
||||
milestones {
|
||||
achieved {
|
||||
name
|
||||
achievedAt
|
||||
}
|
||||
upcoming {
|
||||
name
|
||||
expectedBy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WebSocket Events
|
||||
|
||||
### Connection
|
||||
```javascript
|
||||
// Client connects with auth
|
||||
ws.connect('wss://api.{domain}/ws', {
|
||||
headers: {
|
||||
'Authorization': 'Bearer {access_token}',
|
||||
'X-Device-ID': 'uuid'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Family Room Events
|
||||
```javascript
|
||||
// Join family room
|
||||
ws.emit('join-family', { familyId: 'fam_7h3j9k2m' });
|
||||
|
||||
// Activity logged by family member
|
||||
ws.on('activity-logged', {
|
||||
activityId: 'act_3k9n2m4p',
|
||||
childId: 'chd_9m2k4n8p',
|
||||
type: 'feeding',
|
||||
loggedBy: 'usr_2n4k8m9p',
|
||||
timestamp: '2024-01-10T14:30:00Z'
|
||||
});
|
||||
|
||||
// Real-time timer sync
|
||||
ws.on('timer-started', {
|
||||
timerId: 'tmr_8k3m9n2p',
|
||||
type: 'feeding',
|
||||
childId: 'chd_9m2k4n8p',
|
||||
startedBy: 'usr_2n4k8m9p',
|
||||
startTime: '2024-01-10T14:30:00Z'
|
||||
});
|
||||
|
||||
// AI insight generated
|
||||
ws.on('insight-available', {
|
||||
childId: 'chd_9m2k4n8p',
|
||||
type: 'pattern_detected',
|
||||
message: 'New sleep pattern identified',
|
||||
priority: 'medium'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
### Standard Error Format
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "Invalid input data",
|
||||
"details": {
|
||||
"field": "email",
|
||||
"reason": "Invalid email format"
|
||||
},
|
||||
"timestamp": "2024-01-10T15:30:00Z",
|
||||
"traceId": "trace_8k3m9n2p"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Codes
|
||||
| Code | HTTP Status | Description |
|
||||
|------|------------|-------------|
|
||||
| `UNAUTHORIZED` | 401 | Invalid or expired token |
|
||||
| `FORBIDDEN` | 403 | Insufficient permissions |
|
||||
| `NOT_FOUND` | 404 | Resource not found |
|
||||
| `VALIDATION_ERROR` | 400 | Invalid input data |
|
||||
| `RATE_LIMITED` | 429 | Too many requests |
|
||||
| `FAMILY_FULL` | 400 | Family member limit reached |
|
||||
| `CHILD_LIMIT` | 400 | Free tier child limit reached |
|
||||
| `AI_QUOTA_EXCEEDED` | 429 | AI query limit reached |
|
||||
| `SYNC_CONFLICT` | 409 | Data sync conflict |
|
||||
| `SERVER_ERROR` | 500 | Internal server error |
|
||||
|
||||
### Rate Limit Headers
|
||||
```http
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 45
|
||||
X-RateLimit-Reset: 1704903000
|
||||
Retry-After: 3600
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Localization
|
||||
|
||||
### Supported Locales
|
||||
- `en-US` - English (United States)
|
||||
- `es-ES` - Spanish (Spain)
|
||||
- `es-MX` - Spanish (Mexico)
|
||||
- `fr-FR` - French (France)
|
||||
- `fr-CA` - French (Canada)
|
||||
- `pt-BR` - Portuguese (Brazil)
|
||||
- `zh-CN` - Chinese (Simplified)
|
||||
|
||||
### Locale-Specific Responses
|
||||
All error messages, AI responses, and notifications are returned in the user's selected locale based on the `Accept-Language` header or user profile setting.
|
||||
|
||||
### Date/Time Formatting
|
||||
Dates are returned in ISO 8601 format but should be displayed according to user's locale:
|
||||
- US: MM/DD/YYYY, 12-hour clock
|
||||
- EU: DD/MM/YYYY, 24-hour clock
|
||||
- Time zones always included in responses
|
||||
|
||||
### Measurement Units
|
||||
```json
|
||||
{
|
||||
"measurement": {
|
||||
"value": 8.2,
|
||||
"unit": "kg",
|
||||
"display": "8.2 kg",
|
||||
"imperial": {
|
||||
"value": 18.08,
|
||||
"unit": "lbs",
|
||||
"display": "18 lbs 1 oz"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Authentication Flow
|
||||
1. User provides credentials + device fingerprint
|
||||
2. Server validates and issues access token (1 hour) + refresh token (30 days)
|
||||
3. Device fingerprint stored and validated on each request
|
||||
4. Refresh token rotation on use
|
||||
5. All tokens revoked on suspicious activity
|
||||
|
||||
### Data Encryption
|
||||
- All API communication over HTTPS/TLS 1.3
|
||||
- Sensitive fields encrypted at rest (AES-256)
|
||||
- PII data anonymized in logs
|
||||
- No sensitive data in URL parameters
|
||||
|
||||
### COPPA/GDPR Compliance
|
||||
- Parental consent required for child profiles
|
||||
- Data minimization enforced
|
||||
- Right to deletion implemented
|
||||
- Data portability via export endpoints
|
||||
- Audit logs for all data access
|
||||
|
||||
### Request Signing (Optional Enhanced Security)
|
||||
```http
|
||||
X-Signature: HMAC-SHA256(request-body + timestamp + nonce)
|
||||
X-Timestamp: 1704903000
|
||||
X-Nonce: unique-request-id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Endpoints
|
||||
|
||||
### Health Check
|
||||
`GET /api/v1/health`
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"version": "1.0.0",
|
||||
"timestamp": "2024-01-10T15:30:00Z",
|
||||
"services": {
|
||||
"database": "connected",
|
||||
"redis": "connected",
|
||||
"ai": "operational"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Test Notifications
|
||||
`POST /api/v1/test/notification`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"type": "test",
|
||||
"deviceId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SDK Usage Examples
|
||||
|
||||
### JavaScript/TypeScript
|
||||
```typescript
|
||||
import { MaternalAPI } from '@maternal/sdk';
|
||||
|
||||
const api = new MaternalAPI({
|
||||
baseUrl: 'https://api.maternal.app',
|
||||
version: 'v1'
|
||||
});
|
||||
|
||||
// Authentication
|
||||
const { tokens, user } = await api.auth.login({
|
||||
email: 'user@example.com',
|
||||
password: 'password',
|
||||
deviceInfo: getDeviceInfo()
|
||||
});
|
||||
|
||||
// Set tokens for subsequent requests
|
||||
api.setTokens(tokens);
|
||||
|
||||
// Log activity
|
||||
const activity = await api.activities.logFeeding({
|
||||
childId: 'chd_9m2k4n8p',
|
||||
type: 'bottle',
|
||||
amount: 120,
|
||||
unit: 'ml'
|
||||
});
|
||||
|
||||
// Subscribe to real-time updates
|
||||
api.websocket.on('activity-logged', (data) => {
|
||||
console.log('New activity:', data);
|
||||
});
|
||||
```
|
||||
|
||||
### React Native
|
||||
```typescript
|
||||
import { useMaternalAPI } from '@maternal/react-native';
|
||||
|
||||
function FeedingScreen() {
|
||||
const { logFeeding, isLoading } = useMaternalAPI();
|
||||
|
||||
const handleLogFeeding = async () => {
|
||||
await logFeeding({
|
||||
childId: currentChild.id,
|
||||
type: 'breast',
|
||||
duration: 15
|
||||
});
|
||||
};
|
||||
}
|
||||
```
|
||||
207
docs/maternal-app-dataflow.txt
Normal file
207
docs/maternal-app-dataflow.txt
Normal file
@@ -0,0 +1,207 @@
|
||||
================================================================================
|
||||
MATERNAL APP MVP - DATA FLOW ARCHITECTURE
|
||||
================================================================================
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ USER INTERFACE LAYER │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Parent 1 │ │ Parent 2 │ │ Caregiver │ │ Voice Input │ │
|
||||
│ │ (Mobile) │ │ (Mobile) │ │ (Mobile) │ │ (Whisper) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ └──────────────────┴──────────────────┴──────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────┐ │
|
||||
│ │ API Gateway (REST) │ │
|
||||
│ │ Authentication │ │
|
||||
│ │ Rate Limiting │ │
|
||||
│ │ i18n Routing │ │
|
||||
│ └───────────┬───────────┘ │
|
||||
│ │ │
|
||||
└──────────────────────────────────────┼──────────────────────────────────────┘
|
||||
│
|
||||
================================================================================
|
||||
REAL-TIME SYNC LAYER
|
||||
================================================================================
|
||||
│
|
||||
┌────────────▼────────────┐
|
||||
│ WebSocket Server │
|
||||
│ (Socket.io) │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ Event Publisher │ │
|
||||
│ └──────────────────┘ │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ Family Rooms │ │
|
||||
│ └──────────────────┘ │
|
||||
└────────────┬────────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Redis │ │ Redis │ │ Redis │
|
||||
│ Channel 1│ │ Channel 2│ │ Channel 3│
|
||||
│ (Family) │ │ (Family) │ │ (Family) │
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
│ │ │
|
||||
└─────────────────┼─────────────────┘
|
||||
│
|
||||
================================================================================
|
||||
APPLICATION SERVICE LAYER
|
||||
================================================================================
|
||||
│
|
||||
┌──────────────────────────────┼──────────────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Tracking │ │ AI Assistant │ │ Analytics │
|
||||
│ Service │ │ Service │ │ Service │
|
||||
│ │ │ │ │ │
|
||||
│ • Feeding │ │ • Chat Handler │ │ • Pattern │
|
||||
│ • Sleep │ │ • Context Mgr │ │ Detection │
|
||||
│ • Diaper │◄─────────┤ • LLM Gateway │◄─────────┤ • Predictions │
|
||||
│ • Growth │ │ • Response Gen │ │ • Insights │
|
||||
│ • Voice Process │ │ │ │ • Reports │
|
||||
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────┐ │
|
||||
│ │ LLM API Gateway │ │
|
||||
│ │ ┌────────────────┐ │ │
|
||||
│ │ │ OpenAI/Claude │ │ │
|
||||
│ │ └────────────────┘ │ │
|
||||
│ │ ┌────────────────┐ │ │
|
||||
│ │ │ Context Cache │ │ │
|
||||
│ │ └────────────────┘ │ │
|
||||
│ └───────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
================================================================================
|
||||
DATA PERSISTENCE LAYER
|
||||
================================================================================
|
||||
│
|
||||
┌───────────▼───────────┐
|
||||
│ Database Router │
|
||||
└───────────┬───────────┘
|
||||
│
|
||||
┌───────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ PostgreSQL │ │ MongoDB │ │ Redis │
|
||||
│ (Primary) │ │ (Documents) │ │ (Cache) │
|
||||
├──────────────┤ ├──────────────┤ ├──────────────┤
|
||||
│ • Users │ │ • AI Chats │ │ • Sessions │
|
||||
│ • Children │ │ • Reports │ │ • Real-time │
|
||||
│ • Activities │ │ • Analytics │ │ • Predictions│
|
||||
│ • Families │ │ • Logs │ │ • Temp Data │
|
||||
│ • Settings │ │ │ │ │
|
||||
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
||||
│ │ │
|
||||
└──────────────────────┼───────────────────────┘
|
||||
│
|
||||
================================================================================
|
||||
BACKGROUND JOBS LAYER
|
||||
================================================================================
|
||||
│
|
||||
┌─────────▼─────────┐
|
||||
│ Message Queue │
|
||||
│ (Bull) │
|
||||
└─────────┬─────────┘
|
||||
│
|
||||
┌─────────────────────┼─────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Notification │ │ ML/AI │ │ Data │
|
||||
│ Worker │ │ Worker │ │ Export │
|
||||
├──────────────┤ ├──────────────┤ ├──────────────┤
|
||||
│ • Push │ │ • Training │ │ • PDF Gen │
|
||||
│ • Email │ │ • Prediction │ │ • CSV Export │
|
||||
│ • SMS │ │ • Analysis │ │ • Backup │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
|
||||
================================================================================
|
||||
DATA FLOW PATTERNS
|
||||
================================================================================
|
||||
|
||||
1. ACTIVITY LOGGING FLOW:
|
||||
User → Mobile App → API Gateway → Tracking Service → PostgreSQL
|
||||
↓
|
||||
WebSocket Server → Redis Pub/Sub → All Family Devices
|
||||
|
||||
2. AI ASSISTANT FLOW:
|
||||
User Query → Voice/Text Input → AI Service → Context Fetch (PostgreSQL)
|
||||
↓
|
||||
LLM API → Response Generation
|
||||
↓
|
||||
MongoDB (Chat History) → User
|
||||
|
||||
3. PATTERN RECOGNITION FLOW:
|
||||
PostgreSQL Data → Analytics Service → ML Worker → Pattern Detection
|
||||
↓
|
||||
Redis Cache → Predictions
|
||||
↓
|
||||
Push Notification
|
||||
|
||||
4. REAL-TIME SYNC FLOW:
|
||||
Device A → WebSocket → Redis Channel → WebSocket → Device B
|
||||
↓
|
||||
PostgreSQL (Persistence)
|
||||
|
||||
5. OFFLINE SYNC FLOW:
|
||||
Mobile SQLite → Queue Actions → Network Available → Sync Service
|
||||
↓
|
||||
PostgreSQL
|
||||
↓
|
||||
Conflict Resolution
|
||||
↓
|
||||
Update All Devices
|
||||
|
||||
================================================================================
|
||||
SECURITY BOUNDARIES
|
||||
================================================================================
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ ENCRYPTED AT REST │
|
||||
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ END-TO-END ENCRYPTED │ │
|
||||
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ SENSITIVE USER DATA │ │ │
|
||||
│ │ │ • Child Health Records │ │ │
|
||||
│ │ │ • Personal Identifiable Information │ │ │
|
||||
│ │ │ • Location Data │ │ │
|
||||
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ENCRYPTED IN TRANSIT │ │
|
||||
│ └───────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ AUDIT LOGGING │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
================================================================================
|
||||
SCALABILITY NOTES
|
||||
================================================================================
|
||||
|
||||
• Horizontal Scaling Points:
|
||||
- API Gateway (Load Balancer)
|
||||
- WebSocket Servers (Sticky Sessions)
|
||||
- Service Layer (Kubernetes Pods)
|
||||
- Redis (Cluster Mode)
|
||||
- PostgreSQL (Read Replicas)
|
||||
|
||||
• Bottleneck Mitigation:
|
||||
- LLM API: Response caching, rate limiting
|
||||
- Database: Connection pooling, query optimization
|
||||
- Real-time: Redis pub/sub for fan-out
|
||||
- Storage: CDN for static assets
|
||||
|
||||
• Performance Targets:
|
||||
- API Response: <200ms (p95)
|
||||
- Real-time Sync: <100ms
|
||||
- AI Response: <3s
|
||||
- Offline Support: 7 days of data
|
||||
412
docs/maternal-app-db-migrations.md
Normal file
412
docs/maternal-app-db-migrations.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# Database Migration Scripts - Maternal Organization App
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Naming Convention
|
||||
- Format: `V{version}_{timestamp}_{description}.sql`
|
||||
- Example: `V001_20240110120000_create_users_table.sql`
|
||||
- Rollback: `R001_20240110120000_create_users_table.sql`
|
||||
|
||||
### Execution Order
|
||||
Migrations must run sequentially. Each migration is recorded in a `schema_migrations` table to prevent re-execution.
|
||||
|
||||
---
|
||||
|
||||
## Migration V001: Core Authentication Tables
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V001_20240110120000_create_core_auth.sql
|
||||
|
||||
CREATE TABLE users (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('usr_' || nanoid()),
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
locale VARCHAR(10) DEFAULT 'en-US',
|
||||
timezone VARCHAR(50) DEFAULT 'UTC',
|
||||
email_verified BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE device_registry (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('dev_' || nanoid()),
|
||||
user_id VARCHAR(20) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
device_fingerprint VARCHAR(255) NOT NULL,
|
||||
platform VARCHAR(20) NOT NULL,
|
||||
trusted BOOLEAN DEFAULT FALSE,
|
||||
last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, device_fingerprint)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_email ON users(email);
|
||||
CREATE INDEX idx_devices_user ON device_registry(user_id);
|
||||
```
|
||||
|
||||
### Down Migration
|
||||
```sql
|
||||
-- R001_20240110120000_create_core_auth.sql
|
||||
DROP TABLE device_registry;
|
||||
DROP TABLE users;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V002: Family Structure
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V002_20240110130000_create_family_structure.sql
|
||||
|
||||
CREATE TABLE families (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('fam_' || nanoid()),
|
||||
name VARCHAR(100),
|
||||
share_code VARCHAR(10) UNIQUE DEFAULT upper(substr(md5(random()::text), 1, 6)),
|
||||
created_by VARCHAR(20) REFERENCES users(id),
|
||||
subscription_tier VARCHAR(20) DEFAULT 'free',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE family_members (
|
||||
user_id VARCHAR(20) REFERENCES users(id) ON DELETE CASCADE,
|
||||
family_id VARCHAR(20) REFERENCES families(id) ON DELETE CASCADE,
|
||||
role VARCHAR(20) NOT NULL CHECK (role IN ('parent', 'caregiver', 'viewer')),
|
||||
permissions JSONB DEFAULT '{"canAddChildren": false, "canEditChildren": false, "canLogActivities": true, "canViewReports": true}'::jsonb,
|
||||
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (user_id, family_id)
|
||||
);
|
||||
|
||||
CREATE TABLE children (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('chd_' || nanoid()),
|
||||
family_id VARCHAR(20) NOT NULL REFERENCES families(id) ON DELETE CASCADE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
birth_date DATE NOT NULL,
|
||||
gender VARCHAR(20),
|
||||
photo_url TEXT,
|
||||
medical_info JSONB DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_families_share_code ON families(share_code);
|
||||
CREATE INDEX idx_family_members_family ON family_members(family_id);
|
||||
CREATE INDEX idx_children_family ON children(family_id);
|
||||
CREATE INDEX idx_children_active ON children(deleted_at) WHERE deleted_at IS NULL;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V003: Activity Tracking Tables
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V003_20240110140000_create_activity_tracking.sql
|
||||
|
||||
CREATE TABLE activities (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('act_' || nanoid()),
|
||||
child_id VARCHAR(20) NOT NULL REFERENCES children(id) ON DELETE CASCADE,
|
||||
type VARCHAR(20) NOT NULL CHECK (type IN ('feeding', 'sleep', 'diaper', 'growth', 'medication', 'temperature')),
|
||||
started_at TIMESTAMP NOT NULL,
|
||||
ended_at TIMESTAMP,
|
||||
logged_by VARCHAR(20) NOT NULL REFERENCES users(id),
|
||||
notes TEXT,
|
||||
metadata JSONB DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Partitioned by month for scalability
|
||||
CREATE TABLE activities_2024_01 PARTITION OF activities
|
||||
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
||||
|
||||
CREATE INDEX idx_activities_child_time ON activities(child_id, started_at DESC);
|
||||
CREATE INDEX idx_activities_type ON activities(type, started_at DESC);
|
||||
CREATE INDEX idx_activities_metadata ON activities USING gin(metadata);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V004: AI and Analytics Tables
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V004_20240110150000_create_ai_analytics.sql
|
||||
|
||||
CREATE TABLE conversations (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('conv_' || nanoid()),
|
||||
user_id VARCHAR(20) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
child_id VARCHAR(20) REFERENCES children(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_message_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE messages (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('msg_' || nanoid()),
|
||||
conversation_id VARCHAR(20) NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
role VARCHAR(20) NOT NULL CHECK (role IN ('user', 'assistant')),
|
||||
content TEXT NOT NULL,
|
||||
metadata JSONB DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE patterns (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('pat_' || nanoid()),
|
||||
child_id VARCHAR(20) NOT NULL REFERENCES children(id) ON DELETE CASCADE,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
pattern_data JSONB NOT NULL,
|
||||
confidence DECIMAL(3,2),
|
||||
detected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE predictions (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('prd_' || nanoid()),
|
||||
child_id VARCHAR(20) NOT NULL REFERENCES children(id) ON DELETE CASCADE,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
predicted_time TIMESTAMP NOT NULL,
|
||||
confidence DECIMAL(3,2),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
outcome VARCHAR(20) -- 'correct', 'incorrect', 'pending'
|
||||
);
|
||||
|
||||
CREATE INDEX idx_conversations_user ON conversations(user_id);
|
||||
CREATE INDEX idx_messages_conversation ON messages(conversation_id);
|
||||
CREATE INDEX idx_patterns_child_type ON patterns(child_id, type);
|
||||
CREATE INDEX idx_predictions_child_time ON predictions(child_id, predicted_time);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V005: Performance Optimization Indexes
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V005_20240110160000_add_performance_indexes.sql
|
||||
|
||||
-- Composite indexes for common queries
|
||||
CREATE INDEX idx_activities_daily_summary
|
||||
ON activities(child_id, type, started_at)
|
||||
WHERE ended_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX idx_patterns_active
|
||||
ON patterns(child_id, type, confidence)
|
||||
WHERE expires_at > CURRENT_TIMESTAMP;
|
||||
|
||||
-- Text search for notes
|
||||
CREATE INDEX idx_activities_notes_search
|
||||
ON activities USING gin(to_tsvector('english', notes));
|
||||
|
||||
-- Covering index for dashboard query
|
||||
CREATE INDEX idx_children_dashboard
|
||||
ON children(family_id, id, name, birth_date)
|
||||
WHERE deleted_at IS NULL;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V006: Notification System
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V006_20240110170000_create_notifications.sql
|
||||
|
||||
CREATE TABLE notification_preferences (
|
||||
user_id VARCHAR(20) PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||
push_enabled BOOLEAN DEFAULT true,
|
||||
email_enabled BOOLEAN DEFAULT true,
|
||||
quiet_hours_start TIME,
|
||||
quiet_hours_end TIME,
|
||||
preferences JSONB DEFAULT '{}'::jsonb
|
||||
);
|
||||
|
||||
CREATE TABLE scheduled_notifications (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('ntf_' || nanoid()),
|
||||
user_id VARCHAR(20) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
child_id VARCHAR(20) REFERENCES children(id) ON DELETE CASCADE,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
scheduled_for TIMESTAMP NOT NULL,
|
||||
payload JSONB NOT NULL,
|
||||
sent_at TIMESTAMP,
|
||||
status VARCHAR(20) DEFAULT 'pending'
|
||||
);
|
||||
|
||||
CREATE INDEX idx_notifications_pending
|
||||
ON scheduled_notifications(scheduled_for, status)
|
||||
WHERE status = 'pending';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration V007: Audit and Compliance
|
||||
|
||||
### Up Migration
|
||||
```sql
|
||||
-- V007_20240110180000_create_audit_compliance.sql
|
||||
|
||||
CREATE TABLE audit_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id VARCHAR(20),
|
||||
action VARCHAR(50) NOT NULL,
|
||||
entity_type VARCHAR(50),
|
||||
entity_id VARCHAR(20),
|
||||
changes JSONB,
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE data_deletion_requests (
|
||||
id VARCHAR(20) PRIMARY KEY DEFAULT ('del_' || nanoid()),
|
||||
user_id VARCHAR(20) NOT NULL REFERENCES users(id),
|
||||
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
scheduled_for TIMESTAMP NOT NULL DEFAULT (CURRENT_TIMESTAMP + INTERVAL '30 days'),
|
||||
completed_at TIMESTAMP,
|
||||
status VARCHAR(20) DEFAULT 'pending'
|
||||
);
|
||||
|
||||
-- Partition audit_log by month for retention management
|
||||
CREATE TABLE audit_log_2024_01 PARTITION OF audit_log
|
||||
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
||||
|
||||
CREATE INDEX idx_audit_user_action ON audit_log(user_id, action, created_at DESC);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Seed Data Script
|
||||
|
||||
```sql
|
||||
-- seed_development_data.sql
|
||||
|
||||
-- Test users
|
||||
INSERT INTO users (id, email, password_hash, name, locale) VALUES
|
||||
('usr_test1', 'test1@example.com', '$2b$10$...', 'Test Parent 1', 'en-US'),
|
||||
('usr_test2', 'test2@example.com', '$2b$10$...', 'Test Parent 2', 'es-ES');
|
||||
|
||||
-- Test family
|
||||
INSERT INTO families (id, name, created_by, share_code) VALUES
|
||||
('fam_test', 'Test Family', 'usr_test1', 'TEST01');
|
||||
|
||||
-- Family members
|
||||
INSERT INTO family_members (user_id, family_id, role, permissions) VALUES
|
||||
('usr_test1', 'fam_test', 'parent', '{"canAddChildren": true, "canEditChildren": true, "canLogActivities": true, "canViewReports": true}'::jsonb),
|
||||
('usr_test2', 'fam_test', 'parent', '{"canAddChildren": true, "canEditChildren": true, "canLogActivities": true, "canViewReports": true}'::jsonb);
|
||||
|
||||
-- Test children
|
||||
INSERT INTO children (id, family_id, name, birth_date, gender) VALUES
|
||||
('chd_test1', 'fam_test', 'Emma', '2023-06-15', 'female'),
|
||||
('chd_test2', 'fam_test', 'Liam', '2021-03-22', 'male');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Runner Configuration
|
||||
|
||||
### TypeORM Configuration
|
||||
```typescript
|
||||
// ormconfig.ts
|
||||
export default {
|
||||
type: 'postgres',
|
||||
host: process.env.DB_HOST,
|
||||
port: 5432,
|
||||
database: process.env.DB_NAME,
|
||||
migrations: ['src/migrations/*.sql'],
|
||||
cli: {
|
||||
migrationsDir: 'src/migrations'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Knex Configuration
|
||||
```javascript
|
||||
// knexfile.js
|
||||
module.exports = {
|
||||
development: {
|
||||
client: 'postgresql',
|
||||
connection: process.env.DATABASE_URL,
|
||||
migrations: {
|
||||
directory: './migrations',
|
||||
tableName: 'schema_migrations'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Maintenance Scripts
|
||||
|
||||
### Weekly Vacuum
|
||||
```sql
|
||||
-- maintenance/weekly_vacuum.sql
|
||||
VACUUM ANALYZE activities;
|
||||
VACUUM ANALYZE patterns;
|
||||
VACUUM ANALYZE predictions;
|
||||
```
|
||||
|
||||
### Monthly Partition Creation
|
||||
```sql
|
||||
-- maintenance/create_next_month_partition.sql
|
||||
CREATE TABLE IF NOT EXISTS activities_2024_02
|
||||
PARTITION OF activities
|
||||
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
|
||||
```
|
||||
|
||||
### Archive Old Data
|
||||
```sql
|
||||
-- maintenance/archive_old_activities.sql
|
||||
INSERT INTO activities_archive
|
||||
SELECT * FROM activities
|
||||
WHERE started_at < CURRENT_DATE - INTERVAL '1 year';
|
||||
|
||||
DELETE FROM activities
|
||||
WHERE started_at < CURRENT_DATE - INTERVAL '1 year';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rollback Procedures
|
||||
|
||||
### Full Rollback Script
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# rollback.sh
|
||||
|
||||
VERSION=$1
|
||||
psql $DATABASE_URL -f "migrations/rollback/R${VERSION}.sql"
|
||||
DELETE FROM schema_migrations WHERE version = $VERSION;
|
||||
```
|
||||
|
||||
### Emergency Recovery
|
||||
```sql
|
||||
-- emergency_recovery.sql
|
||||
-- Point-in-time recovery to specific timestamp
|
||||
SELECT pg_restore_point('before_migration');
|
||||
-- Restore from backup if catastrophic failure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Index Strategy
|
||||
- Primary indexes on foreign keys
|
||||
- Composite indexes for common query patterns
|
||||
- Partial indexes for active records
|
||||
- GIN indexes for JSONB search
|
||||
- Covering indexes for dashboard queries
|
||||
|
||||
### Partitioning Strategy
|
||||
- Activities table partitioned by month
|
||||
- Audit log partitioned by month
|
||||
- Automatic partition creation via cron job
|
||||
|
||||
### Connection Pooling
|
||||
```sql
|
||||
-- Recommended PostgreSQL settings
|
||||
max_connections = 200
|
||||
shared_buffers = 256MB
|
||||
effective_cache_size = 1GB
|
||||
work_mem = 4MB
|
||||
```
|
||||
586
docs/maternal-app-design-system.md
Normal file
586
docs/maternal-app-design-system.md
Normal file
@@ -0,0 +1,586 @@
|
||||
# UI/UX Design System - Maternal Organization App
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
### Core Principles
|
||||
- **Calm Clarity**: Modern minimalist approach reducing cognitive load
|
||||
- **Warm Touch**: Nurturing colors and gentle interactions providing emotional comfort
|
||||
- **One-Handed First**: All critical actions accessible within thumb reach
|
||||
- **Interruption-Resilient**: Every interaction can be abandoned and resumed
|
||||
- **Inclusive by Default**: WCAG AA/AAA compliance throughout
|
||||
|
||||
---
|
||||
|
||||
## Color System
|
||||
|
||||
### Primary Palette
|
||||
```css
|
||||
/* Warm Nurturing Colors */
|
||||
--primary-peach: #FFB5A0;
|
||||
--primary-coral: #FF8B7D;
|
||||
--primary-rose: #FFD4CC;
|
||||
--primary-blush: #FFF0ED;
|
||||
|
||||
/* Semantic Colors */
|
||||
--success-sage: #7FB069;
|
||||
--warning-amber: #F4A259;
|
||||
--error-soft: #E07A5F;
|
||||
--info-sky: #81C3D7;
|
||||
|
||||
/* Neutral Scale */
|
||||
--neutral-900: #1A1A1A; /* Primary text */
|
||||
--neutral-700: #404040; /* Secondary text */
|
||||
--neutral-500: #737373; /* Disabled text */
|
||||
--neutral-300: #D4D4D4; /* Borders */
|
||||
--neutral-100: #F5F5F5; /* Backgrounds */
|
||||
--neutral-50: #FAFAFA; /* Surface */
|
||||
--white: #FFFFFF;
|
||||
```
|
||||
|
||||
### Dark Mode Palette
|
||||
```css
|
||||
/* Dark Mode Adjustments */
|
||||
--dark-surface: #1E1E1E;
|
||||
--dark-elevated: #2A2A2A;
|
||||
--dark-primary: #FFB5A0; /* Same warm colors */
|
||||
--dark-text-primary: #F5F5F5;
|
||||
--dark-text-secondary: #B8B8B8;
|
||||
--dark-border: #404040;
|
||||
```
|
||||
|
||||
### Color Usage Guidelines
|
||||
- **Primary actions**: `--primary-coral`
|
||||
- **Secondary actions**: `--primary-peach`
|
||||
- **Backgrounds**: `--primary-blush` (10% opacity overlays)
|
||||
- **Success states**: `--success-sage`
|
||||
- **Warnings**: `--warning-amber`
|
||||
- **Errors**: `--error-soft` (gentler than harsh red)
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Families
|
||||
```css
|
||||
/* Sans-serif for UI elements */
|
||||
--font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
/* Serif for content and insights */
|
||||
--font-content: 'Crimson Pro', 'Georgia', serif;
|
||||
|
||||
/* Monospace for data */
|
||||
--font-mono: 'JetBrains Mono', 'SF Mono', monospace;
|
||||
```
|
||||
|
||||
### Type Scale (Material Design)
|
||||
```css
|
||||
/* Headlines */
|
||||
--headline-1: 96px, light, -1.5px; /* Not used in mobile */
|
||||
--headline-2: 60px, light, -0.5px; /* Not used in mobile */
|
||||
--headline-3: 48px, regular, 0px; /* Not used in mobile */
|
||||
--headline-4: 34px, regular, 0.25px; /* Screen titles */
|
||||
--headline-5: 24px, regular, 0px; /* Section headers */
|
||||
--headline-6: 20px, medium, 0.15px; /* Card titles */
|
||||
|
||||
/* Body Text */
|
||||
--body-1: 16px, regular, 0.5px, 1.5 line-height; /* Main content */
|
||||
--body-2: 14px, regular, 0.25px, 1.43 line-height; /* Secondary content */
|
||||
|
||||
/* Supporting Text */
|
||||
--subtitle-1: 16px, medium, 0.15px; /* List items */
|
||||
--subtitle-2: 14px, medium, 0.1px; /* Sub-headers */
|
||||
--button: 14px, medium, 1.25px, uppercase;
|
||||
--caption: 12px, regular, 0.4px; /* Timestamps, labels */
|
||||
--overline: 10px, regular, 1.5px, uppercase;
|
||||
```
|
||||
|
||||
### Mobile-Optimized Sizes
|
||||
```css
|
||||
/* Minimum touch target: 44x44px (iOS) / 48x48dp (Android) */
|
||||
--text-minimum: 14px; /* Never smaller */
|
||||
--text-comfortable: 16px; /* Default body */
|
||||
--text-large: 18px; /* Easy reading */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Spacing System
|
||||
|
||||
### Base Unit: 8px Grid
|
||||
```css
|
||||
--space-0: 0px;
|
||||
--space-1: 8px;
|
||||
--space-2: 16px;
|
||||
--space-3: 24px;
|
||||
--space-4: 32px;
|
||||
--space-5: 40px;
|
||||
--space-6: 48px;
|
||||
--space-8: 64px;
|
||||
--space-10: 80px;
|
||||
```
|
||||
|
||||
### Component Spacing
|
||||
```css
|
||||
/* Padding */
|
||||
--padding-button: 16px 24px;
|
||||
--padding-card: 16px;
|
||||
--padding-screen: 16px;
|
||||
--padding-input: 12px 16px;
|
||||
|
||||
/* Margins */
|
||||
--margin-section: 32px;
|
||||
--margin-element: 16px;
|
||||
--margin-text: 8px;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layout Grid
|
||||
|
||||
### Mobile Layout
|
||||
```css
|
||||
/* Screen Breakpoints */
|
||||
--screen-small: 320px; /* iPhone SE */
|
||||
--screen-medium: 375px; /* iPhone 12/13 */
|
||||
--screen-large: 414px; /* iPhone Plus/Pro Max */
|
||||
--screen-tablet: 768px; /* iPad */
|
||||
|
||||
/* Content Zones */
|
||||
.safe-area {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.thumb-zone {
|
||||
/* Bottom 60% of screen */
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
height: 60vh;
|
||||
}
|
||||
```
|
||||
|
||||
### One-Handed Reachability Map
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ Hard to reach │ 20%
|
||||
├─────────────────────┤
|
||||
│ Moderate reach │ 20%
|
||||
├─────────────────────┤
|
||||
│ Easy reach │ 30%
|
||||
├─────────────────────┤
|
||||
│ Natural reach │ 30%
|
||||
│ (Thumb zone) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Specifications
|
||||
|
||||
### Buttons
|
||||
|
||||
#### Primary Button
|
||||
```css
|
||||
.button-primary {
|
||||
background: var(--primary-coral);
|
||||
color: white;
|
||||
border-radius: 24px; /* Pill shape */
|
||||
padding: 16px 32px;
|
||||
min-height: 48px; /* Touch target */
|
||||
font: var(--button);
|
||||
box-shadow: 0 4px 8px rgba(255, 139, 125, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
#### Floating Action Button (FAB)
|
||||
```css
|
||||
.fab {
|
||||
position: fixed;
|
||||
bottom: 80px; /* Above navigation */
|
||||
right: 16px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 28px;
|
||||
background: var(--primary-coral);
|
||||
box-shadow: 0 6px 12px rgba(0,0,0,0.15);
|
||||
}
|
||||
```
|
||||
|
||||
### Cards (Material Design)
|
||||
```css
|
||||
.card {
|
||||
background: var(--white);
|
||||
border-radius: 16px; /* Softer than Material default */
|
||||
padding: var(--padding-card);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.card-dark {
|
||||
background: var(--dark-elevated);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### Input Fields
|
||||
```css
|
||||
.input-field {
|
||||
background: var(--neutral-50);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 12px;
|
||||
padding: var(--padding-input);
|
||||
font-size: 16px; /* Prevents zoom on iOS */
|
||||
min-height: 48px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.input-field:focus {
|
||||
border-color: var(--primary-peach);
|
||||
background: var(--white);
|
||||
}
|
||||
```
|
||||
|
||||
### Bottom Navigation
|
||||
```css
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
background: var(--white);
|
||||
box-shadow: 0 -2px 8px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
min-width: 64px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Icon System
|
||||
|
||||
### Icon Library: Material Icons Outlined
|
||||
```css
|
||||
/* Sizes */
|
||||
--icon-small: 20px;
|
||||
--icon-medium: 24px; /* Default */
|
||||
--icon-large: 32px;
|
||||
--icon-xlarge: 48px;
|
||||
|
||||
/* Styles */
|
||||
.icon {
|
||||
stroke-width: 1.5px;
|
||||
color: var(--neutral-700);
|
||||
}
|
||||
|
||||
.icon-primary {
|
||||
color: var(--primary-coral);
|
||||
}
|
||||
```
|
||||
|
||||
### Core Icon Set
|
||||
```
|
||||
Navigation:
|
||||
- home_outlined
|
||||
- calendar_month_outlined
|
||||
- insights_outlined
|
||||
- chat_bubble_outline
|
||||
- person_outline
|
||||
|
||||
Actions:
|
||||
- add_circle_outline
|
||||
- mic_outlined
|
||||
- camera_outlined
|
||||
- timer_outlined
|
||||
- check_circle_outline
|
||||
|
||||
Tracking:
|
||||
- baby_changing_station_outlined
|
||||
- bed_outlined
|
||||
- restaurant_outlined
|
||||
- straighten_outlined (growth)
|
||||
- medical_services_outlined
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interaction Patterns
|
||||
|
||||
### Touch Targets
|
||||
```css
|
||||
/* Minimum touch target size */
|
||||
.touchable {
|
||||
min-width: 44px; /* iOS HIG */
|
||||
min-height: 44px;
|
||||
padding: 12px; /* Extends touch area */
|
||||
}
|
||||
```
|
||||
|
||||
### Gesture Support
|
||||
```javascript
|
||||
/* Swipe Actions */
|
||||
- Swipe left: Delete/Archive
|
||||
- Swipe right: Edit/Complete
|
||||
- Pull down: Refresh
|
||||
- Long press: Context menu
|
||||
- Pinch: Zoom charts
|
||||
```
|
||||
|
||||
### Loading States
|
||||
```css
|
||||
/* Skeleton Screens */
|
||||
.skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--neutral-100) 25%,
|
||||
var(--neutral-50) 50%,
|
||||
var(--neutral-100) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Spinner for actions */
|
||||
.spinner {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 3px solid var(--primary-rose);
|
||||
border-top-color: var(--primary-coral);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
```
|
||||
|
||||
### Micro-Animations
|
||||
```css
|
||||
/* Gentle transitions */
|
||||
* {
|
||||
transition-duration: 0.2s;
|
||||
transition-timing-function: ease-out;
|
||||
}
|
||||
|
||||
/* Success feedback */
|
||||
@keyframes success-pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility Specifications
|
||||
|
||||
### WCAG Compliance
|
||||
```css
|
||||
/* Contrast Ratios */
|
||||
--contrast-normal: 4.5:1; /* AA standard */
|
||||
--contrast-large: 3:1; /* AA for large text */
|
||||
--contrast-enhanced: 7:1; /* AAA standard */
|
||||
|
||||
/* Focus Indicators */
|
||||
:focus-visible {
|
||||
outline: 3px solid var(--primary-coral);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### Screen Reader Support
|
||||
```html
|
||||
<!-- Proper ARIA labels -->
|
||||
<button aria-label="Log feeding" aria-pressed="false">
|
||||
<icon name="restaurant_outlined" aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<!-- Live regions for updates -->
|
||||
<div role="status" aria-live="polite" aria-atomic="true">
|
||||
Activity logged successfully
|
||||
</div>
|
||||
```
|
||||
|
||||
### Reduced Motion
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Platform-Specific Adaptations
|
||||
|
||||
### Material You (Android 12+)
|
||||
```kotlin
|
||||
// Dynamic color extraction
|
||||
MaterialTheme(
|
||||
colorScheme = dynamicColorScheme ?: customColorScheme,
|
||||
typography = AppTypography,
|
||||
content = content
|
||||
)
|
||||
```
|
||||
|
||||
### iOS Adaptations
|
||||
```swift
|
||||
// Haptic feedback
|
||||
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
||||
|
||||
// Safe area handling
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dark Mode Implementation
|
||||
|
||||
### Automatic Switching
|
||||
```javascript
|
||||
// React Native
|
||||
import { useColorScheme } from 'react-native';
|
||||
|
||||
const ColorScheme = {
|
||||
light: {
|
||||
background: '#FFFFFF',
|
||||
text: '#1A1A1A',
|
||||
primary: '#FF8B7D'
|
||||
},
|
||||
dark: {
|
||||
background: '#1E1E1E',
|
||||
text: '#F5F5F5',
|
||||
primary: '#FFB5A0'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Theme Provider
|
||||
```typescript
|
||||
// Material-UI Theme
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
mode: systemPreference,
|
||||
primary: {
|
||||
main: '#FF8B7D',
|
||||
},
|
||||
background: {
|
||||
default: mode === 'dark' ? '#1E1E1E' : '#FFFFFF',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: ['Inter', 'sans-serif'].join(','),
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 12,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component States
|
||||
|
||||
### Interactive States
|
||||
```css
|
||||
/* Default */
|
||||
.button { opacity: 1; }
|
||||
|
||||
/* Hover (web) */
|
||||
.button:hover { opacity: 0.9; }
|
||||
|
||||
/* Active/Pressed */
|
||||
.button:active { transform: scale(0.98); }
|
||||
|
||||
/* Disabled */
|
||||
.button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Loading */
|
||||
.button.loading {
|
||||
pointer-events: none;
|
||||
color: transparent;
|
||||
}
|
||||
```
|
||||
|
||||
### Form Validation States
|
||||
```css
|
||||
.input-success {
|
||||
border-color: var(--success-sage);
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: var(--error-soft);
|
||||
background-color: rgba(224, 122, 95, 0.05);
|
||||
}
|
||||
|
||||
.helper-text {
|
||||
font-size: 12px;
|
||||
color: var(--neutral-700);
|
||||
margin-top: 4px;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Action Design
|
||||
|
||||
### Bottom Sheet Actions
|
||||
```css
|
||||
.quick-actions {
|
||||
position: fixed;
|
||||
bottom: 80px; /* Above nav */
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: var(--white);
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.quick-action-button {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--primary-blush);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Guidelines
|
||||
|
||||
### Image Optimization
|
||||
- Maximum image size: 200KB
|
||||
- Lazy loading for all images
|
||||
- WebP format with JPG fallback
|
||||
- Thumbnail generation for avatars
|
||||
|
||||
### Animation Performance
|
||||
- Use transform and opacity only
|
||||
- 60fps target for all animations
|
||||
- GPU acceleration for transitions
|
||||
- Avoid animating during scroll
|
||||
|
||||
### Font Loading
|
||||
```css
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap; /* Show fallback immediately */
|
||||
src: url('/fonts/Inter.woff2') format('woff2');
|
||||
}
|
||||
```
|
||||
507
docs/maternal-app-env-config.md
Normal file
507
docs/maternal-app-env-config.md
Normal file
@@ -0,0 +1,507 @@
|
||||
# Environment Configuration Guide - Maternal Organization App
|
||||
|
||||
## Environment Structure
|
||||
|
||||
### Environment Types
|
||||
- **Development** (`dev`): Local development with hot reload
|
||||
- **Staging** (`staging`): Pre-production testing environment
|
||||
- **Production** (`prod`): Live application environment
|
||||
- **Testing** (`test`): Automated testing environment
|
||||
|
||||
---
|
||||
|
||||
## Backend Environment Variables (.env)
|
||||
|
||||
### Core Configuration
|
||||
```bash
|
||||
# Application
|
||||
NODE_ENV=development
|
||||
APP_NAME=MaternalApp
|
||||
APP_VERSION=1.0.0
|
||||
API_VERSION=v1
|
||||
PORT=3000
|
||||
HOST=localhost
|
||||
|
||||
# URLs
|
||||
BACKEND_URL=http://localhost:3000
|
||||
FRONTEND_URL=http://localhost:8081
|
||||
WEBSOCKET_URL=ws://localhost:3000
|
||||
```
|
||||
|
||||
### Database Configuration
|
||||
```bash
|
||||
# PostgreSQL Primary
|
||||
DATABASE_URL=postgresql://user:password@localhost:5432/maternal_app
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=maternal_app
|
||||
DB_USER=maternal_user
|
||||
DB_PASSWORD=secure_password_here
|
||||
DB_SSL=false
|
||||
DB_POOL_MIN=2
|
||||
DB_POOL_MAX=10
|
||||
|
||||
# MongoDB (AI Chat History)
|
||||
MONGODB_URI=mongodb://localhost:27017/maternal_ai
|
||||
MONGODB_DB=maternal_ai
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DB=0
|
||||
REDIS_CACHE_TTL=3600
|
||||
```
|
||||
|
||||
### Authentication & Security
|
||||
```bash
|
||||
# JWT Configuration
|
||||
JWT_SECRET=your-256-bit-secret-key-here
|
||||
JWT_REFRESH_SECRET=different-256-bit-secret-key-here
|
||||
JWT_EXPIRES_IN=1h
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# Encryption
|
||||
ENCRYPTION_KEY=32-character-encryption-key-here
|
||||
ENCRYPTION_IV=16-character-iv-here
|
||||
|
||||
# Device Fingerprinting
|
||||
FINGERPRINT_SECRET=device-fingerprint-secret-key
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_WINDOW_MS=60000
|
||||
RATE_LIMIT_MAX_REQUESTS=100
|
||||
```
|
||||
|
||||
### AI Services
|
||||
```bash
|
||||
# OpenAI
|
||||
OPENAI_API_KEY=sk-your-openai-api-key
|
||||
OPENAI_MODEL=gpt-4
|
||||
OPENAI_TEMPERATURE=0.7
|
||||
OPENAI_MAX_TOKENS=1000
|
||||
|
||||
# Anthropic Claude (Alternative)
|
||||
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key
|
||||
ANTHROPIC_MODEL=claude-3-opus-20240229
|
||||
|
||||
# Whisper (Voice Recognition)
|
||||
WHISPER_API_KEY=your-whisper-api-key
|
||||
WHISPER_MODEL=whisper-1
|
||||
|
||||
# LangChain
|
||||
LANGCHAIN_TRACING_V2=true
|
||||
LANGCHAIN_API_KEY=your-langchain-api-key
|
||||
LANGCHAIN_PROJECT=maternal-app
|
||||
```
|
||||
|
||||
### External Services
|
||||
```bash
|
||||
# Email Service (SendGrid)
|
||||
SENDGRID_API_KEY=SG.your-sendgrid-api-key
|
||||
SENDGRID_FROM_EMAIL=support@maternalapp.com
|
||||
SENDGRID_FROM_NAME=Maternal App
|
||||
|
||||
# Push Notifications
|
||||
FCM_SERVER_KEY=your-firebase-server-key
|
||||
FCM_PROJECT_ID=maternal-app-prod
|
||||
APNS_KEY_ID=your-apple-key-id
|
||||
APNS_TEAM_ID=your-apple-team-id
|
||||
|
||||
# File Storage (MinIO/S3)
|
||||
S3_ENDPOINT=http://localhost:9000
|
||||
S3_ACCESS_KEY=minioadmin
|
||||
S3_SECRET_KEY=minioadmin
|
||||
S3_BUCKET=maternal-uploads
|
||||
S3_REGION=us-east-1
|
||||
S3_USE_SSL=false
|
||||
|
||||
# Monitoring
|
||||
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
|
||||
SENTRY_ENVIRONMENT=development
|
||||
SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||
```
|
||||
|
||||
### Compliance & Analytics
|
||||
```bash
|
||||
# COPPA/GDPR
|
||||
COPPA_VERIFICATION_REQUIRED=true
|
||||
GDPR_ENABLED=true
|
||||
DATA_RETENTION_DAYS=365
|
||||
AUDIT_LOG_ENABLED=true
|
||||
|
||||
# Analytics
|
||||
MIXPANEL_TOKEN=your-mixpanel-token
|
||||
GA_TRACKING_ID=G-XXXXXXXXXX
|
||||
POSTHOG_API_KEY=your-posthog-key
|
||||
POSTHOG_HOST=https://app.posthog.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend Environment Variables (.env)
|
||||
|
||||
### React Native Configuration
|
||||
```bash
|
||||
# API Configuration
|
||||
REACT_APP_API_BASE_URL=http://localhost:3000/api/v1
|
||||
REACT_APP_GRAPHQL_URL=http://localhost:3000/graphql
|
||||
REACT_APP_WS_URL=ws://localhost:3000/ws
|
||||
|
||||
# Feature Flags
|
||||
REACT_APP_ENABLE_VOICE=true
|
||||
REACT_APP_ENABLE_AI_CHAT=true
|
||||
REACT_APP_ENABLE_DARK_MODE=true
|
||||
REACT_APP_ENABLE_OFFLINE=true
|
||||
REACT_APP_MAX_CHILDREN_FREE=2
|
||||
REACT_APP_AI_QUERIES_FREE=10
|
||||
|
||||
# App Configuration
|
||||
REACT_APP_NAME=Maternal
|
||||
REACT_APP_VERSION=1.0.0
|
||||
REACT_APP_BUILD_NUMBER=1
|
||||
REACT_APP_BUNDLE_ID=com.maternalapp.app
|
||||
```
|
||||
|
||||
### Platform-Specific (iOS)
|
||||
```bash
|
||||
# iOS Configuration
|
||||
IOS_APP_ID=1234567890
|
||||
IOS_TEAM_ID=XXXXXXXXXX
|
||||
IOS_PROVISIONING_PROFILE=maternal-app-dev
|
||||
APPLE_SIGN_IN_SERVICE_ID=com.maternalapp.signin
|
||||
```
|
||||
|
||||
### Platform-Specific (Android)
|
||||
```bash
|
||||
# Android Configuration
|
||||
ANDROID_PACKAGE_NAME=com.maternalapp.app
|
||||
ANDROID_KEYSTORE_PATH=./android/app/maternal.keystore
|
||||
ANDROID_KEY_ALIAS=maternal-key
|
||||
ANDROID_KEYSTORE_PASSWORD=keystore-password
|
||||
ANDROID_KEY_PASSWORD=key-password
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Environment Configuration
|
||||
|
||||
### docker-compose.yml
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
mongodb:
|
||||
image: mongo:6
|
||||
environment:
|
||||
MONGO_INITDB_DATABASE: maternal_ai
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
ports:
|
||||
- "27017:27017"
|
||||
|
||||
minio:
|
||||
image: minio/minio
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${S3_ACCESS_KEY}
|
||||
MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY}
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
mongo_data:
|
||||
minio_data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secret Management
|
||||
|
||||
### Development Secrets (.env.local)
|
||||
```bash
|
||||
# Never commit this file
|
||||
# Copy from .env.example and fill with real values
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
### Production Secrets (AWS Secrets Manager)
|
||||
```bash
|
||||
# Store production secrets in AWS Secrets Manager
|
||||
aws secretsmanager create-secret \
|
||||
--name maternal-app/production \
|
||||
--secret-string file://secrets.json
|
||||
|
||||
# Retrieve secrets in application
|
||||
aws secretsmanager get-secret-value \
|
||||
--secret-id maternal-app/production
|
||||
```
|
||||
|
||||
### Kubernetes Secrets
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: maternal-app-secrets
|
||||
type: Opaque
|
||||
data:
|
||||
jwt-secret: <base64-encoded-secret>
|
||||
database-url: <base64-encoded-url>
|
||||
openai-api-key: <base64-encoded-key>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment File Templates
|
||||
|
||||
### .env.example (Commit to repo)
|
||||
```bash
|
||||
# Copy this file to .env.local and fill in values
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
|
||||
# Database
|
||||
DATABASE_URL=postgresql://user:password@localhost:5432/maternal_app
|
||||
|
||||
# Add all variables with placeholder values...
|
||||
JWT_SECRET=change-this-to-random-256-bit-key
|
||||
OPENAI_API_KEY=sk-your-api-key-here
|
||||
```
|
||||
|
||||
### .env.test (Testing)
|
||||
```bash
|
||||
NODE_ENV=test
|
||||
DATABASE_URL=postgresql://test:test@localhost:5432/maternal_test
|
||||
REDIS_URL=redis://localhost:6380
|
||||
JWT_SECRET=test-jwt-secret-not-for-production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Platform-Specific Configuration
|
||||
|
||||
### iOS Info.plist Additions
|
||||
```xml
|
||||
<key>API_BASE_URL</key>
|
||||
<string>$(API_BASE_URL)</string>
|
||||
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Voice input for hands-free logging</string>
|
||||
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Take photos of your child</string>
|
||||
```
|
||||
|
||||
### Android gradle.properties
|
||||
```properties
|
||||
API_BASE_URL=http://10.0.2.2:3000/api/v1
|
||||
ENABLE_VOICE_INPUT=true
|
||||
ENABLE_PROGUARD=false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Loading Order
|
||||
|
||||
### Backend (Node.js)
|
||||
```javascript
|
||||
// config/index.ts
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
// Load in order of precedence
|
||||
dotenv.config({ path: '.env.local' }); // Local overrides
|
||||
dotenv.config({ path: `.env.${NODE_ENV}` }); // Environment specific
|
||||
dotenv.config(); // Default values
|
||||
|
||||
export const config = {
|
||||
app: {
|
||||
name: process.env.APP_NAME || 'MaternalApp',
|
||||
version: process.env.APP_VERSION || '1.0.0',
|
||||
env: process.env.NODE_ENV || 'development',
|
||||
},
|
||||
// ... rest of config
|
||||
};
|
||||
```
|
||||
|
||||
### Frontend (React Native)
|
||||
```javascript
|
||||
// config/env.js
|
||||
import Config from 'react-native-config';
|
||||
|
||||
export const ENV = {
|
||||
dev: {
|
||||
API_URL: 'http://localhost:3000/api/v1',
|
||||
WS_URL: 'ws://localhost:3000/ws',
|
||||
},
|
||||
staging: {
|
||||
API_URL: 'https://staging-api.maternalapp.com/api/v1',
|
||||
WS_URL: 'wss://staging-api.maternalapp.com/ws',
|
||||
},
|
||||
prod: {
|
||||
API_URL: 'https://api.maternalapp.com/api/v1',
|
||||
WS_URL: 'wss://api.maternalapp.com/ws',
|
||||
},
|
||||
}[Config.ENV || 'dev'];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Secret Rotation Schedule
|
||||
- **JWT Secrets**: Every 90 days
|
||||
- **API Keys**: Every 180 days
|
||||
- **Database Passwords**: Every 60 days
|
||||
- **Encryption Keys**: Every year
|
||||
|
||||
### Environment Variable Validation
|
||||
```typescript
|
||||
// validateEnv.ts
|
||||
import { cleanEnv, str, port, url, bool, num } from 'envalid';
|
||||
|
||||
export const env = cleanEnv(process.env, {
|
||||
NODE_ENV: str({ choices: ['development', 'test', 'staging', 'production'] }),
|
||||
PORT: port(),
|
||||
DATABASE_URL: url(),
|
||||
JWT_SECRET: str({ minLength: 32 }),
|
||||
OPENAI_API_KEY: str(),
|
||||
RATE_LIMIT_MAX_REQUESTS: num({ default: 100 }),
|
||||
});
|
||||
```
|
||||
|
||||
### Git Security
|
||||
```bash
|
||||
# .gitignore
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
secrets/
|
||||
*.key
|
||||
*.pem
|
||||
*.p12
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Configuration
|
||||
|
||||
### Heroku
|
||||
```json
|
||||
// app.json
|
||||
{
|
||||
"env": {
|
||||
"NODE_ENV": {
|
||||
"value": "production"
|
||||
},
|
||||
"DATABASE_URL": {
|
||||
"required": true
|
||||
},
|
||||
"JWT_SECRET": {
|
||||
"generator": "secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Docker Build Args
|
||||
```dockerfile
|
||||
ARG NODE_ENV=production
|
||||
ARG API_VERSION=v1
|
||||
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
ENV API_VERSION=${API_VERSION}
|
||||
```
|
||||
|
||||
### CI/CD Variables (GitHub Actions)
|
||||
```yaml
|
||||
env:
|
||||
NODE_ENV: production
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Debugging
|
||||
|
||||
### Debug Configuration
|
||||
```bash
|
||||
# Development debugging
|
||||
DEBUG=maternal:*
|
||||
LOG_LEVEL=debug
|
||||
PRETTY_LOGS=true
|
||||
|
||||
# Production
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=json
|
||||
```
|
||||
|
||||
### Health Check Variables
|
||||
```bash
|
||||
HEALTH_CHECK_INTERVAL=30000
|
||||
HEALTH_CHECK_TIMEOUT=3000
|
||||
HEALTH_CHECK_PATH=/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start Commands
|
||||
|
||||
### Local Development Setup
|
||||
```bash
|
||||
# 1. Copy environment template
|
||||
cp .env.example .env.local
|
||||
|
||||
# 2. Start Docker services
|
||||
docker-compose up -d
|
||||
|
||||
# 3. Run migrations
|
||||
npm run migrate:up
|
||||
|
||||
# 4. Seed development data
|
||||
npm run seed:dev
|
||||
|
||||
# 5. Start development server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Environment Verification
|
||||
```bash
|
||||
# Check all required variables are set
|
||||
npm run env:validate
|
||||
|
||||
# Display current configuration (masked)
|
||||
npm run env:debug
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
1. **Missing API Keys**: Ensure all AI service keys are valid
|
||||
2. **Database Connection**: Check DATABASE_URL format and credentials
|
||||
3. **Redis Connection**: Verify Redis is running and accessible
|
||||
4. **CORS Issues**: Confirm FRONTEND_URL is correctly set
|
||||
5. **WebSocket Failures**: Check WS_URL matches backend configuration
|
||||
588
docs/maternal-app-error-logging.md
Normal file
588
docs/maternal-app-error-logging.md
Normal file
@@ -0,0 +1,588 @@
|
||||
# Error Handling & Logging Standards - Maternal Organization App
|
||||
|
||||
## Error Philosophy
|
||||
|
||||
### Core Principles
|
||||
- **Parent-Friendly Messages**: Never show technical jargon to users
|
||||
- **Graceful Degradation**: App remains usable even with errors
|
||||
- **Recovery Guidance**: Always suggest next steps
|
||||
- **Preserve User Work**: Never lose unsaved data due to errors
|
||||
- **Privacy First**: Never log sensitive data (PII, health info)
|
||||
|
||||
---
|
||||
|
||||
## Error Code Hierarchy
|
||||
|
||||
### Error Code Structure
|
||||
Format: `[CATEGORY]_[SPECIFIC_ERROR]`
|
||||
|
||||
### Categories
|
||||
```typescript
|
||||
enum ErrorCategory {
|
||||
AUTH = 'AUTH', // Authentication/Authorization
|
||||
VALIDATION = 'VAL', // Input validation
|
||||
SYNC = 'SYNC', // Synchronization issues
|
||||
NETWORK = 'NET', // Network/connectivity
|
||||
DATA = 'DATA', // Database/storage
|
||||
AI = 'AI', // AI service errors
|
||||
LIMIT = 'LIMIT', // Rate limiting/quotas
|
||||
PAYMENT = 'PAY', // Subscription/payment
|
||||
SYSTEM = 'SYS', // System/internal errors
|
||||
COMPLIANCE = 'COMP' // COPPA/GDPR compliance
|
||||
}
|
||||
```
|
||||
|
||||
### Complete Error Code Registry
|
||||
```typescript
|
||||
export const ErrorCodes = {
|
||||
// Authentication
|
||||
AUTH_INVALID_CREDENTIALS: 'AUTH_001',
|
||||
AUTH_TOKEN_EXPIRED: 'AUTH_002',
|
||||
AUTH_TOKEN_INVALID: 'AUTH_003',
|
||||
AUTH_DEVICE_NOT_TRUSTED: 'AUTH_004',
|
||||
AUTH_MFA_REQUIRED: 'AUTH_005',
|
||||
AUTH_ACCOUNT_LOCKED: 'AUTH_006',
|
||||
|
||||
// Validation
|
||||
VAL_REQUIRED_FIELD: 'VAL_001',
|
||||
VAL_INVALID_EMAIL: 'VAL_002',
|
||||
VAL_WEAK_PASSWORD: 'VAL_003',
|
||||
VAL_INVALID_DATE: 'VAL_004',
|
||||
VAL_FUTURE_BIRTHDATE: 'VAL_005',
|
||||
VAL_INVALID_AMOUNT: 'VAL_006',
|
||||
|
||||
// Sync
|
||||
SYNC_CONFLICT: 'SYNC_001',
|
||||
SYNC_OFFLINE_QUEUE_FULL: 'SYNC_002',
|
||||
SYNC_VERSION_MISMATCH: 'SYNC_003',
|
||||
SYNC_FAMILY_UPDATE_FAILED: 'SYNC_004',
|
||||
|
||||
// Network
|
||||
NET_OFFLINE: 'NET_001',
|
||||
NET_TIMEOUT: 'NET_002',
|
||||
NET_SERVER_ERROR: 'NET_003',
|
||||
NET_SLOW_CONNECTION: 'NET_004',
|
||||
|
||||
// AI
|
||||
AI_SERVICE_UNAVAILABLE: 'AI_001',
|
||||
AI_QUOTA_EXCEEDED: 'AI_002',
|
||||
AI_INAPPROPRIATE_REQUEST: 'AI_003',
|
||||
AI_CONTEXT_TOO_LARGE: 'AI_004',
|
||||
|
||||
// Limits
|
||||
LIMIT_RATE_EXCEEDED: 'LIMIT_001',
|
||||
LIMIT_CHILDREN_EXCEEDED: 'LIMIT_002',
|
||||
LIMIT_FAMILY_SIZE_EXCEEDED: 'LIMIT_003',
|
||||
LIMIT_STORAGE_EXCEEDED: 'LIMIT_004',
|
||||
|
||||
// Compliance
|
||||
COMP_PARENTAL_CONSENT_REQUIRED: 'COMP_001',
|
||||
COMP_AGE_VERIFICATION_FAILED: 'COMP_002',
|
||||
COMP_DATA_RETENTION_EXPIRED: 'COMP_003'
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User-Facing Error Messages
|
||||
|
||||
### Message Structure
|
||||
```typescript
|
||||
interface UserErrorMessage {
|
||||
title: string; // Brief, clear title
|
||||
message: string; // Detailed explanation
|
||||
action?: string; // What user should do
|
||||
retryable: boolean; // Can user retry?
|
||||
severity: 'info' | 'warning' | 'error';
|
||||
}
|
||||
```
|
||||
|
||||
### Localized Error Messages
|
||||
```typescript
|
||||
// errors/locales/en-US.json
|
||||
{
|
||||
"AUTH_001": {
|
||||
"title": "Sign in failed",
|
||||
"message": "The email or password you entered doesn't match our records.",
|
||||
"action": "Please check your credentials and try again.",
|
||||
"retryable": true
|
||||
},
|
||||
"SYNC_001": {
|
||||
"title": "Update conflict",
|
||||
"message": "This activity was updated by another family member.",
|
||||
"action": "We've merged the changes. Please review.",
|
||||
"retryable": false
|
||||
},
|
||||
"AI_002": {
|
||||
"title": "AI assistant limit reached",
|
||||
"message": "You've used all 10 free AI questions today.",
|
||||
"action": "Upgrade to Premium for unlimited questions.",
|
||||
"retryable": false
|
||||
},
|
||||
"NET_001": {
|
||||
"title": "You're offline",
|
||||
"message": "Don't worry! Your activities are saved locally.",
|
||||
"action": "They'll sync when you're back online.",
|
||||
"retryable": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Localization for Other Languages
|
||||
```typescript
|
||||
// errors/locales/es-ES.json
|
||||
{
|
||||
"AUTH_001": {
|
||||
"title": "Error al iniciar sesión",
|
||||
"message": "El correo o contraseña no coinciden con nuestros registros.",
|
||||
"action": "Por favor verifica tus credenciales e intenta nuevamente.",
|
||||
"retryable": true
|
||||
}
|
||||
}
|
||||
|
||||
// errors/locales/fr-FR.json
|
||||
{
|
||||
"AUTH_001": {
|
||||
"title": "Échec de connexion",
|
||||
"message": "L'email ou le mot de passe ne correspond pas.",
|
||||
"action": "Veuillez vérifier vos identifiants et réessayer.",
|
||||
"retryable": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Logging Strategy
|
||||
|
||||
### Log Levels
|
||||
```typescript
|
||||
enum LogLevel {
|
||||
DEBUG = 0, // Development only
|
||||
INFO = 1, // General information
|
||||
WARN = 2, // Warning conditions
|
||||
ERROR = 3, // Error conditions
|
||||
FATAL = 4 // System is unusable
|
||||
}
|
||||
|
||||
// Environment-based levels
|
||||
const LOG_LEVELS = {
|
||||
development: LogLevel.DEBUG,
|
||||
staging: LogLevel.INFO,
|
||||
production: LogLevel.WARN
|
||||
};
|
||||
```
|
||||
|
||||
### Structured Logging Format
|
||||
```typescript
|
||||
interface LogEntry {
|
||||
timestamp: string;
|
||||
level: LogLevel;
|
||||
service: string;
|
||||
userId?: string; // Hashed for privacy
|
||||
familyId?: string; // For family-related issues
|
||||
deviceId?: string; // Device fingerprint
|
||||
errorCode?: string;
|
||||
message: string;
|
||||
context?: Record<string, any>;
|
||||
stack?: string;
|
||||
duration?: number; // For performance logs
|
||||
correlationId: string; // Trace requests
|
||||
}
|
||||
|
||||
// Example log entry
|
||||
{
|
||||
"timestamp": "2024-01-10T14:30:00.123Z",
|
||||
"level": "ERROR",
|
||||
"service": "ActivityService",
|
||||
"userId": "hash_2n4k8m9p",
|
||||
"errorCode": "SYNC_001",
|
||||
"message": "Sync conflict detected",
|
||||
"context": {
|
||||
"activityId": "act_123",
|
||||
"conflictType": "simultaneous_edit"
|
||||
},
|
||||
"correlationId": "req_8k3m9n2p"
|
||||
}
|
||||
```
|
||||
|
||||
### Logger Implementation
|
||||
```typescript
|
||||
// logger/index.ts
|
||||
import winston from 'winston';
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json()
|
||||
),
|
||||
defaultMeta: {
|
||||
service: process.env.SERVICE_NAME,
|
||||
version: process.env.APP_VERSION
|
||||
},
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
format: winston.format.simple(),
|
||||
silent: process.env.NODE_ENV === 'test'
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'error.log',
|
||||
level: 'error'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
// Privacy wrapper
|
||||
export const log = {
|
||||
info: (message: string, meta?: any) => {
|
||||
logger.info(message, sanitizePII(meta));
|
||||
},
|
||||
error: (message: string, error: Error, meta?: any) => {
|
||||
logger.error(message, {
|
||||
...sanitizePII(meta),
|
||||
errorMessage: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sentry Configuration
|
||||
|
||||
### Sentry Setup
|
||||
```typescript
|
||||
// sentry.config.ts
|
||||
import * as Sentry from '@sentry/node';
|
||||
|
||||
Sentry.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
environment: process.env.NODE_ENV,
|
||||
integrations: [
|
||||
new Sentry.Integrations.Http({ tracing: true }),
|
||||
new Sentry.Integrations.Express({ app }),
|
||||
],
|
||||
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
|
||||
beforeSend(event, hint) {
|
||||
// Remove sensitive data
|
||||
if (event.request) {
|
||||
delete event.request.cookies;
|
||||
delete event.request.headers?.authorization;
|
||||
}
|
||||
|
||||
// Filter out user-caused errors
|
||||
if (event.exception?.values?.[0]?.type === 'ValidationError') {
|
||||
return null; // Don't send to Sentry
|
||||
}
|
||||
|
||||
return sanitizeEvent(event);
|
||||
},
|
||||
ignoreErrors: [
|
||||
'NetworkError',
|
||||
'Request aborted',
|
||||
'Non-Error promise rejection'
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### React Native Sentry
|
||||
```typescript
|
||||
// Mobile sentry config
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
|
||||
Sentry.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
debug: __DEV__,
|
||||
environment: __DEV__ ? 'development' : 'production',
|
||||
attachScreenshot: true,
|
||||
attachViewHierarchy: true,
|
||||
beforeSend: (event) => {
|
||||
// Don't send events in dev
|
||||
if (__DEV__) return null;
|
||||
|
||||
// Remove sensitive context
|
||||
delete event.user?.email;
|
||||
delete event.contexts?.app?.device_name;
|
||||
|
||||
return event;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Recovery Procedures
|
||||
|
||||
### Automatic Recovery
|
||||
```typescript
|
||||
// services/errorRecovery.ts
|
||||
class ErrorRecoveryService {
|
||||
async handleError(error: AppError): Promise<RecoveryAction> {
|
||||
switch (error.code) {
|
||||
case 'NET_OFFLINE':
|
||||
return this.queueForOfflineSync(error.context);
|
||||
|
||||
case 'AUTH_TOKEN_EXPIRED':
|
||||
return this.refreshToken();
|
||||
|
||||
case 'SYNC_CONFLICT':
|
||||
return this.resolveConflict(error.context);
|
||||
|
||||
case 'AI_SERVICE_UNAVAILABLE':
|
||||
return this.fallbackToOfflineAI();
|
||||
|
||||
default:
|
||||
return this.defaultRecovery(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async queueForOfflineSync(context: any) {
|
||||
await offlineQueue.add(context);
|
||||
return {
|
||||
recovered: true,
|
||||
message: 'Saved locally, will sync when online'
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### User-Guided Recovery
|
||||
```typescript
|
||||
// components/ErrorBoundary.tsx
|
||||
class ErrorBoundary extends React.Component {
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
// Log to Sentry
|
||||
Sentry.captureException(error, { contexts: { react: errorInfo } });
|
||||
|
||||
// Show recovery UI
|
||||
this.setState({
|
||||
hasError: true,
|
||||
error,
|
||||
recovery: this.getRecoveryOptions(error)
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<ErrorRecoveryScreen
|
||||
title={i18n.t('error.something_went_wrong')}
|
||||
message={i18n.t('error.we_are_sorry')}
|
||||
actions={[
|
||||
{ label: 'Try Again', onPress: this.retry },
|
||||
{ label: 'Go to Dashboard', onPress: this.reset },
|
||||
{ label: 'Contact Support', onPress: this.support }
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audit Logging
|
||||
|
||||
### COPPA/GDPR Compliance Logging
|
||||
```typescript
|
||||
interface AuditLog {
|
||||
timestamp: string;
|
||||
userId: string;
|
||||
action: AuditAction;
|
||||
entityType: string;
|
||||
entityId: string;
|
||||
changes?: Record<string, any>;
|
||||
ipAddress: string;
|
||||
userAgent: string;
|
||||
result: 'success' | 'failure';
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
enum AuditAction {
|
||||
// Data access
|
||||
VIEW_CHILD_DATA = 'VIEW_CHILD_DATA',
|
||||
EXPORT_DATA = 'EXPORT_DATA',
|
||||
|
||||
// Data modification
|
||||
CREATE_CHILD_PROFILE = 'CREATE_CHILD_PROFILE',
|
||||
UPDATE_CHILD_DATA = 'UPDATE_CHILD_DATA',
|
||||
DELETE_CHILD_DATA = 'DELETE_CHILD_DATA',
|
||||
|
||||
// Consent
|
||||
GRANT_CONSENT = 'GRANT_CONSENT',
|
||||
REVOKE_CONSENT = 'REVOKE_CONSENT',
|
||||
|
||||
// Account
|
||||
DELETE_ACCOUNT = 'DELETE_ACCOUNT',
|
||||
CHANGE_PASSWORD = 'CHANGE_PASSWORD'
|
||||
}
|
||||
```
|
||||
|
||||
### Audit Log Implementation
|
||||
```sql
|
||||
-- Audit log table with partitioning
|
||||
CREATE TABLE audit_logs (
|
||||
id BIGSERIAL,
|
||||
timestamp TIMESTAMP NOT NULL,
|
||||
user_id VARCHAR(20),
|
||||
action VARCHAR(50) NOT NULL,
|
||||
entity_type VARCHAR(50),
|
||||
entity_id VARCHAR(20),
|
||||
changes JSONB,
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
result VARCHAR(20),
|
||||
PRIMARY KEY (id, timestamp)
|
||||
) PARTITION BY RANGE (timestamp);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Monitoring
|
||||
|
||||
### Response Time Logging
|
||||
```typescript
|
||||
// middleware/performanceLogger.ts
|
||||
export const performanceLogger = (req: Request, res: Response, next: Next) => {
|
||||
const start = Date.now();
|
||||
|
||||
res.on('finish', () => {
|
||||
const duration = Date.now() - start;
|
||||
|
||||
if (duration > 1000) { // Log slow requests
|
||||
logger.warn('Slow request detected', {
|
||||
method: req.method,
|
||||
path: req.path,
|
||||
duration,
|
||||
statusCode: res.statusCode
|
||||
});
|
||||
|
||||
// Send to monitoring
|
||||
metrics.histogram('request.duration', duration, {
|
||||
path: req.path,
|
||||
method: req.method
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alert Configuration
|
||||
|
||||
### Critical Alerts
|
||||
```yaml
|
||||
# alerts/critical.yml
|
||||
alerts:
|
||||
- name: high_error_rate
|
||||
condition: error_rate > 5%
|
||||
duration: 5m
|
||||
action: page_on_call
|
||||
|
||||
- name: auth_failures_spike
|
||||
condition: auth_failures > 100
|
||||
duration: 1m
|
||||
action: security_team_alert
|
||||
|
||||
- name: ai_service_down
|
||||
condition: ai_availability < 99%
|
||||
duration: 2m
|
||||
action: notify_team
|
||||
|
||||
- name: database_connection_pool_exhausted
|
||||
condition: available_connections < 5
|
||||
action: scale_database
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Client-Side Error Tracking
|
||||
|
||||
### React Native Global Handler
|
||||
```typescript
|
||||
// errorHandler.ts
|
||||
import { setJSExceptionHandler } from 'react-native-exception-handler';
|
||||
|
||||
setJSExceptionHandler((error, isFatal) => {
|
||||
if (isFatal) {
|
||||
logger.fatal('Fatal JS error', { error });
|
||||
Alert.alert(
|
||||
'Unexpected error occurred',
|
||||
'The app needs to restart. Your data has been saved.',
|
||||
[{ text: 'Restart', onPress: () => RNRestart.Restart() }]
|
||||
);
|
||||
} else {
|
||||
logger.error('Non-fatal JS error', { error });
|
||||
// Show toast notification
|
||||
Toast.show({
|
||||
type: 'error',
|
||||
text1: 'Something went wrong',
|
||||
text2: 'Please try again'
|
||||
});
|
||||
}
|
||||
}, true); // Allow in production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Analytics Dashboard
|
||||
|
||||
### Key Metrics
|
||||
```typescript
|
||||
interface ErrorMetrics {
|
||||
errorRate: number; // Errors per 1000 requests
|
||||
errorTypes: Record<string, number>; // Count by error code
|
||||
affectedUsers: number; // Unique users with errors
|
||||
recoveryRate: number; // % of errors recovered
|
||||
meanTimeToRecovery: number; // Seconds
|
||||
criticalErrors: ErrorEvent[]; // P0 errors
|
||||
}
|
||||
|
||||
// Monitoring queries
|
||||
const getErrorMetrics = async (timeRange: TimeRange): Promise<ErrorMetrics> => {
|
||||
const errors = await db.query(`
|
||||
SELECT
|
||||
COUNT(*) as total_errors,
|
||||
COUNT(DISTINCT user_id) as affected_users,
|
||||
AVG(recovery_time) as mttr,
|
||||
error_code,
|
||||
COUNT(*) as count
|
||||
FROM error_logs
|
||||
WHERE timestamp > $1
|
||||
GROUP BY error_code
|
||||
`, [timeRange.start]);
|
||||
|
||||
return processMetrics(errors);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Error Tools
|
||||
|
||||
### Debug Mode Enhancements
|
||||
```typescript
|
||||
// Development only error overlay
|
||||
if (__DEV__) {
|
||||
// Show detailed error information
|
||||
ErrorUtils.setGlobalHandler((error, isFatal) => {
|
||||
console.group('🔴 Error Details');
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
console.error('Component Stack:', error.componentStack);
|
||||
console.error('Fatal:', isFatal);
|
||||
console.groupEnd();
|
||||
});
|
||||
|
||||
// Network request inspector
|
||||
global.XMLHttpRequest = decorateXHR(global.XMLHttpRequest);
|
||||
}
|
||||
```
|
||||
782
docs/maternal-app-implementation-plan.md
Normal file
782
docs/maternal-app-implementation-plan.md
Normal file
@@ -0,0 +1,782 @@
|
||||
# Implementation Plan - AI-Powered Maternal Organization App
|
||||
|
||||
## AI Coding Assistant Role Guide
|
||||
|
||||
### How to Use This Document with AI
|
||||
|
||||
Each phase specifies a role for the AI assistant to adopt, ensuring appropriate expertise and focus. When starting a new phase, instruct the AI with the specified role prompt to get optimal results.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```
|
||||
"For this phase, act as a Senior Backend Architect with expertise in NestJS and PostgreSQL. Focus on security, scalability, and proper architectural patterns."
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 0: Development Environment Setup (Week 0)
|
||||
|
||||
### 🤖 AI Role: Senior DevOps Engineer & System Architect
|
||||
|
||||
```
|
||||
"Act as a Senior DevOps Engineer with expertise in Docker, PostgreSQL, Redis, and cloud infrastructure. Focus on creating a robust, scalable development environment with proper security configurations."
|
||||
```
|
||||
|
||||
### Infrastructure Setup
|
||||
|
||||
```bash
|
||||
# Required installations - See Technical Stack document for complete list
|
||||
- Node.js 18+ LTS
|
||||
- React Native CLI
|
||||
- Expo CLI
|
||||
- Docker & Docker Compose
|
||||
- PostgreSQL 15+
|
||||
- Redis 7+
|
||||
- MongoDB 6+ (for AI chat history)
|
||||
- MinIO (for file storage)
|
||||
- Git
|
||||
```
|
||||
|
||||
### Project Initialization
|
||||
|
||||
```bash
|
||||
# Frontend setup - Reference Technical Stack document
|
||||
npx create-expo-app maternal-app --template
|
||||
cd maternal-app
|
||||
npm install react-navigation react-native-paper redux-toolkit
|
||||
# Additional packages from Technical Stack document
|
||||
|
||||
# Backend setup
|
||||
nest new maternal-app-backend
|
||||
cd maternal-app-backend
|
||||
npm install @nestjs/websockets @nestjs/typeorm @nestjs/jwt
|
||||
```
|
||||
|
||||
### Development Tools Configuration
|
||||
|
||||
- Set up ESLint, Prettier, Husky
|
||||
- Configure VS Code with recommended extensions
|
||||
- Initialize Git repositories with .gitignore
|
||||
- **Configure environment variables** - See Environment Configuration Guide for complete .env setup
|
||||
- Configure Docker Compose - Use docker-compose.yml from Environment Configuration Guide
|
||||
|
||||
### AI Service Setup
|
||||
|
||||
- **Configure AI services** - See Environment Configuration Guide for API keys
|
||||
- **LangChain setup** - See AI Context & Prompting Templates document
|
||||
- Rate limiting configuration (100 requests/minute per user)
|
||||
|
||||
-----
|
||||
|
||||
## Phase 1: Foundation & Authentication (Week 1-2)
|
||||
|
||||
### 🤖 AI Role: Senior Backend Developer & Security Expert
|
||||
|
||||
```
|
||||
"Act as a Senior Backend Developer specializing in NestJS, PostgreSQL, and JWT authentication. Focus on security best practices, OWASP compliance, and building a scalable authentication system with device fingerprinting."
|
||||
```
|
||||
|
||||
### 1.1 Database Schema Design
|
||||
|
||||
```sql
|
||||
-- Use complete schema from Database Migration Scripts document
|
||||
-- Run migrations V001 through V007 in sequence
|
||||
-- See Database Migration Scripts for rollback procedures
|
||||
```
|
||||
|
||||
### 1.2 Authentication System
|
||||
|
||||
```typescript
|
||||
// Backend: NestJS Auth Module
|
||||
// Complete implementation in API Specification Document - Authentication Endpoints section
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
JwtModule.register({
|
||||
secret: process.env.JWT_SECRET,
|
||||
signOptions: { expiresIn: '1h' }, // Access token
|
||||
// Refresh token handled separately - see API Specification
|
||||
}),
|
||||
PassportModule,
|
||||
],
|
||||
providers: [AuthService, JwtStrategy, LocalStrategy],
|
||||
controllers: [AuthController],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
// Implement endpoints from API Specification Document:
|
||||
POST /api/v1/auth/register (with device fingerprinting)
|
||||
POST /api/v1/auth/login
|
||||
POST /api/v1/auth/refresh
|
||||
POST /api/v1/auth/logout
|
||||
```
|
||||
|
||||
### 1.3 Mobile Authentication UI
|
||||
|
||||
```typescript
|
||||
// React Native Screens - Follow UI/UX Design System document
|
||||
// Use Material Design components and warm color palette
|
||||
- SplashScreen.tsx
|
||||
- OnboardingScreen.tsx
|
||||
- LoginScreen.tsx (implement design from UI/UX Design System)
|
||||
- RegisterScreen.tsx
|
||||
- ForgotPasswordScreen.tsx
|
||||
|
||||
// Key components with Material Design
|
||||
- BiometricLogin component
|
||||
- SocialLoginButtons (Google/Apple)
|
||||
- SecureTextInput component (min-height: 48px for touch targets)
|
||||
```
|
||||
|
||||
### 1.4 Internationalization Setup
|
||||
|
||||
```javascript
|
||||
// i18n configuration - 5 languages from MVP Features document
|
||||
// See Error Handling & Logging Standards for localized error messages
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
// Language files structure
|
||||
/locales
|
||||
/en-US
|
||||
/es-ES
|
||||
/fr-FR
|
||||
/pt-BR
|
||||
/zh-CN
|
||||
```
|
||||
|
||||
### Deliverables Week 1-2
|
||||
|
||||
- [ ] Working authentication flow with JWT + Refresh tokens
|
||||
- [ ] Device fingerprinting (see API Specification)
|
||||
- [ ] Secure password storage with bcrypt
|
||||
- [ ] Email verification system
|
||||
- [ ] Multi-language support (5 languages)
|
||||
- [ ] Material Design UI components
|
||||
|
||||
-----
|
||||
|
||||
## Phase 2: Child Profiles & Family Management (Week 2-3)
|
||||
|
||||
### 🤖 AI Role: Full-Stack Developer with Real-time Systems Experience
|
||||
|
||||
```
|
||||
"Act as a Full-Stack Developer with expertise in React Native, NestJS, WebSockets, and Redis. Focus on building real-time synchronization, family data management, and responsive mobile UI with Material Design."
|
||||
```
|
||||
|
||||
### 2.1 Child Profile CRUD Operations
|
||||
|
||||
```typescript
|
||||
// API Endpoints - Full specifications in API Specification Document
|
||||
// See "Children Management Endpoints" section for complete schemas
|
||||
|
||||
POST /api/v1/children
|
||||
GET /api/v1/children/:id
|
||||
PUT /api/v1/children/:id
|
||||
DELETE /api/v1/children/:id
|
||||
|
||||
// Use State Management Schema for Redux structure
|
||||
// Children slice with normalized state shape
|
||||
```
|
||||
|
||||
### 2.2 Family Invitation System
|
||||
|
||||
```typescript
|
||||
// Complete flow in API Specification Document - "Family Management Endpoints"
|
||||
POST /api/v1/families/invite
|
||||
POST /api/v1/families/join/:shareCode
|
||||
|
||||
// Error handling from Error Handling & Logging Standards
|
||||
// Use error codes: LIMIT_FAMILY_SIZE_EXCEEDED, AUTH_DEVICE_NOT_TRUSTED
|
||||
```
|
||||
|
||||
### 2.3 Real-time Family Sync Setup
|
||||
|
||||
```typescript
|
||||
// WebSocket implementation - See API Specification Document "WebSocket Events"
|
||||
// State sync via State Management Schema - Sync Slice
|
||||
|
||||
@WebSocketGateway()
|
||||
export class FamilyGateway {
|
||||
// Implementation details in API Specification
|
||||
// Use sync middleware from State Management Schema
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 Mobile Family Management UI
|
||||
|
||||
```typescript
|
||||
// Screens following UI/UX Design System
|
||||
// Material Design with warm color palette (peach, coral, rose)
|
||||
// Minimum touch targets: 44x44px
|
||||
|
||||
- FamilyDashboard.tsx (use card components from Design System)
|
||||
- AddChildScreen.tsx (spacious layout for one-handed use)
|
||||
- ChildProfileScreen.tsx
|
||||
- InviteFamilyMember.tsx
|
||||
- FamilySettings.tsx
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 3: Core Tracking Features (Week 3-4)
|
||||
|
||||
### 🤖 AI Role: Mobile Developer & Offline-First Systems Expert
|
||||
|
||||
```
|
||||
"Act as a Senior Mobile Developer specializing in React Native, offline-first architecture, and voice interfaces. Focus on building intuitive tracking features with voice input, offline support, and seamless sync using Redux and SQLite."
|
||||
```
|
||||
|
||||
### 3.1 Database Schema for Activities
|
||||
|
||||
```sql
|
||||
-- Use Migration V003 from Database Migration Scripts document
|
||||
-- Includes partitioned tables for scalability
|
||||
-- Run performance optimization indexes from Migration V005
|
||||
```
|
||||
|
||||
### 3.2 Activity Tracking Services
|
||||
|
||||
```typescript
|
||||
// Backend services - See API Specification "Activity Tracking Endpoints"
|
||||
// Implement all REST endpoints with proper error codes
|
||||
|
||||
@Injectable()
|
||||
export class TrackingService {
|
||||
// Use error codes from Error Handling & Logging Standards
|
||||
// Implement offline queue from State Management Schema
|
||||
|
||||
async logFeeding(data: FeedingDto) {
|
||||
// Follow API schema from specification
|
||||
// Emit WebSocket events per API Specification
|
||||
// Update Redux state per State Management Schema
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Voice Input Integration
|
||||
|
||||
```typescript
|
||||
// Complete implementation in Voice Input Processing Guide
|
||||
// Multi-language patterns for all 5 MVP languages
|
||||
// Whisper API configuration from Environment Configuration Guide
|
||||
|
||||
import { WhisperService } from './services/whisperService';
|
||||
// Use natural language patterns from Voice Input Processing Guide
|
||||
// Implement error recovery and clarification prompts
|
||||
```
|
||||
|
||||
### 3.4 Tracking UI Components
|
||||
|
||||
```typescript
|
||||
// Follow UI/UX Design System specifications
|
||||
// Material Design components with warm palette
|
||||
// One-handed operation optimization (bottom 60% of screen)
|
||||
|
||||
- QuickActionButtons.tsx (FAB positioning from Design System)
|
||||
- FeedingTimer.tsx
|
||||
- SleepTracker.tsx
|
||||
- DiaperLogger.tsx
|
||||
- ActivityTimeline.tsx (use skeleton screens for loading)
|
||||
```
|
||||
|
||||
### 3.5 Offline Support Implementation
|
||||
|
||||
```typescript
|
||||
// Complete offline architecture in State Management Schema
|
||||
// See Offline Slice and middleware configuration
|
||||
// Sync queue implementation from Sync Slice
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 4: AI Assistant Integration (Week 4-5)
|
||||
|
||||
### 🤖 AI Role: AI/ML Engineer & LLM Integration Specialist
|
||||
|
||||
```
|
||||
"Act as an AI/ML Engineer with expertise in LangChain, OpenAI APIs, prompt engineering, and safety systems. Focus on building a helpful, safe, and contextually aware AI assistant with proper token management and response quality."
|
||||
```
|
||||
|
||||
### Context Review:
|
||||
|
||||
```
|
||||
"Also review as a Child Safety Expert to ensure all AI responses are appropriate for parenting contexts and include proper medical disclaimers."
|
||||
```
|
||||
|
||||
### 4.1 LLM Service Setup
|
||||
|
||||
```typescript
|
||||
// Complete LangChain configuration in AI Context & Prompting Templates document
|
||||
// Use system prompts and safety boundaries from the document
|
||||
|
||||
import { initializeLangChain } from './config/langchain';
|
||||
// See AI Context & Prompting Templates for:
|
||||
// - Context window management (4000 tokens)
|
||||
// - Safety boundaries and medical disclaimers
|
||||
// - Personalization engine
|
||||
```
|
||||
|
||||
### 4.2 Context Management System
|
||||
|
||||
```typescript
|
||||
// Full implementation in AI Context & Prompting Templates
|
||||
// Priority weighting system for context selection
|
||||
|
||||
class AIContextBuilder {
|
||||
// Use ContextManager from AI Context & Prompting Templates
|
||||
// Implements token counting and prioritization
|
||||
// Child-specific context templates
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Chat Interface Implementation
|
||||
|
||||
```typescript
|
||||
// React Native Chat UI
|
||||
// Follow UI/UX Design System for chat bubbles
|
||||
// Implement localized responses from AI Context & Prompting Templates
|
||||
|
||||
const AIAssistantScreen = () => {
|
||||
// Use conversation memory management from AI Context document
|
||||
// Implement prompt injection protection
|
||||
// Apply response formatting templates
|
||||
};
|
||||
```
|
||||
|
||||
### 4.4 Smart Notifications System
|
||||
|
||||
```typescript
|
||||
// Use patterns from API Specification - Analytics & Insights Endpoints
|
||||
// Schedule based on predictions from AI
|
||||
|
||||
class SmartNotificationService {
|
||||
// Reference notification preferences from Database Migration V006
|
||||
// Use push notification setup from Environment Configuration Guide
|
||||
}
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 5: Pattern Recognition & Analytics (Week 5-6)
|
||||
|
||||
### 🤖 AI Role: Data Scientist & Analytics Engineer
|
||||
|
||||
```
|
||||
"Act as a Data Scientist with expertise in time-series analysis, pattern recognition, and data visualization. Focus on building accurate prediction algorithms, meaningful insights extraction, and clear data presentation using React Native charts."
|
||||
```
|
||||
|
||||
### Context Review:
|
||||
|
||||
```
|
||||
"Review predictions as a Pediatric Data Analyst to ensure all insights are age-appropriate and medically sound."
|
||||
```
|
||||
|
||||
### 5.1 Pattern Analysis Engine
|
||||
|
||||
```typescript
|
||||
// Pattern detection algorithms referenced in API Specification
|
||||
// See "Analytics & Insights Endpoints" for complete schemas
|
||||
|
||||
@Injectable()
|
||||
export class PatternAnalysisService {
|
||||
// GraphQL queries from API Specification for complex data
|
||||
// Use AI Context & Prompting Templates for pattern insights
|
||||
|
||||
async analyzeSleepPatterns(childId: string) {
|
||||
// Implement sleep prediction from Voice Input Processing Guide
|
||||
// Store predictions in State Management Schema - AI Slice
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Predictive Algorithms
|
||||
|
||||
```typescript
|
||||
// Sleep prediction using patterns from API Specification
|
||||
// Response format from "GET /api/v1/insights/{childId}/predictions"
|
||||
|
||||
class SleepPredictor {
|
||||
// Algorithm matches Huckleberry's SweetSpot® approach
|
||||
// 85% confidence target from API Specification
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Analytics Dashboard
|
||||
|
||||
```typescript
|
||||
// Dashboard Components using UI/UX Design System
|
||||
// Material Design cards and charts
|
||||
// Victory Native from Technical Stack document
|
||||
|
||||
- WeeklySleepChart.tsx (use warm color palette)
|
||||
- FeedingFrequencyGraph.tsx
|
||||
- GrowthCurve.tsx (WHO percentiles)
|
||||
- PatternInsights.tsx
|
||||
- ExportReport.tsx
|
||||
```
|
||||
|
||||
### 5.4 Report Generation
|
||||
|
||||
```typescript
|
||||
// PDF generation using libraries from Technical Stack
|
||||
// GraphQL WeeklyReport query from API Specification
|
||||
|
||||
class ReportGenerator {
|
||||
// Use report formatting from UI/UX Design System
|
||||
// Include localized content for all 5 languages
|
||||
}
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 6: Testing & Optimization (Week 6-7)
|
||||
|
||||
### 🤖 AI Role: QA Engineer & Performance Specialist
|
||||
|
||||
```
|
||||
"Act as a Senior QA Engineer with expertise in Jest, Detox, performance testing, and accessibility compliance. Focus on comprehensive test coverage, performance optimization, and ensuring WCAG compliance."
|
||||
```
|
||||
|
||||
### Context Reviews:
|
||||
|
||||
```
|
||||
1. "Review as a Security Auditor for vulnerability assessment"
|
||||
2. "Review as an Accessibility Expert for WCAG AA/AAA compliance"
|
||||
3. "Review as a Performance Engineer for optimization opportunities"
|
||||
```
|
||||
|
||||
### 6.1 Unit Testing Implementation
|
||||
|
||||
```typescript
|
||||
// Complete testing strategy in Testing Strategy Document
|
||||
// 80% code coverage requirement
|
||||
// Use mock data structures from Testing Strategy Document
|
||||
|
||||
describe('TrackingService', () => {
|
||||
// Test examples from Testing Strategy Document
|
||||
// Use error codes from Error Handling & Logging Standards
|
||||
});
|
||||
|
||||
describe('SleepPredictor', () => {
|
||||
// Performance benchmarks from Testing Strategy Document
|
||||
// 85% accuracy target for predictions
|
||||
});
|
||||
```
|
||||
|
||||
### 6.2 Integration Testing
|
||||
|
||||
```typescript
|
||||
// E2E tests with Detox - See Testing Strategy Document
|
||||
// Critical user journeys and offline sync testing
|
||||
|
||||
describe('Complete tracking flow', () => {
|
||||
// Test WebSocket sync from API Specification
|
||||
// Verify offline queue from State Management Schema
|
||||
});
|
||||
```
|
||||
|
||||
### 6.3 Performance Optimization
|
||||
|
||||
```typescript
|
||||
// React Native optimizations from UI/UX Design System
|
||||
// - 60fps scrolling requirement
|
||||
// - 2-second max load time
|
||||
// - Skeleton screens for loading states
|
||||
|
||||
// Backend optimizations from Database Migration Scripts
|
||||
// - Partitioned tables for activities
|
||||
// - Performance indexes from Migration V005
|
||||
// - Redis caching from Environment Configuration
|
||||
```
|
||||
|
||||
### 6.4 Security Audit
|
||||
|
||||
```bash
|
||||
# Security checklist from multiple documents:
|
||||
# - API Specification: Request signing, rate limiting
|
||||
# - Environment Configuration: Secret rotation schedule
|
||||
# - Database Migrations: COPPA/GDPR compliance tables
|
||||
# - Error Handling: Audit logging implementation
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 7: Beta Testing & Launch Preparation (Week 7-8)
|
||||
|
||||
### 🤖 AI Role: DevOps Engineer & Mobile Deployment Specialist
|
||||
|
||||
```
|
||||
"Act as a DevOps Engineer with expertise in CI/CD, mobile app deployment, TestFlight, Google Play Console, and production infrastructure. Focus on automated deployment pipelines, monitoring setup, and app store compliance."
|
||||
```
|
||||
|
||||
### Context Review:
|
||||
|
||||
```
|
||||
"Review as a Compliance Officer for COPPA/GDPR requirements and app store policies"
|
||||
```
|
||||
|
||||
### 7.1 Beta Testing Program
|
||||
|
||||
```markdown
|
||||
# Beta Testing Plan from Testing Strategy Document
|
||||
- Recruit 50 diverse families (language/geography diversity)
|
||||
- Testing groups from Mobile Build & Deployment Guide
|
||||
- Use TestFlight/Play Console setup from Mobile Build & Deployment Guide
|
||||
- Feedback collection via Testing Strategy Document metrics
|
||||
```
|
||||
|
||||
### 7.2 App Store Preparation
|
||||
|
||||
```markdown
|
||||
# Complete requirements from Mobile Build & Deployment Guide
|
||||
# iOS App Store - see "TestFlight Configuration" section
|
||||
# Google Play Store - see "Google Play Console Configuration" section
|
||||
|
||||
# Store assets using UI/UX Design System guidelines:
|
||||
- Screenshots with warm color palette
|
||||
- App icon with peach/coral branding
|
||||
- Localized descriptions for 5 languages
|
||||
```
|
||||
|
||||
### 7.3 Monitoring Setup
|
||||
|
||||
```typescript
|
||||
// Sentry configuration from Environment Configuration Guide
|
||||
// Error tracking setup from Error Handling & Logging Standards
|
||||
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
// Use Sentry DSN from Environment Configuration
|
||||
// Implement error filtering from Error Handling document
|
||||
|
||||
// Analytics from Technical Stack document (PostHog/Matomo)
|
||||
```
|
||||
|
||||
### 7.4 Production Infrastructure
|
||||
|
||||
```yaml
|
||||
# Use docker-compose.yml from Environment Configuration Guide
|
||||
# Add production settings from Mobile Build & Deployment Guide
|
||||
# Include all services from Technical Stack:
|
||||
# - PostgreSQL, MongoDB, Redis, MinIO
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Phase 8: Launch & Post-Launch (Week 8+)
|
||||
|
||||
### 🤖 AI Role: Product Manager & Growth Engineer
|
||||
|
||||
```
|
||||
"Act as a Product Manager with expertise in user analytics, growth strategies, and iterative development. Focus on monitoring key metrics, user feedback analysis, and rapid iteration based on real-world usage."
|
||||
```
|
||||
|
||||
### Context Reviews:
|
||||
|
||||
```
|
||||
1. "Analyze as a Data Analyst for user behavior patterns"
|
||||
2. "Review as a Customer Success Manager for support improvements"
|
||||
3. "Evaluate as a Growth Hacker for retention optimization"
|
||||
```
|
||||
|
||||
### 8.1 Launch Checklist
|
||||
|
||||
```markdown
|
||||
## Technical - Reference Mobile Build & Deployment Guide
|
||||
- [ ] Production environment live (Environment Configuration Guide)
|
||||
- [ ] SSL certificates configured
|
||||
- [ ] CDN configured (Technical Stack - performance section)
|
||||
- [ ] Backup systems tested (Database Migration Scripts - maintenance)
|
||||
- [ ] Monitoring dashboards active (Error Handling & Logging Standards)
|
||||
- [ ] Error tracking enabled (Sentry setup)
|
||||
- [ ] Analytics tracking verified (PostHog/Matomo)
|
||||
|
||||
## Legal
|
||||
- [ ] Privacy policy published (COPPA/GDPR from Database Migrations)
|
||||
- [ ] Terms of service published
|
||||
- [ ] Compliance verified (Audit tables from Migration V007)
|
||||
|
||||
## Support
|
||||
- [ ] Help documentation complete
|
||||
- [ ] Multi-language support ready (5 languages)
|
||||
- [ ] Error messages localized (Error Handling document)
|
||||
```
|
||||
|
||||
### 8.2 Post-Launch Monitoring
|
||||
|
||||
```typescript
|
||||
// Key metrics from Testing Strategy Document
|
||||
// Success criteria: 60% DAU, <2% crash rate, 4.0+ rating
|
||||
|
||||
const metrics = {
|
||||
// Track via analytics setup from Environment Configuration
|
||||
// Use error monitoring from Error Handling & Logging Standards
|
||||
// Performance metrics from API Specification (p95 < 3s)
|
||||
};
|
||||
```
|
||||
|
||||
### 8.3 Rapid Iteration Plan
|
||||
|
||||
```markdown
|
||||
# Use CodePush from Mobile Build & Deployment Guide for OTA updates
|
||||
# Follow staged rollout strategy from Mobile Build & Deployment Guide
|
||||
|
||||
# Week 1-2: Monitor error codes from Error Handling document
|
||||
# Week 3-4: UI improvements based on Design System principles
|
||||
# Month 2: Premium features from MVP Features document
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Development Best Practices
|
||||
|
||||
### Code Organization
|
||||
|
||||
```
|
||||
/maternal-app
|
||||
/src
|
||||
/components
|
||||
/common
|
||||
/tracking
|
||||
/ai
|
||||
/screens
|
||||
/services
|
||||
/hooks
|
||||
/utils
|
||||
/redux
|
||||
/slices
|
||||
/actions
|
||||
/locales
|
||||
/navigation
|
||||
/types
|
||||
|
||||
/maternal-app-backend
|
||||
/src
|
||||
/modules
|
||||
/auth
|
||||
/users
|
||||
/families
|
||||
/tracking
|
||||
/ai
|
||||
/common
|
||||
/guards
|
||||
/interceptors
|
||||
/filters
|
||||
/database
|
||||
/entities
|
||||
/migrations
|
||||
```
|
||||
|
||||
### Git Workflow
|
||||
|
||||
```bash
|
||||
# Branch naming
|
||||
feature/track-feeding
|
||||
bugfix/sync-issue
|
||||
hotfix/crash-on-login
|
||||
|
||||
# Commit messages
|
||||
feat: add voice input for feeding tracker
|
||||
fix: resolve timezone sync issue
|
||||
docs: update API documentation
|
||||
test: add unit tests for sleep predictor
|
||||
```
|
||||
|
||||
### CI/CD Pipeline
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
name: CI/CD Pipeline
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
- run: npm run lint
|
||||
|
||||
build:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: npm run build
|
||||
- run: docker build
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- run: ./deploy.sh
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Risk Mitigation Strategies
|
||||
|
||||
### Technical Risks
|
||||
|
||||
1. **LLM API Downtime**
|
||||
- Implement fallback to cached responses
|
||||
- Queue queries for retry
|
||||
- Basic rule-based responses as backup
|
||||
1. **Scalability Issues**
|
||||
- Start with vertical scaling capability
|
||||
- Design for horizontal scaling from day 1
|
||||
- Implement caching aggressively
|
||||
1. **Data Loss**
|
||||
- Automated backups every 6 hours
|
||||
- Point-in-time recovery capability
|
||||
- Multi-region backup storage
|
||||
|
||||
### Business Risks
|
||||
|
||||
1. **Low User Adoption**
|
||||
- Quick onboarding (< 2 minutes)
|
||||
- Immediate value demonstration
|
||||
- Strong referral incentives
|
||||
1. **High Churn Rate**
|
||||
- Weekly engagement emails
|
||||
- Push notification optimization
|
||||
- Feature discovery prompts
|
||||
1. **Competitive Pressure**
|
||||
- Rapid feature iteration
|
||||
- Strong AI differentiation
|
||||
- Community building
|
||||
|
||||
-----
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### MVP Launch Success
|
||||
|
||||
- 1,000 downloads in first month
|
||||
- 60% day-7 retention
|
||||
- 4.0+ app store rating
|
||||
- <2% crash rate
|
||||
- 5+ activities logged per day per active user
|
||||
- 70% of users trying AI assistant
|
||||
|
||||
### 3-Month Goals
|
||||
|
||||
- 10,000 active users
|
||||
- 500 premium subscribers
|
||||
- 50% month-over-month growth
|
||||
- 4.5+ app store rating
|
||||
- 3 major feature updates
|
||||
- 2 partnership agreements
|
||||
|
||||
### 6-Month Vision
|
||||
|
||||
- 50,000 active users
|
||||
- 2,500 premium subscribers
|
||||
- Break-even on operational costs
|
||||
- International expansion (10+ countries)
|
||||
- Integration ecosystem launched
|
||||
- Series A fundraising ready
|
||||
590
docs/maternal-app-mobile-deployment.md
Normal file
590
docs/maternal-app-mobile-deployment.md
Normal file
@@ -0,0 +1,590 @@
|
||||
# Mobile Build & Deployment Guide - Maternal Organization App
|
||||
|
||||
## Build Environment Setup
|
||||
|
||||
### Prerequisites
|
||||
```bash
|
||||
# Required tools
|
||||
node >= 18.0.0
|
||||
npm >= 9.0.0
|
||||
react-native-cli >= 2.0.1
|
||||
expo-cli >= 6.0.0
|
||||
cocoapods >= 1.12.0 (iOS)
|
||||
java 11 (Android)
|
||||
android-studio (Android)
|
||||
xcode >= 14.0 (iOS)
|
||||
```
|
||||
|
||||
### Project Initialization
|
||||
```bash
|
||||
# Create project with Expo
|
||||
npx create-expo-app maternal-app --template
|
||||
|
||||
# Install core dependencies
|
||||
cd maternal-app
|
||||
npm install react-native-reanimated react-native-gesture-handler
|
||||
npm install react-native-safe-area-context react-native-screens
|
||||
npm install @react-navigation/native @react-navigation/bottom-tabs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## iOS Configuration
|
||||
|
||||
### Bundle Identifier & Provisioning
|
||||
```xml
|
||||
<!-- ios/MaternalApp/Info.plist -->
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.maternalapp.ios</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Maternal</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
```
|
||||
|
||||
### App Capabilities
|
||||
```xml
|
||||
<!-- ios/MaternalApp/MaternalApp.entitlements -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>production</string>
|
||||
<key>com.apple.developer.healthkit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.healthkit.background-delivery</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.maternalapp.shared</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### Permissions
|
||||
```xml
|
||||
<!-- ios/MaternalApp/Info.plist -->
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Take photos of your child for memories and milestone tracking</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Enable voice input for hands-free activity logging</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Select photos for your child's profile and milestones</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>Convert your voice to text for quick logging</string>
|
||||
<key>NSHealthShareUsageDescription</key>
|
||||
<string>Read health data to track your child's growth</string>
|
||||
<key>NSHealthUpdateUsageDescription</key>
|
||||
<string>Save growth measurements to Health app</string>
|
||||
```
|
||||
|
||||
### Code Signing Configuration
|
||||
```ruby
|
||||
# ios/fastlane/Fastfile
|
||||
platform :ios do
|
||||
desc "Build and deploy to TestFlight"
|
||||
lane :beta do
|
||||
increment_build_number
|
||||
|
||||
match(
|
||||
type: "appstore",
|
||||
app_identifier: "com.maternalapp.ios",
|
||||
git_url: "git@github.com:maternal-app/certificates.git"
|
||||
)
|
||||
|
||||
gym(
|
||||
scheme: "MaternalApp",
|
||||
configuration: "Release",
|
||||
export_method: "app-store",
|
||||
output_directory: "./build",
|
||||
output_name: "MaternalApp.ipa"
|
||||
)
|
||||
|
||||
pilot(
|
||||
ipa: "./build/MaternalApp.ipa",
|
||||
skip_waiting_for_build_processing: true,
|
||||
changelog: "Bug fixes and performance improvements"
|
||||
)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Android Configuration
|
||||
|
||||
### Package Name & Versioning
|
||||
```gradle
|
||||
// android/app/build.gradle
|
||||
android {
|
||||
compileSdkVersion 34
|
||||
buildToolsVersion "34.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.maternalapp.android"
|
||||
minSdkVersion 23 // Android 6.0
|
||||
targetSdkVersion 34
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file(MATERNAL_RELEASE_STORE_FILE)
|
||||
storePassword MATERNAL_RELEASE_STORE_PASSWORD
|
||||
keyAlias MATERNAL_RELEASE_KEY_ALIAS
|
||||
keyPassword MATERNAL_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Permissions
|
||||
```xml
|
||||
<!-- android/app/src/main/AndroidManifest.xml -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<!-- Google Play Services -->
|
||||
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" />
|
||||
```
|
||||
|
||||
### ProGuard Rules
|
||||
```pro
|
||||
# android/app/proguard-rules.pro
|
||||
-keep class com.maternalapp.** { *; }
|
||||
-keep class com.facebook.react.** { *; }
|
||||
-keep class com.swmansion.** { *; }
|
||||
|
||||
# React Native
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
|
||||
|
||||
# Firebase
|
||||
-keep class com.google.firebase.** { *; }
|
||||
-keep class com.google.android.gms.** { *; }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment-Specific Builds
|
||||
|
||||
### Build Configurations
|
||||
```javascript
|
||||
// app.config.js
|
||||
export default ({ config }) => {
|
||||
const buildType = process.env.BUILD_TYPE || 'development';
|
||||
|
||||
const configs = {
|
||||
development: {
|
||||
name: 'Maternal (Dev)',
|
||||
bundleIdentifier: 'com.maternalapp.dev',
|
||||
apiUrl: 'https://dev-api.maternalapp.com',
|
||||
icon: './assets/icon-dev.png',
|
||||
},
|
||||
staging: {
|
||||
name: 'Maternal (Staging)',
|
||||
bundleIdentifier: 'com.maternalapp.staging',
|
||||
apiUrl: 'https://staging-api.maternalapp.com',
|
||||
icon: './assets/icon-staging.png',
|
||||
},
|
||||
production: {
|
||||
name: 'Maternal',
|
||||
bundleIdentifier: 'com.maternalapp.ios',
|
||||
apiUrl: 'https://api.maternalapp.com',
|
||||
icon: './assets/icon.png',
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
...config,
|
||||
...configs[buildType],
|
||||
ios: {
|
||||
...config.ios,
|
||||
bundleIdentifier: configs[buildType].bundleIdentifier,
|
||||
buildNumber: '1',
|
||||
},
|
||||
android: {
|
||||
...config.android,
|
||||
package: configs[buildType].bundleIdentifier.replace('ios', 'android'),
|
||||
versionCode: 1,
|
||||
},
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
# .env.production
|
||||
API_URL=https://api.maternalapp.com
|
||||
SENTRY_DSN=https://prod-sentry.maternalapp.com
|
||||
ANALYTICS_ENABLED=true
|
||||
CRASH_REPORTING=true
|
||||
|
||||
# .env.staging
|
||||
API_URL=https://staging-api.maternalapp.com
|
||||
SENTRY_DSN=https://staging-sentry.maternalapp.com
|
||||
ANALYTICS_ENABLED=true
|
||||
CRASH_REPORTING=true
|
||||
|
||||
# .env.development
|
||||
API_URL=http://localhost:3000
|
||||
SENTRY_DSN=
|
||||
ANALYTICS_ENABLED=false
|
||||
CRASH_REPORTING=false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
### GitHub Actions Workflow
|
||||
```yaml
|
||||
# .github/workflows/mobile-deploy.yml
|
||||
name: Mobile Build & Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, staging]
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
- run: npm run lint
|
||||
|
||||
build-ios:
|
||||
needs: test
|
||||
runs-on: macos-latest
|
||||
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
cd ios && pod install
|
||||
|
||||
- name: Setup certificates
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE_BASE64 }}
|
||||
PROVISION_PROFILE_BASE64: ${{ secrets.IOS_PROVISION_PROFILE_BASE64 }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# Create keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
# Import certificate
|
||||
echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12
|
||||
security import certificate.p12 -k build.keychain -P "${{ secrets.CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign
|
||||
|
||||
# Import provisioning profile
|
||||
echo "$PROVISION_PROFILE_BASE64" | base64 --decode > profile.mobileprovision
|
||||
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
|
||||
|
||||
- name: Build IPA
|
||||
run: |
|
||||
cd ios
|
||||
xcodebuild -workspace MaternalApp.xcworkspace \
|
||||
-scheme MaternalApp \
|
||||
-configuration Release \
|
||||
-archivePath $PWD/build/MaternalApp.xcarchive \
|
||||
archive
|
||||
|
||||
xcodebuild -exportArchive \
|
||||
-archivePath $PWD/build/MaternalApp.xcarchive \
|
||||
-exportPath $PWD/build \
|
||||
-exportOptionsPlist ExportOptions.plist
|
||||
|
||||
- name: Upload to TestFlight
|
||||
env:
|
||||
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
|
||||
run: |
|
||||
xcrun altool --upload-app \
|
||||
--type ios \
|
||||
--file ios/build/MaternalApp.ipa \
|
||||
--apiKey "${{ secrets.API_KEY_ID }}" \
|
||||
--apiIssuer "${{ secrets.API_ISSUER_ID }}"
|
||||
|
||||
build-android:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Setup keystore
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
run: |
|
||||
echo "$KEYSTORE_BASE64" | base64 --decode > android/app/release.keystore
|
||||
echo "MATERNAL_RELEASE_STORE_FILE=release.keystore" >> android/gradle.properties
|
||||
echo "MATERNAL_RELEASE_KEY_ALIAS=${{ secrets.ANDROID_KEY_ALIAS }}" >> android/gradle.properties
|
||||
echo "MATERNAL_RELEASE_STORE_PASSWORD=${{ secrets.ANDROID_STORE_PASSWORD }}" >> android/gradle.properties
|
||||
echo "MATERNAL_RELEASE_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/gradle.properties
|
||||
|
||||
- name: Build APK
|
||||
run: |
|
||||
cd android
|
||||
./gradlew assembleRelease
|
||||
|
||||
- name: Build AAB
|
||||
run: |
|
||||
cd android
|
||||
./gradlew bundleRelease
|
||||
|
||||
- name: Upload to Play Store
|
||||
uses: r0adkll/upload-google-play@v1
|
||||
with:
|
||||
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
|
||||
packageName: com.maternalapp.android
|
||||
releaseFiles: android/app/build/outputs/bundle/release/app-release.aab
|
||||
track: internal
|
||||
status: draft
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TestFlight Configuration
|
||||
|
||||
### App Store Connect Setup
|
||||
```javascript
|
||||
// ios/fastlane/metadata/en-US/description.txt
|
||||
Maternal is your AI-powered parenting companion, designed to reduce mental load and bring confidence to your parenting journey.
|
||||
|
||||
Key Features:
|
||||
• Smart activity tracking with voice input
|
||||
• AI assistant available 24/7 for parenting questions
|
||||
• Real-time family synchronization
|
||||
• Sleep predictions based on your baby's patterns
|
||||
• Growth tracking with WHO percentiles
|
||||
|
||||
// ios/fastlane/metadata/en-US/keywords.txt
|
||||
parenting,baby tracker,sleep tracking,feeding log,AI assistant,family app,childcare
|
||||
```
|
||||
|
||||
### Beta Testing Groups
|
||||
```yaml
|
||||
# TestFlight Groups
|
||||
internal_testing:
|
||||
name: "Internal Team"
|
||||
members: 10
|
||||
builds: all
|
||||
|
||||
beta_families:
|
||||
name: "Beta Families"
|
||||
members: 50
|
||||
builds: stable
|
||||
feedback: enabled
|
||||
|
||||
early_access:
|
||||
name: "Early Access"
|
||||
members: 500
|
||||
builds: release_candidate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Google Play Console Configuration
|
||||
|
||||
### Store Listing
|
||||
```yaml
|
||||
# Play Console Setup
|
||||
app_details:
|
||||
title: "Maternal - AI Parenting Assistant"
|
||||
short_description: "Smart parenting companion with AI support"
|
||||
full_description: |
|
||||
Complete description...
|
||||
|
||||
category: "Parenting"
|
||||
content_rating: "Everyone"
|
||||
|
||||
graphics:
|
||||
icon: 512x512px
|
||||
feature_graphic: 1024x500px
|
||||
screenshots:
|
||||
phone: [6 images minimum]
|
||||
tablet: [optional]
|
||||
```
|
||||
|
||||
### Release Tracks
|
||||
```yaml
|
||||
internal_testing:
|
||||
testers: "internal-testers@maternalapp.com"
|
||||
release_frequency: "daily"
|
||||
|
||||
closed_testing:
|
||||
testers: 100
|
||||
release_frequency: "weekly"
|
||||
|
||||
open_testing:
|
||||
countries: ["US", "CA", "GB", "AU"]
|
||||
release_frequency: "bi-weekly"
|
||||
|
||||
production:
|
||||
rollout_percentage: 10 # Start with 10%
|
||||
staged_rollout: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Over-the-Air Updates
|
||||
|
||||
### CodePush Setup
|
||||
```bash
|
||||
# Install CodePush
|
||||
npm install react-native-code-push
|
||||
|
||||
# iOS setup
|
||||
cd ios && pod install
|
||||
|
||||
# Register app with CodePush
|
||||
code-push app add Maternal-iOS ios react-native
|
||||
code-push app add Maternal-Android android react-native
|
||||
```
|
||||
|
||||
### Update Configuration
|
||||
```javascript
|
||||
// App.js
|
||||
import CodePush from 'react-native-code-push';
|
||||
|
||||
const codePushOptions = {
|
||||
checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
|
||||
installMode: CodePush.InstallMode.ON_NEXT_RESTART,
|
||||
mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,
|
||||
updateDialog: {
|
||||
title: 'Update Available',
|
||||
mandatoryUpdateMessage: 'An important update is available.',
|
||||
optionalUpdateMessage: 'An update is available. Would you like to install it?',
|
||||
},
|
||||
};
|
||||
|
||||
export default CodePush(codePushOptions)(App);
|
||||
```
|
||||
|
||||
### Deployment Commands
|
||||
```bash
|
||||
# Deploy update to staging
|
||||
code-push release-react Maternal-iOS ios -d Staging
|
||||
code-push release-react Maternal-Android android -d Staging
|
||||
|
||||
# Promote to production
|
||||
code-push promote Maternal-iOS Staging Production -r 10%
|
||||
code-push promote Maternal-Android Staging Production -r 10%
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Monitoring
|
||||
|
||||
### Build Size Optimization
|
||||
```javascript
|
||||
// metro.config.js
|
||||
module.exports = {
|
||||
transformer: {
|
||||
minifierConfig: {
|
||||
keep_fnames: true,
|
||||
mangle: {
|
||||
keep_fnames: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Bundle Analysis
|
||||
```bash
|
||||
# Analyze bundle size
|
||||
npx react-native-bundle-visualizer
|
||||
|
||||
# iOS specific
|
||||
npx react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --assets-dest ios
|
||||
|
||||
# Android specific
|
||||
cd android && ./gradlew bundleRelease --scan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pre-Launch Checklist
|
||||
|
||||
### iOS Submission
|
||||
- [ ] TestFlight build approved
|
||||
- [ ] App Store screenshots (6.5", 5.5")
|
||||
- [ ] App preview video (optional)
|
||||
- [ ] Privacy policy URL
|
||||
- [ ] Support URL
|
||||
- [ ] Marketing URL
|
||||
- [ ] Age rating questionnaire
|
||||
- [ ] Export compliance
|
||||
- [ ] App Review notes
|
||||
|
||||
### Android Submission
|
||||
- [ ] Signed AAB uploaded
|
||||
- [ ] Store listing complete
|
||||
- [ ] Content rating questionnaire
|
||||
- [ ] Target audience declaration
|
||||
- [ ] Data safety form
|
||||
- [ ] Privacy policy URL
|
||||
- [ ] App category selected
|
||||
- [ ] Closed testing feedback addressed
|
||||
|
||||
### General Requirements
|
||||
- [ ] COPPA compliance verified
|
||||
- [ ] GDPR compliance documented
|
||||
- [ ] Terms of service updated
|
||||
- [ ] Support system ready
|
||||
- [ ] Analytics tracking verified
|
||||
- [ ] Crash reporting active
|
||||
- [ ] Performance benchmarks met
|
||||
- [ ] Accessibility tested
|
||||
346
docs/maternal-app-mvp.md
Normal file
346
docs/maternal-app-mvp.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# MVP Features List - AI-Powered Maternal Organization App
|
||||
|
||||
## 🎯 MVP Goal
|
||||
Launch a functional app that solves the most acute pain points for mothers with children 0-6 years old, focusing on reducing mental load through intelligent tracking and AI-powered support.
|
||||
|
||||
## 📱 Core User Experience (Week 1-2 Priority)
|
||||
|
||||
### User Onboarding & Account Setup
|
||||
- **Quick Registration**
|
||||
- Email/phone signup with verification
|
||||
- Google/Apple social login
|
||||
- Basic profile creation (name, timezone)
|
||||
- COPPA/GDPR consent flow
|
||||
|
||||
- **Child Profile Setup**
|
||||
- Add child (name, birthdate, gender optional)
|
||||
- Support for 1-2 children (free tier)
|
||||
- Basic medical info (allergies, conditions)
|
||||
- Profile photo upload
|
||||
|
||||
- **Family Access**
|
||||
- Invite one partner/caregiver
|
||||
- Simple permission model (view/edit)
|
||||
- Share code for quick partner setup
|
||||
|
||||
## 🍼 Essential Tracking Features (Week 2-4 Priority)
|
||||
|
||||
### Feeding Tracker
|
||||
- **Quick Log Options**
|
||||
- Breast (left/right/both) with timer
|
||||
- Bottle (amount in oz/ml)
|
||||
- Start/stop timer functionality
|
||||
- Previous feeding quick-repeat
|
||||
|
||||
- **Voice Input**
|
||||
- "Baby fed 4 ounces at 3pm"
|
||||
- "Started nursing left side"
|
||||
- Natural language processing
|
||||
|
||||
### Sleep Tracker
|
||||
- **Simple Sleep Logging**
|
||||
- One-tap sleep start/end
|
||||
- Nap vs night sleep
|
||||
- Location (crib, car, stroller)
|
||||
- Quick notes option
|
||||
|
||||
- **AI Sleep Predictions** ⭐
|
||||
- Next nap time prediction
|
||||
- Wake window calculations
|
||||
- Optimal bedtime suggestions
|
||||
- Pattern recognition after 5 days
|
||||
|
||||
### Diaper Tracker
|
||||
- **Fast Diaper Logging**
|
||||
- Wet/dirty/both buttons
|
||||
- Time auto-stamps
|
||||
- Optional notes (rash, color)
|
||||
- Pattern tracking for health
|
||||
|
||||
### Growth Tracker
|
||||
- **Basic Measurements**
|
||||
- Weight entry
|
||||
- Height entry
|
||||
- Growth chart visualization
|
||||
- WHO percentile calculations
|
||||
|
||||
## 🤖 AI Assistant - The Killer Feature (Week 3-5 Priority)
|
||||
|
||||
### 24/7 Conversational Support
|
||||
- **Natural Language Chat**
|
||||
- "Why won't my baby sleep?"
|
||||
- "Is this feeding pattern normal?"
|
||||
- "What solids should I introduce?"
|
||||
- "Help with sleep regression"
|
||||
|
||||
- **Contextual Responses**
|
||||
- Uses your child's tracked data
|
||||
- Age-appropriate guidance
|
||||
- Evidence-based recommendations
|
||||
- Remembers conversation context
|
||||
|
||||
- **Safety Features**
|
||||
- Emergency resource links
|
||||
- "Consult doctor" prompts for concerns
|
||||
- Disclaimer on medical advice
|
||||
- Crisis hotline integration
|
||||
|
||||
### Smart Insights & Predictions
|
||||
- **Pattern Recognition**
|
||||
- "Your baby sleeps better after morning walks"
|
||||
- "Feeding intervals are increasing"
|
||||
- "Nap duration improving this week"
|
||||
|
||||
- **Proactive Suggestions**
|
||||
- "Based on patterns, next feeding around 2:30pm"
|
||||
- "Consider starting bedtime routine at 6:45pm"
|
||||
- "Growth spurt likely - expect increased feeding"
|
||||
|
||||
## 📅 Basic Family Coordination (Week 4-5 Priority)
|
||||
|
||||
### Real-Time Sync
|
||||
- **Instant Updates**
|
||||
- Activities sync across devices
|
||||
- Partner sees updates immediately
|
||||
- Offline mode with sync queue
|
||||
- Conflict resolution
|
||||
|
||||
### Simple Notifications
|
||||
- **Smart Reminders**
|
||||
- Medication schedules
|
||||
- Vaccination appointments
|
||||
- Custom reminders
|
||||
- Pattern-based alerts
|
||||
|
||||
### Activity Feed
|
||||
- **Family Timeline**
|
||||
- Chronological activity list
|
||||
- Filter by child/activity type
|
||||
- Today/yesterday/week views
|
||||
- Quick stats dashboard
|
||||
|
||||
## 📊 Essential Analytics (Week 5-6 Priority)
|
||||
|
||||
### Daily Summaries
|
||||
- **Overview Dashboard**
|
||||
- Today's feeding total
|
||||
- Sleep duration (day/night)
|
||||
- Last activities at a glance
|
||||
- Trends vs yesterday
|
||||
|
||||
### Weekly Patterns
|
||||
- **Simple Reports**
|
||||
- Average sleep per day
|
||||
- Feeding frequency trends
|
||||
- Growth trajectory
|
||||
- Exportable for pediatrician
|
||||
|
||||
## 🌍 Internationalization & Localization
|
||||
|
||||
### Language Support (MVP Phase)
|
||||
- **Initial Languages**
|
||||
- English (primary)
|
||||
- Spanish (large US population)
|
||||
- French (Canadian market)
|
||||
- Portuguese (Brazilian market)
|
||||
- Simplified Chinese (growth market)
|
||||
|
||||
- **Localization Framework**
|
||||
- All strings externalized from day 1
|
||||
- RTL support structure (Arabic/Hebrew ready)
|
||||
- Date/time format localization
|
||||
- Number format localization
|
||||
- Currency display for future features
|
||||
|
||||
- **AI Assistant Multilingual**
|
||||
- Responses in user's selected language
|
||||
- Language detection from voice input
|
||||
- Culturally appropriate advice
|
||||
- Local emergency resources by region
|
||||
|
||||
- **Content Localization**
|
||||
- Measurement units (metric/imperial)
|
||||
- Growth charts by region (WHO/CDC)
|
||||
- Vaccination schedules by country
|
||||
- Local pediatric guidelines
|
||||
- Timezone auto-detection
|
||||
|
||||
## 🔒 Privacy & Security Essentials
|
||||
|
||||
### Data Protection
|
||||
- **Security Basics**
|
||||
- End-to-end encryption
|
||||
- Secure authentication
|
||||
- Biometric login option
|
||||
- Auto-logout settings
|
||||
|
||||
### Privacy Controls
|
||||
- **User Control**
|
||||
- Data export capability
|
||||
- Account deletion option
|
||||
- No third-party data sharing
|
||||
- Anonymous mode available
|
||||
- Region-specific privacy compliance
|
||||
|
||||
## 📱 Technical MVP Requirements
|
||||
|
||||
### Platform Support
|
||||
- **Mobile First**
|
||||
- iOS 14+ support
|
||||
- Android 10+ support
|
||||
- Responsive design
|
||||
- Tablet optimization (Phase 2)
|
||||
|
||||
### Performance Standards
|
||||
- **User Experience**
|
||||
- 2-second max load time
|
||||
- Offline core features
|
||||
- <100MB app size
|
||||
- 60fps scrolling
|
||||
|
||||
### Accessibility Basics
|
||||
- **Inclusive Design**
|
||||
- Large touch targets (44x44 min)
|
||||
- High contrast mode
|
||||
- Text size adjustment
|
||||
- Screen reader support
|
||||
|
||||
## 💰 Monetization - Simple Tiers
|
||||
|
||||
### Free Tier (Launch)
|
||||
- 1-2 children max
|
||||
- All core tracking features
|
||||
- Basic AI assistance (10 questions/day)
|
||||
- 7-day data history
|
||||
- Basic patterns & insights
|
||||
|
||||
### Premium Tier ($9.99/month)
|
||||
- Unlimited children
|
||||
- Unlimited AI assistance
|
||||
- Full data history
|
||||
- Advanced predictions
|
||||
- Priority support
|
||||
- Export features
|
||||
- Advanced insights
|
||||
|
||||
## 🚫 NOT in MVP (Future Releases)
|
||||
|
||||
### Deferred Features
|
||||
- ❌ Meal planning
|
||||
- ❌ Financial tracking
|
||||
- ❌ Community forums
|
||||
- ❌ Photo milestone tracking
|
||||
- ❌ Video consultations
|
||||
- ❌ Smart home integration
|
||||
- ❌ Web version
|
||||
- ❌ Wearable integration
|
||||
- ❌ School platform connections
|
||||
|
||||
## 📈 Success Metrics for MVP
|
||||
|
||||
### Key Performance Indicators
|
||||
- **User Acquisition**
|
||||
- 1,000 downloads in first month
|
||||
- 40% complete onboarding
|
||||
- 25% invite a partner
|
||||
|
||||
- **Engagement Metrics**
|
||||
- 60% daily active users
|
||||
- 5+ logs per day average
|
||||
- 3+ AI interactions weekly
|
||||
- 70% week-1 retention
|
||||
|
||||
- **Technical Metrics**
|
||||
- <2% crash rate
|
||||
- 99.5% uptime
|
||||
- <3 second response time
|
||||
- 4.0+ app store rating
|
||||
|
||||
## 🗓️ 6-Week MVP Timeline
|
||||
|
||||
### Week 1-2: Foundation
|
||||
- User authentication system
|
||||
- Basic child profiles
|
||||
- Core database schema
|
||||
- Initial UI framework
|
||||
- i18n framework setup
|
||||
- String externalization
|
||||
|
||||
### Week 3-4: Core Features
|
||||
- Feeding/sleep/diaper tracking
|
||||
- Voice input integration
|
||||
- Real-time sync
|
||||
- Basic notifications
|
||||
- Multilingual voice recognition
|
||||
|
||||
### Week 5-6: AI Integration
|
||||
- LLM integration (OpenAI/Claude)
|
||||
- Context-aware responses
|
||||
- Pattern recognition
|
||||
- Sleep predictions
|
||||
- Language-specific AI responses
|
||||
|
||||
### Week 7-8: Polish & Launch
|
||||
- Bug fixes & optimization
|
||||
- App store preparation (multiple locales)
|
||||
- Beta testing with 50 families (diverse languages)
|
||||
- Launch marketing preparation
|
||||
- Translation quality review
|
||||
|
||||
## 🎯 MVP Principles
|
||||
|
||||
### Focus Areas
|
||||
1. **Solve One Problem Well**: Reduce mental load through intelligent tracking
|
||||
2. **AI as Differentiator**: Make the assistant genuinely helpful from day 1
|
||||
3. **Trust Through Privacy**: Parents need to feel data is secure
|
||||
4. **Work in Chaos**: One-handed, interruption-resistant design
|
||||
5. **Immediate Value**: User should see benefit within first 24 hours
|
||||
|
||||
### Quality Thresholds
|
||||
- **Stability over features**: Better to have 5 rock-solid features than 10 buggy ones
|
||||
- **Real-time sync must be flawless**: Partners rely on accurate shared data
|
||||
- **AI responses must be helpful**: No generic, unhelpful responses
|
||||
- **Voice input must be accurate**: Critical for hands-occupied situations
|
||||
|
||||
## 🚀 Post-MVP Roadmap Preview
|
||||
|
||||
### Phase 2 (Months 2-3)
|
||||
- Community features with moderation
|
||||
- Photo milestone tracking
|
||||
- Meal planning basics
|
||||
- Calendar integration
|
||||
- Additional languages (German, Italian, Japanese, Korean, Arabic)
|
||||
|
||||
### Phase 3 (Months 4-6)
|
||||
- Financial tracking
|
||||
- Smart home integration
|
||||
- Professional tools
|
||||
- Advanced analytics
|
||||
- Telemedicine integration
|
||||
|
||||
## ✅ MVP Launch Checklist
|
||||
|
||||
### Pre-Launch Requirements
|
||||
- [ ] COPPA/GDPR compliance verified
|
||||
- [ ] Privacy policy & terms of service (all languages)
|
||||
- [ ] App store assets ready (localized)
|
||||
- [ ] Beta testing with 50+ families (diverse languages/cultures)
|
||||
- [ ] Customer support system setup (multilingual)
|
||||
- [ ] Analytics tracking implemented
|
||||
- [ ] Crash reporting active
|
||||
- [ ] Payment processing tested (multi-currency)
|
||||
- [ ] Backup systems verified
|
||||
- [ ] Security audit completed
|
||||
- [ ] Translation quality assurance completed
|
||||
|
||||
### Launch Day Essentials
|
||||
- [ ] App store submission approved (all regions)
|
||||
- [ ] Marketing website live (multilingual)
|
||||
- [ ] Support documentation ready (all languages)
|
||||
- [ ] Social media accounts active
|
||||
- [ ] Press kit available (multilingual)
|
||||
- [ ] Customer feedback system active
|
||||
- [ ] Monitoring dashboards operational
|
||||
- [ ] Support team trained (language coverage)
|
||||
- [ ] Emergency response plan ready
|
||||
- [ ] Celebration planned! 🎉
|
||||
89
docs/maternal-app-name-and-domain-research.md
Normal file
89
docs/maternal-app-name-and-domain-research.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Available Domains for Maternal Parenting App
|
||||
|
||||
**Both .com and .app domains show strong availability** across these 20 carefully researched names that convey support, organization, AI assistance, and reduced mental load for overwhelmed parents. Each name is under 15 characters, easy to spell, memorable, and professionally warm.
|
||||
|
||||
## Research methodology and validation
|
||||
|
||||
I deployed five research teams to explore different thematic categories and verify domain availability across multiple registrars including Namecheap, GoDaddy, Name.com, InstantDomainSearch, and DNSChecker. While registrars require interactive searches for definitive confirmation, extensive web research found **no active websites or businesses** using these names, indicating strong availability likelihood. You should verify final availability within 24-48 hours as domains are registered constantly.
|
||||
|
||||
## Top tier names (strongest recommendations)
|
||||
|
||||
These seven names scored highest across all criteria—memorability, brand strength, thematic fit, and availability confidence:
|
||||
|
||||
**CareAI** (6 characters) combines nurturing care with direct AI positioning. Extremely concise and clear about technology-enabled parenting support. No existing services found across multiple registrars and search engines. Conveys both warmth and intelligence.
|
||||
|
||||
**MomMind** (7 characters) perfectly captures intelligent assistance through the "mind" concept while maintaining warm maternal connection. Short, brandable, and memorable with zero online presence detected. Suggests the app serves as a second mind for busy mothers.
|
||||
|
||||
**FamMind** (7 characters) offers broader family appeal than MomMind while maintaining the intelligent assistant positioning. Modern and tech-forward with no conflicting websites found. Appeals to all parents rather than mothers exclusively.
|
||||
|
||||
**CareGlow** (8 characters) evokes warmth, positivity, and radiant care. The "glow" connects naturally to maternal imagery while "care" remains direct and clear. Highly memorable and brandable with no active businesses using this name.
|
||||
|
||||
**FamNest** (7 characters) combines family focus with nest imagery suggesting safety, home, and warmth. Perfect for family hub concept with strong visual identity potential. No major web presence detected across multiple searches.
|
||||
|
||||
**MomFlow** (7 characters) suggests smooth, effortless family management through productivity flow. Easy to pronounce with strong appeal for reducing mental load. No active website found.
|
||||
|
||||
**NestWise** (8 characters) merges nurturing nest imagery with wisdom and guidance. Professional yet warm, suggesting smart parenting support. Clean search results indicate availability across registrars.
|
||||
|
||||
## AI and technology-focused names
|
||||
|
||||
These options emphasize intelligent assistance and smart parenting technology:
|
||||
|
||||
**NurturAI** (8 characters) beautifully combines nurture with AI through intentional spelling (dropping the 'e' from nurture). Sophisticated yet approachable with no websites found using this spelling variant. The creative spelling makes it more unique and brandable.
|
||||
|
||||
**MomPulse** (8 characters) suggests real-time monitoring and staying connected with needs. "Pulse" conveys being in tune with family rhythms. Modern and dynamic while maintaining warmth. No existing services detected.
|
||||
|
||||
**GuideMom** (8 characters) offers clear value proposition about providing guidance. Direct and memorable with professional tone. Zero online presence found across multiple registrar searches.
|
||||
|
||||
**BabyMind** (8 characters) appeals specifically to new parents and infant care. Suggests intelligent support during the demanding early parenting phase. No conflicting websites identified.
|
||||
|
||||
## Organization and coordination names
|
||||
|
||||
These emphasize family management and reducing mental load:
|
||||
|
||||
**FamFlow** (7 characters) conveys smooth family coordination and workflow optimization. Short, catchy, and professional with strong brandability. No active websites found.
|
||||
|
||||
**CoordKit** (8 characters) directly communicates "coordination toolkit" with professional, functional clarity. Modern tech feel while maintaining warmth. No major online presence detected.
|
||||
|
||||
**OrgaMom** (7 characters) provides direct organization messaging for mothers. Playful yet professional and easy to remember. Clean availability status across searches.
|
||||
|
||||
**MomCoord** (8 characters) straightforward mom coordination concept. Clear purpose with professional appeal. No existing businesses found using this name.
|
||||
|
||||
## Calm and stress relief names
|
||||
|
||||
These focus on easing parental overwhelm and providing peace:
|
||||
|
||||
**CalmPath** (8 characters) suggests a journey toward tranquility and calm parenting. Clear, memorable, and evocative with easy spelling. Professional yet warm tone with no active websites detected.
|
||||
|
||||
**ParentFlow** (10 characters) conveys smooth, effortless parenting where everything flows naturally. Modern professional branding appealing to tech-savvy parents. No conflicting online presence found.
|
||||
|
||||
**CalmLift** (8 characters) suggests lifting burdens and providing relief from stress. Strong emotional connection for overwhelmed parents. Memorable and distinctive with clean availability.
|
||||
|
||||
**MomPeace** (8 characters) directly addresses what stressed parents seek most. Short, memorable, and easy to spell with warm maternal tone remaining professional. No existing services identified.
|
||||
|
||||
## Community and support names
|
||||
|
||||
These emphasize connection, togetherness, and shared experience:
|
||||
|
||||
**MomGather** (9 characters) communicates community and togetherness perfectly. "Gather" feels warm, inviting, and action-oriented while appealing to maternal audience. Modern and professional with no brand conflicts found.
|
||||
|
||||
**ParentCove** (10 characters) uses "cove" to suggest safe harbor, protection, and community. Professional and warm simultaneously with good SEO potential through "parent" keyword. No major online presence detected.
|
||||
|
||||
## Domain verification checklist
|
||||
|
||||
To confirm availability for both .com and .app extensions, check these registrars immediately:
|
||||
|
||||
**Primary verification:** Visit Namecheap.com/domains/domain-name-search and enter each domain name. Check both .com and .app extensions. Namecheap offers competitive pricing ($10-15/year for .com, $15-20/year for .app) plus free WHOIS privacy protection.
|
||||
|
||||
**Secondary verification:** Cross-reference at GoDaddy.com/domains to ensure consistency. GoDaddy is the largest registrar with extensive customer support and reliable infrastructure.
|
||||
|
||||
**Rapid checking:** Use InstantDomainSearch.com for real-time results showing availability across multiple extensions simultaneously. This tool provides results in under 25 milliseconds.
|
||||
|
||||
**Important considerations:** The .app extension requires HTTPS/SSL certificates as it's owned by Google and operates as a secure namespace. Register both .com and .app for your chosen name simultaneously to protect your brand. Budget $50-75 for the domain pair plus SSL certificate for .app.
|
||||
|
||||
## Names confirmed unavailable (avoid these)
|
||||
|
||||
Research identified these names as taken: MomEase, CalmNest, ParentZen, MomHaven, MomCircle (active app), ParentPod, FamSync, ParentHub/parent.app, MomWise, MomAlly, ParentLift, CareBloom, MomGlow, MomThrive, and NurtureNow. These have active websites, businesses, or apps already using them.
|
||||
|
||||
## Registration strategy
|
||||
|
||||
Act quickly on your top 3-5 choices as domain availability changes constantly. The strongest options—CareAI, MomMind, FamMind, CareGlow, and FamNest—showed zero existing web presence across all research, indicating highest availability confidence. Consider registering multiple extensions (.com, .app, .net) for your final choice to protect brand identity. Verify within 24-48 hours and register immediately once confirmed to secure your preferred name.
|
||||
724
docs/maternal-app-state-management.md
Normal file
724
docs/maternal-app-state-management.md
Normal file
@@ -0,0 +1,724 @@
|
||||
# State Management Schema - Maternal Organization App
|
||||
|
||||
## Store Architecture Overview
|
||||
|
||||
### Redux Toolkit Structure
|
||||
```typescript
|
||||
// Core principles:
|
||||
// - Single source of truth
|
||||
// - Normalized state shape
|
||||
// - Offline-first design
|
||||
// - Optimistic updates
|
||||
// - Automatic sync queue
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Root Store Structure
|
||||
|
||||
```typescript
|
||||
interface RootState {
|
||||
auth: AuthState;
|
||||
user: UserState;
|
||||
family: FamilyState;
|
||||
children: ChildrenState;
|
||||
activities: ActivitiesState;
|
||||
ai: AIState;
|
||||
sync: SyncState;
|
||||
offline: OfflineState;
|
||||
ui: UIState;
|
||||
notifications: NotificationState;
|
||||
analytics: AnalyticsState;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Auth Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface AuthState {
|
||||
isAuthenticated: boolean;
|
||||
accessToken: string | null;
|
||||
refreshToken: string | null;
|
||||
tokenExpiry: number | null;
|
||||
deviceFingerprint: string;
|
||||
trustedDevices: string[];
|
||||
authStatus: 'idle' | 'loading' | 'succeeded' | 'failed';
|
||||
error: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### Actions
|
||||
```typescript
|
||||
// authSlice.ts
|
||||
const authSlice = createSlice({
|
||||
name: 'auth',
|
||||
initialState,
|
||||
reducers: {
|
||||
loginStart: (state) => {
|
||||
state.authStatus = 'loading';
|
||||
},
|
||||
loginSuccess: (state, action) => {
|
||||
state.isAuthenticated = true;
|
||||
state.accessToken = action.payload.accessToken;
|
||||
state.refreshToken = action.payload.refreshToken;
|
||||
state.tokenExpiry = action.payload.expiresAt;
|
||||
state.authStatus = 'succeeded';
|
||||
},
|
||||
loginFailure: (state, action) => {
|
||||
state.authStatus = 'failed';
|
||||
state.error = action.payload;
|
||||
},
|
||||
tokenRefreshed: (state, action) => {
|
||||
state.accessToken = action.payload.accessToken;
|
||||
state.tokenExpiry = action.payload.expiresAt;
|
||||
},
|
||||
logout: (state) => {
|
||||
return initialState;
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface UserState {
|
||||
currentUser: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
locale: string;
|
||||
timezone: string;
|
||||
photoUrl?: string;
|
||||
preferences: UserPreferences;
|
||||
} | null;
|
||||
subscription: {
|
||||
tier: 'free' | 'premium' | 'plus';
|
||||
expiresAt?: string;
|
||||
aiQueriesUsed: number;
|
||||
aiQueriesLimit: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface UserPreferences {
|
||||
darkMode: 'auto' | 'light' | 'dark';
|
||||
notifications: {
|
||||
push: boolean;
|
||||
email: boolean;
|
||||
quietHoursStart?: string;
|
||||
quietHoursEnd?: string;
|
||||
};
|
||||
measurementUnit: 'metric' | 'imperial';
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Family Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface FamilyState {
|
||||
currentFamily: {
|
||||
id: string;
|
||||
name: string;
|
||||
shareCode: string;
|
||||
createdBy: string;
|
||||
} | null;
|
||||
members: {
|
||||
byId: Record<string, FamilyMember>;
|
||||
allIds: string[];
|
||||
};
|
||||
invitations: Invitation[];
|
||||
loadingStatus: LoadingStatus;
|
||||
}
|
||||
|
||||
interface FamilyMember {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role: 'parent' | 'caregiver' | 'viewer';
|
||||
permissions: Permissions;
|
||||
lastActive: string;
|
||||
isOnline: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Normalized Actions
|
||||
```typescript
|
||||
const familySlice = createSlice({
|
||||
name: 'family',
|
||||
initialState,
|
||||
reducers: {
|
||||
memberAdded: (state, action) => {
|
||||
const member = action.payload;
|
||||
state.members.byId[member.id] = member;
|
||||
state.members.allIds.push(member.id);
|
||||
},
|
||||
memberUpdated: (state, action) => {
|
||||
const { id, changes } = action.payload;
|
||||
state.members.byId[id] = {
|
||||
...state.members.byId[id],
|
||||
...changes,
|
||||
};
|
||||
},
|
||||
memberRemoved: (state, action) => {
|
||||
const id = action.payload;
|
||||
delete state.members.byId[id];
|
||||
state.members.allIds = state.members.allIds.filter(mid => mid !== id);
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Children Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface ChildrenState {
|
||||
children: {
|
||||
byId: Record<string, Child>;
|
||||
allIds: string[];
|
||||
};
|
||||
activeChildId: string | null;
|
||||
milestones: {
|
||||
byChildId: Record<string, Milestone[]>;
|
||||
};
|
||||
}
|
||||
|
||||
interface Child {
|
||||
id: string;
|
||||
name: string;
|
||||
birthDate: string;
|
||||
gender?: string;
|
||||
photoUrl?: string;
|
||||
medical: {
|
||||
bloodType?: string;
|
||||
allergies: string[];
|
||||
conditions: string[];
|
||||
medications: Medication[];
|
||||
};
|
||||
metrics: {
|
||||
currentWeight?: Measurement;
|
||||
currentHeight?: Measurement;
|
||||
headCircumference?: Measurement;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Activities Slice (Normalized)
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface ActivitiesState {
|
||||
activities: {
|
||||
byId: Record<string, Activity>;
|
||||
allIds: string[];
|
||||
byChild: Record<string, string[]>; // childId -> activityIds
|
||||
byDate: Record<string, string[]>; // date -> activityIds
|
||||
};
|
||||
activeTimers: {
|
||||
[childId: string]: ActiveTimer;
|
||||
};
|
||||
filters: {
|
||||
childId?: string;
|
||||
dateRange?: { start: string; end: string };
|
||||
types?: ActivityType[];
|
||||
};
|
||||
pagination: {
|
||||
cursor: string | null;
|
||||
hasMore: boolean;
|
||||
isLoading: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface Activity {
|
||||
id: string;
|
||||
childId: string;
|
||||
type: ActivityType;
|
||||
timestamp: string;
|
||||
duration?: number;
|
||||
details: ActivityDetails;
|
||||
loggedBy: string;
|
||||
syncStatus: 'synced' | 'pending' | 'error';
|
||||
version: number; // For conflict resolution
|
||||
}
|
||||
|
||||
interface ActiveTimer {
|
||||
activityType: ActivityType;
|
||||
startTime: number;
|
||||
pausedDuration: number;
|
||||
isPaused: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Activity Actions
|
||||
```typescript
|
||||
const activitiesSlice = createSlice({
|
||||
name: 'activities',
|
||||
initialState,
|
||||
reducers: {
|
||||
// Optimistic update
|
||||
activityLogged: (state, action) => {
|
||||
const activity = {
|
||||
...action.payload,
|
||||
syncStatus: 'pending',
|
||||
};
|
||||
state.activities.byId[activity.id] = activity;
|
||||
state.activities.allIds.unshift(activity.id);
|
||||
|
||||
// Update indexes
|
||||
if (!state.activities.byChild[activity.childId]) {
|
||||
state.activities.byChild[activity.childId] = [];
|
||||
}
|
||||
state.activities.byChild[activity.childId].unshift(activity.id);
|
||||
},
|
||||
|
||||
// Sync confirmed
|
||||
activitySynced: (state, action) => {
|
||||
const { localId, serverId } = action.payload;
|
||||
state.activities.byId[localId].id = serverId;
|
||||
state.activities.byId[localId].syncStatus = 'synced';
|
||||
},
|
||||
|
||||
// Timer management
|
||||
timerStarted: (state, action) => {
|
||||
const { childId, activityType } = action.payload;
|
||||
state.activeTimers[childId] = {
|
||||
activityType,
|
||||
startTime: Date.now(),
|
||||
pausedDuration: 0,
|
||||
isPaused: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface AIState {
|
||||
conversations: {
|
||||
byId: Record<string, Conversation>;
|
||||
activeId: string | null;
|
||||
};
|
||||
insights: {
|
||||
byChildId: Record<string, Insight[]>;
|
||||
pending: Insight[];
|
||||
};
|
||||
predictions: {
|
||||
byChildId: Record<string, Predictions>;
|
||||
};
|
||||
quotas: {
|
||||
dailyQueries: number;
|
||||
dailyLimit: number;
|
||||
resetAt: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Conversation {
|
||||
id: string;
|
||||
childId?: string;
|
||||
messages: Message[];
|
||||
context: ConversationContext;
|
||||
lastMessageAt: string;
|
||||
}
|
||||
|
||||
interface Predictions {
|
||||
nextNapTime?: { time: string; confidence: number };
|
||||
nextFeedingTime?: { time: string; confidence: number };
|
||||
growthSpurt?: { likelihood: number; expectedIn: string };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sync Slice (Critical for Offline)
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface SyncState {
|
||||
queue: SyncQueueItem[];
|
||||
conflicts: ConflictItem[];
|
||||
lastSync: {
|
||||
[entityType: string]: string; // ISO timestamp
|
||||
};
|
||||
syncStatus: 'idle' | 'syncing' | 'error' | 'offline';
|
||||
retryCount: number;
|
||||
webSocket: {
|
||||
connected: boolean;
|
||||
reconnectAttempts: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface SyncQueueItem {
|
||||
id: string;
|
||||
type: 'CREATE' | 'UPDATE' | 'DELETE';
|
||||
entity: 'activity' | 'child' | 'family';
|
||||
payload: any;
|
||||
timestamp: string;
|
||||
retries: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface ConflictItem {
|
||||
id: string;
|
||||
localVersion: any;
|
||||
serverVersion: any;
|
||||
strategy: 'manual' | 'local' | 'server' | 'merge';
|
||||
}
|
||||
```
|
||||
|
||||
### Sync Actions
|
||||
```typescript
|
||||
const syncSlice = createSlice({
|
||||
name: 'sync',
|
||||
initialState,
|
||||
reducers: {
|
||||
addToQueue: (state, action) => {
|
||||
state.queue.push({
|
||||
id: nanoid(),
|
||||
...action.payload,
|
||||
timestamp: new Date().toISOString(),
|
||||
retries: 0,
|
||||
});
|
||||
},
|
||||
|
||||
removeFromQueue: (state, action) => {
|
||||
state.queue = state.queue.filter(item => item.id !== action.payload);
|
||||
},
|
||||
|
||||
conflictDetected: (state, action) => {
|
||||
state.conflicts.push(action.payload);
|
||||
},
|
||||
|
||||
conflictResolved: (state, action) => {
|
||||
const { id, resolution } = action.payload;
|
||||
state.conflicts = state.conflicts.filter(c => c.id !== id);
|
||||
// Apply resolution...
|
||||
},
|
||||
|
||||
syncCompleted: (state, action) => {
|
||||
state.lastSync[action.payload.entity] = new Date().toISOString();
|
||||
state.syncStatus = 'idle';
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Offline Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface OfflineState {
|
||||
isOnline: boolean;
|
||||
queuedActions: OfflineAction[];
|
||||
cachedData: {
|
||||
[key: string]: {
|
||||
data: any;
|
||||
timestamp: string;
|
||||
ttl: number;
|
||||
};
|
||||
};
|
||||
retryPolicy: {
|
||||
maxRetries: number;
|
||||
retryDelay: number;
|
||||
backoffMultiplier: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface OfflineAction {
|
||||
id: string;
|
||||
action: AnyAction;
|
||||
meta: {
|
||||
offline: {
|
||||
effect: any;
|
||||
commit: AnyAction;
|
||||
rollback: AnyAction;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI Slice
|
||||
|
||||
### State Shape
|
||||
```typescript
|
||||
interface UIState {
|
||||
theme: 'light' | 'dark' | 'auto';
|
||||
activeScreen: string;
|
||||
modals: {
|
||||
[modalId: string]: {
|
||||
isOpen: boolean;
|
||||
data?: any;
|
||||
};
|
||||
};
|
||||
loading: {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
errors: {
|
||||
[key: string]: ErrorInfo;
|
||||
};
|
||||
toasts: Toast[];
|
||||
bottomSheet: {
|
||||
isOpen: boolean;
|
||||
content: 'quickActions' | 'activityDetails' | null;
|
||||
};
|
||||
}
|
||||
|
||||
interface Toast {
|
||||
id: string;
|
||||
type: 'success' | 'error' | 'info';
|
||||
message: string;
|
||||
duration: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Middleware Configuration
|
||||
|
||||
### Store Setup
|
||||
```typescript
|
||||
// store/index.ts
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import {
|
||||
persistStore,
|
||||
persistReducer,
|
||||
FLUSH,
|
||||
REHYDRATE,
|
||||
PAUSE,
|
||||
PERSIST,
|
||||
PURGE,
|
||||
REGISTER,
|
||||
} from 'redux-persist';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
const persistConfig = {
|
||||
key: 'root',
|
||||
storage: AsyncStorage,
|
||||
whitelist: ['auth', 'user', 'children', 'activities'],
|
||||
blacklist: ['ui', 'sync'], // Don't persist UI state
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
user: userReducer,
|
||||
family: familyReducer,
|
||||
children: childrenReducer,
|
||||
activities: activitiesReducer,
|
||||
ai: aiReducer,
|
||||
sync: syncReducer,
|
||||
offline: offlineReducer,
|
||||
ui: uiReducer,
|
||||
notifications: notificationsReducer,
|
||||
analytics: analyticsReducer,
|
||||
});
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: persistedReducer,
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: {
|
||||
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
|
||||
},
|
||||
}).concat([
|
||||
syncMiddleware,
|
||||
offlineMiddleware,
|
||||
analyticsMiddleware,
|
||||
conflictResolutionMiddleware,
|
||||
]),
|
||||
});
|
||||
|
||||
export const persistor = persistStore(store);
|
||||
```
|
||||
|
||||
### Sync Middleware
|
||||
```typescript
|
||||
// middleware/syncMiddleware.ts
|
||||
export const syncMiddleware: Middleware = (store) => (next) => (action) => {
|
||||
const result = next(action);
|
||||
|
||||
// Queue actions for sync
|
||||
if (action.type.includes('activities/') && !action.meta?.skipSync) {
|
||||
const state = store.getState();
|
||||
|
||||
if (!state.offline.isOnline) {
|
||||
store.dispatch(addToQueue({
|
||||
type: 'UPDATE',
|
||||
entity: 'activity',
|
||||
payload: action.payload,
|
||||
}));
|
||||
} else {
|
||||
// Sync immediately
|
||||
syncActivity(action.payload);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
```
|
||||
|
||||
### Offline Middleware
|
||||
```typescript
|
||||
// middleware/offlineMiddleware.ts
|
||||
export const offlineMiddleware: Middleware = (store) => (next) => (action) => {
|
||||
// Check network status
|
||||
if (action.type === 'network/statusChanged') {
|
||||
const isOnline = action.payload;
|
||||
|
||||
if (isOnline && store.getState().sync.queue.length > 0) {
|
||||
// Process offline queue
|
||||
store.dispatch(processOfflineQueue());
|
||||
}
|
||||
}
|
||||
|
||||
// Handle optimistic updates
|
||||
if (action.meta?.offline) {
|
||||
const { effect, commit, rollback } = action.meta.offline;
|
||||
|
||||
// Apply optimistic update
|
||||
next(action);
|
||||
|
||||
// Attempt sync
|
||||
effect()
|
||||
.then(() => next(commit))
|
||||
.catch(() => next(rollback));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return next(action);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Selectors
|
||||
|
||||
### Memoized Selectors
|
||||
```typescript
|
||||
// selectors/activities.ts
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
export const selectActivitiesByChild = createSelector(
|
||||
[(state: RootState) => state.activities.activities.byId,
|
||||
(state: RootState, childId: string) => state.activities.activities.byChild[childId]],
|
||||
(byId, activityIds = []) =>
|
||||
activityIds.map(id => byId[id]).filter(Boolean)
|
||||
);
|
||||
|
||||
export const selectTodaysSummary = createSelector(
|
||||
[(state: RootState, childId: string) => selectActivitiesByChild(state, childId)],
|
||||
(activities) => {
|
||||
const today = new Date().toDateString();
|
||||
const todaysActivities = activities.filter(
|
||||
a => new Date(a.timestamp).toDateString() === today
|
||||
);
|
||||
|
||||
return {
|
||||
feedings: todaysActivities.filter(a => a.type === 'feeding').length,
|
||||
sleepHours: calculateSleepHours(todaysActivities),
|
||||
diapers: todaysActivities.filter(a => a.type === 'diaper').length,
|
||||
};
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
### Conflict Resolution Strategy
|
||||
```typescript
|
||||
// utils/conflictResolution.ts
|
||||
export const resolveConflict = (
|
||||
local: Activity,
|
||||
remote: Activity
|
||||
): Activity => {
|
||||
// Last write wins for simple conflicts
|
||||
if (local.version === remote.version) {
|
||||
return local.timestamp > remote.timestamp ? local : remote;
|
||||
}
|
||||
|
||||
// Server version is higher - merge changes
|
||||
if (remote.version > local.version) {
|
||||
return {
|
||||
...remote,
|
||||
// Preserve local notes if different
|
||||
details: {
|
||||
...remote.details,
|
||||
notes: local.details.notes !== remote.details.notes
|
||||
? `${remote.details.notes}\n---\n${local.details.notes}`
|
||||
: remote.details.notes,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Local version is higher
|
||||
return local;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Normalized State Updates
|
||||
```typescript
|
||||
// Batch updates for performance
|
||||
const activitiesSlice = createSlice({
|
||||
name: 'activities',
|
||||
reducers: {
|
||||
activitiesBatchUpdated: (state, action) => {
|
||||
const activities = action.payload;
|
||||
|
||||
// Use immer's batching
|
||||
activities.forEach(activity => {
|
||||
state.activities.byId[activity.id] = activity;
|
||||
if (!state.activities.allIds.includes(activity.id)) {
|
||||
state.activities.allIds.push(activity.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
```typescript
|
||||
// Lazy load historical data
|
||||
export const loadMoreActivities = createAsyncThunk(
|
||||
'activities/loadMore',
|
||||
async ({ cursor, limit = 20 }, { getState }) => {
|
||||
const response = await api.getActivities({ cursor, limit });
|
||||
return response.data;
|
||||
},
|
||||
{
|
||||
condition: (_, { getState }) => {
|
||||
const state = getState() as RootState;
|
||||
return !state.activities.pagination.isLoading;
|
||||
},
|
||||
}
|
||||
);
|
||||
```
|
||||
420
docs/maternal-app-tech-stack.md
Normal file
420
docs/maternal-app-tech-stack.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# Technical Stack - Open Source Technologies for Maternal Organization App
|
||||
|
||||
## Mobile Application Development
|
||||
|
||||
### Cross-Platform Framework
|
||||
- **React Native** (Primary Choice)
|
||||
- `react-native`: Core framework
|
||||
- `react-native-cli`: Command line interface
|
||||
- `expo`: Development toolchain and libraries
|
||||
- `react-navigation`: Navigation library
|
||||
- `react-native-paper`: Material Design components
|
||||
- `react-native-elements`: UI toolkit
|
||||
|
||||
### Alternative Native Development
|
||||
- **Flutter** (Alternative Option)
|
||||
- `flutter`: Core SDK
|
||||
- `flutter_bloc`: State management
|
||||
- `provider`: Dependency injection
|
||||
- `get_it`: Service locator
|
||||
- `dio`: HTTP client
|
||||
|
||||
### State Management
|
||||
- **Redux Toolkit**
|
||||
- `@reduxjs/toolkit`: Modern Redux with less boilerplate
|
||||
- `react-redux`: React bindings
|
||||
- `redux-persist`: Offline data persistence
|
||||
- `redux-offline`: Offline-first functionality
|
||||
- `redux-saga`: Side effects management
|
||||
|
||||
### Local Database & Storage
|
||||
- **SQLite** (Primary local database)
|
||||
- `react-native-sqlite-storage`: SQLite for React Native
|
||||
- `typeorm`: Object-relational mapping
|
||||
- `realm`: Alternative mobile database
|
||||
|
||||
- **Async Storage**
|
||||
- `@react-native-async-storage/async-storage`: Key-value storage
|
||||
- `react-native-mmkv`: Fast key-value storage alternative
|
||||
|
||||
## Backend Infrastructure
|
||||
|
||||
### Core Backend Framework
|
||||
- **Node.js** with **NestJS**
|
||||
- `@nestjs/core`: Enterprise-grade Node.js framework
|
||||
- `@nestjs/common`: Common utilities
|
||||
- `@nestjs/platform-express`: Express adapter
|
||||
- `@nestjs/microservices`: Microservices support
|
||||
- `@nestjs/websockets`: WebSocket support
|
||||
- `@nestjs/graphql`: GraphQL integration
|
||||
|
||||
### API Development
|
||||
- **GraphQL**
|
||||
- `apollo-server-express`: GraphQL server
|
||||
- `type-graphql`: TypeScript GraphQL framework
|
||||
- `graphql-subscriptions`: Real-time subscriptions
|
||||
- `graphql-upload`: File upload handling
|
||||
|
||||
- **REST API**
|
||||
- `express`: Web framework
|
||||
- `fastify`: Alternative high-performance framework
|
||||
- `cors`: Cross-origin resource sharing
|
||||
- `helmet`: Security headers
|
||||
- `compression`: Response compression
|
||||
|
||||
### Database Systems
|
||||
- **PostgreSQL** (Primary database)
|
||||
- `pg`: PostgreSQL client
|
||||
- `knex`: SQL query builder
|
||||
- `prisma`: Modern ORM
|
||||
- `typeorm`: Alternative ORM
|
||||
|
||||
- **MongoDB** (Document storage)
|
||||
- `mongoose`: MongoDB object modeling
|
||||
- `mongodb`: Native driver
|
||||
|
||||
### Caching & Performance
|
||||
- **Redis**
|
||||
- `redis`: Redis client
|
||||
- `ioredis`: Advanced Redis client
|
||||
- `bull`: Queue management
|
||||
- `node-cache`: In-memory caching
|
||||
|
||||
- **Elasticsearch** (Search & analytics)
|
||||
- `@elastic/elasticsearch`: Official client
|
||||
- `searchkit`: Search UI components
|
||||
|
||||
## AI & Machine Learning
|
||||
|
||||
### LLM Integration (Proprietary APIs)
|
||||
- **OpenAI API** / **Anthropic Claude API** / **Google Gemini API**
|
||||
- **LangChain** (Framework)
|
||||
- `langchain`: Core library
|
||||
- `@langchain/community`: Community integrations
|
||||
- `@langchain/openai`: OpenAI integration
|
||||
|
||||
### Open Source ML/AI
|
||||
- **TensorFlow.js**
|
||||
- `@tensorflow/tfjs`: Core library
|
||||
- `@tensorflow/tfjs-node`: Node.js bindings
|
||||
- `@tensorflow/tfjs-react-native`: React Native support
|
||||
|
||||
- **ONNX Runtime**
|
||||
- `onnxruntime-node`: Node.js inference
|
||||
- `onnxruntime-react-native`: Mobile inference
|
||||
|
||||
### Natural Language Processing
|
||||
- **Natural**
|
||||
- `natural`: General NLP tasks
|
||||
- `compromise`: Natural language understanding
|
||||
- `sentiment`: Sentiment analysis
|
||||
- `franc`: Language detection
|
||||
|
||||
### Pattern Recognition & Analytics
|
||||
- **Time Series Analysis**
|
||||
- `timeseries-analysis`: Time series forecasting
|
||||
- `simple-statistics`: Statistical functions
|
||||
- `regression`: Regression analysis
|
||||
|
||||
- **Data Processing**
|
||||
- `pandas-js`: Data manipulation
|
||||
- `dataframe-js`: DataFrame operations
|
||||
- `ml-js`: Machine learning algorithms
|
||||
|
||||
## Real-Time Communication
|
||||
|
||||
### WebSocket & Real-Time Sync
|
||||
- **Socket.io**
|
||||
- `socket.io`: Server implementation
|
||||
- `socket.io-client`: Client library
|
||||
- `socket.io-redis`: Redis adapter for scaling
|
||||
|
||||
### Push Notifications
|
||||
- **Firebase Cloud Messaging** (Free tier available)
|
||||
- `firebase-admin`: Server SDK
|
||||
- `react-native-firebase`: React Native integration
|
||||
|
||||
- **Alternative: Expo Push Notifications**
|
||||
- `expo-notifications`: Notification handling
|
||||
- `expo-server-sdk`: Server implementation
|
||||
|
||||
## Voice & Audio Processing
|
||||
|
||||
### Voice Input & Recognition
|
||||
- **Whisper** (OpenAI's open source)
|
||||
- `whisper`: Speech recognition
|
||||
- `react-native-voice`: Voice recognition wrapper
|
||||
|
||||
- **Web Speech API**
|
||||
- `react-speech-kit`: React speech components
|
||||
- `speech-to-text`: Browser-based recognition
|
||||
|
||||
### Audio Processing
|
||||
- **FFmpeg**
|
||||
- `fluent-ffmpeg`: Node.js wrapper
|
||||
- `react-native-ffmpeg`: Mobile integration
|
||||
|
||||
- **Web Audio API**
|
||||
- `tone.js`: Audio synthesis and effects
|
||||
- `wavesurfer.js`: Audio visualization
|
||||
|
||||
## Security & Privacy
|
||||
|
||||
### Authentication & Authorization
|
||||
- **Supabase** (Open source Firebase alternative)
|
||||
- `@supabase/supabase-js`: Client library
|
||||
- `@supabase/auth-helpers`: Authentication utilities
|
||||
|
||||
- **Passport.js**
|
||||
- `passport`: Authentication middleware
|
||||
- `passport-jwt`: JWT strategy
|
||||
- `passport-local`: Local strategy
|
||||
|
||||
### Encryption & Security
|
||||
- **Cryptography**
|
||||
- `bcrypt`: Password hashing
|
||||
- `jsonwebtoken`: JWT tokens
|
||||
- `crypto-js`: Encryption utilities
|
||||
- `node-forge`: Cryptography toolkit
|
||||
|
||||
- **Security Middleware**
|
||||
- `helmet`: Security headers
|
||||
- `express-rate-limit`: Rate limiting
|
||||
- `express-validator`: Input validation
|
||||
- `hpp`: HTTP parameter pollution prevention
|
||||
|
||||
### COPPA/GDPR Compliance
|
||||
- **Age Verification**
|
||||
- `age-calculator`: Age calculation utilities
|
||||
- Custom implementation required
|
||||
|
||||
- **Data Privacy**
|
||||
- `anonymize`: Data anonymization
|
||||
- `gdpr-guard`: GDPR compliance helpers
|
||||
|
||||
## File & Media Management
|
||||
|
||||
### Image Processing
|
||||
- **Sharp**
|
||||
- `sharp`: High-performance image processing
|
||||
- `react-native-image-resizer`: Mobile image resizing
|
||||
- `react-native-image-picker`: Image selection
|
||||
|
||||
### File Storage
|
||||
- **MinIO** (Self-hosted S3-compatible)
|
||||
- `minio`: Object storage server
|
||||
- `multer`: File upload middleware
|
||||
- `multer-s3`: S3 storage engine
|
||||
|
||||
### Document Processing
|
||||
- **PDF Generation**
|
||||
- `pdfkit`: PDF generation
|
||||
- `puppeteer`: HTML to PDF conversion
|
||||
- `react-native-pdf`: PDF viewing
|
||||
|
||||
## Calendar & Scheduling
|
||||
|
||||
### Calendar Integration
|
||||
- **Calendar Libraries**
|
||||
- `node-ical`: iCal parsing
|
||||
- `ical-generator`: iCal generation
|
||||
- `react-native-calendars`: Calendar components
|
||||
- `react-big-calendar`: Web calendar component
|
||||
|
||||
### Scheduling
|
||||
- **Cron Jobs**
|
||||
- `node-cron`: Task scheduling
|
||||
- `agenda`: Job scheduling
|
||||
- `bull`: Queue-based job processing
|
||||
|
||||
## Integration Libraries
|
||||
|
||||
### External Service Integrations
|
||||
- **Google APIs**
|
||||
- `googleapis`: Google services client
|
||||
- `@react-native-google-signin/google-signin`: Google sign-in
|
||||
|
||||
- **Microsoft Graph**
|
||||
- `@microsoft/microsoft-graph-client`: Graph API client
|
||||
|
||||
- **School Platforms**
|
||||
- Custom API integrations required
|
||||
- `axios`: HTTP client for API calls
|
||||
|
||||
### Smart Home Integration
|
||||
- **Home Assistant**
|
||||
- `home-assistant-js-websocket`: WebSocket client
|
||||
|
||||
- **Voice Assistants**
|
||||
- `ask-sdk`: Alexa Skills Kit
|
||||
- `actions-on-google`: Google Assistant
|
||||
|
||||
## Data Visualization & Analytics
|
||||
|
||||
### Charting Libraries
|
||||
- **D3.js Ecosystem**
|
||||
- `d3`: Core visualization library
|
||||
- `react-native-svg`: SVG support for React Native
|
||||
- `victory-native`: React Native charts
|
||||
|
||||
- **Chart.js**
|
||||
- `chart.js`: Charting library
|
||||
- `react-chartjs-2`: React wrapper
|
||||
- `react-native-chart-kit`: React Native charts
|
||||
|
||||
### Analytics
|
||||
- **Matomo** (Open source analytics)
|
||||
- `matomo-tracker`: Analytics tracking
|
||||
|
||||
- **PostHog** (Open source product analytics)
|
||||
- `posthog-js`: JavaScript client
|
||||
- `posthog-react-native`: React Native client
|
||||
|
||||
## Development Tools
|
||||
|
||||
### Testing Frameworks
|
||||
- **Unit Testing**
|
||||
- `jest`: Testing framework
|
||||
- `@testing-library/react-native`: React Native testing
|
||||
- `enzyme`: Component testing
|
||||
|
||||
- **E2E Testing**
|
||||
- `detox`: React Native E2E testing
|
||||
- `appium`: Cross-platform mobile testing
|
||||
- `cypress`: Web testing
|
||||
|
||||
### Code Quality
|
||||
- **Linting & Formatting**
|
||||
- `eslint`: JavaScript linter
|
||||
- `prettier`: Code formatter
|
||||
- `husky`: Git hooks
|
||||
- `lint-staged`: Pre-commit linting
|
||||
|
||||
### Development Environment
|
||||
- **Build Tools**
|
||||
- `webpack`: Module bundler
|
||||
- `babel`: JavaScript compiler
|
||||
- `metro`: React Native bundler
|
||||
|
||||
- **Development Servers**
|
||||
- `nodemon`: Node.js auto-restart
|
||||
- `concurrently`: Run multiple commands
|
||||
- `dotenv`: Environment variables
|
||||
|
||||
## DevOps & Infrastructure
|
||||
|
||||
### Container Orchestration
|
||||
- **Docker**
|
||||
- `docker`: Containerization
|
||||
- `docker-compose`: Multi-container apps
|
||||
|
||||
- **Kubernetes** (for scaling)
|
||||
- `kubernetes`: Container orchestration
|
||||
- `helm`: Kubernetes package manager
|
||||
|
||||
### CI/CD
|
||||
- **GitHub Actions** / **GitLab CI** / **Jenkins**
|
||||
- `semantic-release`: Automated versioning
|
||||
- `standard-version`: Changelog generation
|
||||
|
||||
### Monitoring & Logging
|
||||
- **Sentry** (Open source error tracking)
|
||||
- `@sentry/node`: Node.js SDK
|
||||
- `@sentry/react-native`: React Native SDK
|
||||
|
||||
- **Winston** (Logging)
|
||||
- `winston`: Logging library
|
||||
- `morgan`: HTTP request logger
|
||||
|
||||
### Message Queue
|
||||
- **RabbitMQ**
|
||||
- `amqplib`: RabbitMQ client
|
||||
|
||||
- **Apache Kafka** (for high scale)
|
||||
- `kafkajs`: Kafka client
|
||||
|
||||
## Additional Utilities
|
||||
|
||||
### Date & Time
|
||||
- `dayjs`: Lightweight date library
|
||||
- `date-fns`: Date utility library
|
||||
- `moment-timezone`: Timezone handling
|
||||
- `react-native-date-picker`: Date picker component
|
||||
|
||||
### Forms & Validation
|
||||
- `react-hook-form`: Form management
|
||||
- `yup`: Schema validation
|
||||
- `joi`: Object schema validation
|
||||
- `react-native-masked-text`: Input masking
|
||||
|
||||
### Localization
|
||||
- `i18next`: Internationalization framework
|
||||
- `react-i18next`: React integration
|
||||
- `react-native-localize`: Device locale detection
|
||||
|
||||
### Utilities
|
||||
- `lodash`: Utility functions
|
||||
- `uuid`: UUID generation
|
||||
- `validator`: String validators
|
||||
- `numeral`: Number formatting
|
||||
|
||||
## Infrastructure Services (Self-Hosted Options)
|
||||
|
||||
### Backend as a Service
|
||||
- **Supabase** (Complete backend solution)
|
||||
- **Appwrite** (Alternative BaaS)
|
||||
- **Parse Server** (Mobile backend)
|
||||
|
||||
### Search Infrastructure
|
||||
- **Meilisearch** (Fast search engine)
|
||||
- **Typesense** (Typo-tolerant search)
|
||||
|
||||
### Email Service
|
||||
- **Nodemailer** with SMTP
|
||||
- **SendGrid** (Free tier available)
|
||||
- **Postal** (Self-hosted)
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Mobile Performance
|
||||
- `react-native-fast-image`: Optimized image loading
|
||||
- `react-native-super-grid`: Efficient grid rendering
|
||||
- `recyclerlistview`: High-performance lists
|
||||
- `react-native-reanimated`: Smooth animations
|
||||
|
||||
### Backend Performance
|
||||
- `cluster`: Node.js clustering
|
||||
- `pm2`: Process management
|
||||
- `compression`: Response compression
|
||||
- `memory-cache`: In-memory caching
|
||||
|
||||
## Accessibility Tools
|
||||
- `react-native-accessibility`: Accessibility utilities
|
||||
- `react-native-tts`: Text-to-speech
|
||||
- `react-native-screen-reader`: Screen reader detection
|
||||
|
||||
## Development Recommendations
|
||||
|
||||
### Minimum Viable Stack
|
||||
1. **Frontend**: React Native + Expo
|
||||
2. **Backend**: NestJS + PostgreSQL
|
||||
3. **Real-time**: Socket.io
|
||||
4. **AI**: OpenAI/Claude API + LangChain
|
||||
5. **Auth**: Supabase Auth
|
||||
6. **Storage**: MinIO/Supabase Storage
|
||||
7. **Cache**: Redis
|
||||
8. **Search**: Meilisearch
|
||||
|
||||
### Scalability Considerations
|
||||
- Start with monolithic backend, prepare for microservices
|
||||
- Use message queues early for async operations
|
||||
- Implement caching strategy from day one
|
||||
- Design for offline-first mobile experience
|
||||
- Plan for horizontal scaling with Kubernetes
|
||||
|
||||
### Security Priorities
|
||||
- Implement end-to-end encryption for sensitive data
|
||||
- Use JWT with refresh tokens
|
||||
- Apply rate limiting on all endpoints
|
||||
- Regular security audits with OWASP tools
|
||||
- COPPA/GDPR compliance from the start
|
||||
575
docs/maternal-app-testing-strategy.md
Normal file
575
docs/maternal-app-testing-strategy.md
Normal file
@@ -0,0 +1,575 @@
|
||||
# Testing Strategy Document - Maternal Organization App
|
||||
|
||||
## Testing Philosophy
|
||||
|
||||
### Core Principles
|
||||
- **User-Centric Testing**: Focus on real parent workflows
|
||||
- **Offline-First Validation**: Test sync and conflict resolution
|
||||
- **AI Response Quality**: Verify helpful, safe responses
|
||||
- **Accessibility Testing**: Ensure one-handed operation works
|
||||
- **Performance Under Stress**: Test with interrupted network, low battery
|
||||
|
||||
### Coverage Goals
|
||||
- **Unit Tests**: 80% code coverage
|
||||
- **Integration Tests**: All API endpoints
|
||||
- **E2E Tests**: Critical user journeys
|
||||
- **Performance**: Sub-3 second response times
|
||||
- **Accessibility**: WCAG AA compliance
|
||||
|
||||
---
|
||||
|
||||
## Unit Testing
|
||||
|
||||
### Test Structure
|
||||
```javascript
|
||||
// Standard test file naming
|
||||
ComponentName.test.tsx
|
||||
ServiceName.test.ts
|
||||
utils.test.ts
|
||||
```
|
||||
|
||||
### Component Testing Example
|
||||
```typescript
|
||||
// FeedingTracker.test.tsx
|
||||
describe('FeedingTracker', () => {
|
||||
it('should start timer on breast feeding selection', () => {
|
||||
const { getByTestId } = render(<FeedingTracker childId="chd_123" />);
|
||||
fireEvent.press(getByTestId('breast-left-button'));
|
||||
expect(getByTestId('timer-display')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should validate minimum feeding duration', () => {
|
||||
const onSave = jest.fn();
|
||||
const { getByTestId } = render(<FeedingTracker onSave={onSave} />);
|
||||
fireEvent.press(getByTestId('save-button'));
|
||||
expect(getByTestId('error-message')).toHaveTextContent('Feeding too short');
|
||||
expect(onSave).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Service Testing Example
|
||||
```typescript
|
||||
// SleepPredictionService.test.ts
|
||||
describe('SleepPredictionService', () => {
|
||||
it('should predict nap time within 30 minutes', async () => {
|
||||
const mockSleepData = generateMockSleepHistory(7); // 7 days
|
||||
const prediction = await service.predictNextNap('chd_123', mockSleepData);
|
||||
|
||||
expect(prediction.confidence).toBeGreaterThan(0.7);
|
||||
expect(prediction.predictedTime).toBeInstanceOf(Date);
|
||||
expect(prediction.wakeWindow).toBeBetween(90, 180); // minutes
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Redux Testing
|
||||
```typescript
|
||||
// trackingSlice.test.ts
|
||||
describe('tracking reducer', () => {
|
||||
it('should handle activity logged', () => {
|
||||
const action = activityLogged({
|
||||
id: 'act_123',
|
||||
type: 'feeding',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const newState = trackingReducer(initialState, action);
|
||||
expect(newState.activities).toHaveLength(1);
|
||||
expect(newState.lastSync).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Testing
|
||||
|
||||
### API Endpoint Testing
|
||||
```typescript
|
||||
// auth.integration.test.ts
|
||||
describe('POST /api/v1/auth/register', () => {
|
||||
it('should create user with family', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/v1/auth/register')
|
||||
.send({
|
||||
email: 'test@example.com',
|
||||
password: 'SecurePass123!',
|
||||
name: 'Test User'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body.data).toHaveProperty('user.id');
|
||||
expect(response.body.data).toHaveProperty('family.shareCode');
|
||||
expect(response.body.data.tokens.accessToken).toMatch(/^eyJ/);
|
||||
});
|
||||
|
||||
it('should enforce password requirements', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/v1/auth/register')
|
||||
.send({
|
||||
email: 'test@example.com',
|
||||
password: 'weak'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error.code).toBe('VALIDATION_ERROR');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### WebSocket Testing
|
||||
```typescript
|
||||
// realtime.integration.test.ts
|
||||
describe('Family Activity Sync', () => {
|
||||
let client1, client2;
|
||||
|
||||
beforeEach((done) => {
|
||||
client1 = io('http://localhost:3000', {
|
||||
auth: { token: 'parent1_token' }
|
||||
});
|
||||
client2 = io('http://localhost:3000', {
|
||||
auth: { token: 'parent2_token' }
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('should broadcast activity to family members', (done) => {
|
||||
client2.on('activity-logged', (data) => {
|
||||
expect(data.activityId).toBe('act_123');
|
||||
expect(data.type).toBe('feeding');
|
||||
done();
|
||||
});
|
||||
|
||||
client1.emit('log-activity', {
|
||||
type: 'feeding',
|
||||
childId: 'chd_123'
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## E2E Testing with Detox
|
||||
|
||||
### Critical User Journeys
|
||||
```javascript
|
||||
// e2e/criticalPaths.e2e.js
|
||||
describe('Onboarding Flow', () => {
|
||||
beforeAll(async () => {
|
||||
await device.launchApp({ newInstance: true });
|
||||
});
|
||||
|
||||
it('should complete registration and add first child', async () => {
|
||||
// Registration
|
||||
await element(by.id('get-started-button')).tap();
|
||||
await element(by.id('email-input')).typeText('parent@test.com');
|
||||
await element(by.id('password-input')).typeText('TestPass123!');
|
||||
await element(by.id('register-button')).tap();
|
||||
|
||||
// Add child
|
||||
await expect(element(by.id('add-child-screen'))).toBeVisible();
|
||||
await element(by.id('child-name-input')).typeText('Emma');
|
||||
await element(by.id('birth-date-picker')).tap();
|
||||
await element(by.text('15')).tap();
|
||||
await element(by.id('save-child-button')).tap();
|
||||
|
||||
// Verify dashboard
|
||||
await expect(element(by.text('Emma'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Offline Sync Testing
|
||||
```javascript
|
||||
describe('Offline Activity Logging', () => {
|
||||
it('should queue activities when offline', async () => {
|
||||
// Go offline
|
||||
await device.setURLBlacklist(['.*']);
|
||||
|
||||
// Log activity
|
||||
await element(by.id('quick-log-feeding')).tap();
|
||||
await element(by.id('amount-input')).typeText('4');
|
||||
await element(by.id('save-button')).tap();
|
||||
|
||||
// Verify local storage
|
||||
await expect(element(by.id('sync-pending-badge'))).toBeVisible();
|
||||
|
||||
// Go online
|
||||
await device.clearURLBlacklist();
|
||||
|
||||
// Verify sync
|
||||
await waitFor(element(by.id('sync-pending-badge')))
|
||||
.not.toBeVisible()
|
||||
.withTimeout(5000);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock Data Structures
|
||||
|
||||
### User & Family Mocks
|
||||
```typescript
|
||||
// mocks/users.ts
|
||||
export const mockParent = {
|
||||
id: 'usr_mock1',
|
||||
email: 'test@example.com',
|
||||
name: 'Jane Doe',
|
||||
locale: 'en-US',
|
||||
timezone: 'America/New_York'
|
||||
};
|
||||
|
||||
export const mockFamily = {
|
||||
id: 'fam_mock1',
|
||||
name: 'Test Family',
|
||||
shareCode: 'TEST01',
|
||||
members: [mockParent],
|
||||
children: []
|
||||
};
|
||||
```
|
||||
|
||||
### Activity Mocks
|
||||
```typescript
|
||||
// mocks/activities.ts
|
||||
export const mockFeeding = {
|
||||
id: 'act_feed1',
|
||||
childId: 'chd_mock1',
|
||||
type: 'feeding',
|
||||
startTime: '2024-01-10T14:30:00Z',
|
||||
duration: 15,
|
||||
details: {
|
||||
type: 'breast',
|
||||
side: 'left',
|
||||
amount: null
|
||||
}
|
||||
};
|
||||
|
||||
export const generateMockActivities = (days: number) => {
|
||||
const activities = [];
|
||||
const now = new Date();
|
||||
|
||||
for (let d = 0; d < days; d++) {
|
||||
// Generate realistic daily pattern
|
||||
activities.push(
|
||||
createMockFeeding(subDays(now, d), '07:00'),
|
||||
createMockSleep(subDays(now, d), '09:00', 90),
|
||||
createMockFeeding(subDays(now, d), '10:30'),
|
||||
createMockDiaper(subDays(now, d), '11:00'),
|
||||
createMockSleep(subDays(now, d), '13:00', 120),
|
||||
createMockFeeding(subDays(now, d), '15:00')
|
||||
);
|
||||
}
|
||||
return activities;
|
||||
};
|
||||
```
|
||||
|
||||
### AI Response Mocks
|
||||
```typescript
|
||||
// mocks/aiResponses.ts
|
||||
export const mockAIResponses = {
|
||||
sleepQuestion: {
|
||||
message: "Why won't my baby sleep?",
|
||||
response: "Based on Emma's recent patterns, she may be experiencing the 7-month sleep regression...",
|
||||
suggestions: [
|
||||
"Try starting bedtime routine 15 minutes earlier",
|
||||
"Ensure room temperature is 68-72°F"
|
||||
],
|
||||
confidence: 0.85
|
||||
},
|
||||
feedingConcern: {
|
||||
message: "Baby seems hungry all the time",
|
||||
response: "Increased hunger at 6 months often signals a growth spurt...",
|
||||
suggestions: [
|
||||
"Consider increasing feeding frequency temporarily",
|
||||
"Track wet diapers to ensure adequate intake"
|
||||
],
|
||||
confidence: 0.92
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Testing
|
||||
|
||||
### Load Testing Scenarios
|
||||
```javascript
|
||||
// performance/loadTest.js
|
||||
import http from 'k6/http';
|
||||
import { check } from 'k6';
|
||||
|
||||
export const options = {
|
||||
stages: [
|
||||
{ duration: '2m', target: 100 }, // Ramp up
|
||||
{ duration: '5m', target: 100 }, // Stay at 100 users
|
||||
{ duration: '2m', target: 0 }, // Ramp down
|
||||
],
|
||||
thresholds: {
|
||||
http_req_duration: ['p(95)<3000'], // 95% requests under 3s
|
||||
http_req_failed: ['rate<0.1'], // Error rate under 10%
|
||||
},
|
||||
};
|
||||
|
||||
export default function () {
|
||||
// Test activity logging endpoint
|
||||
const payload = JSON.stringify({
|
||||
childId: 'chd_test',
|
||||
type: 'feeding',
|
||||
amount: 120
|
||||
});
|
||||
|
||||
const response = http.post('http://localhost:3000/api/v1/activities/feeding', payload, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ${__ENV.TEST_TOKEN}'
|
||||
},
|
||||
});
|
||||
|
||||
check(response, {
|
||||
'status is 201': (r) => r.status === 201,
|
||||
'response time < 500ms': (r) => r.timings.duration < 500,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Mobile Performance Testing
|
||||
```typescript
|
||||
// Mobile performance metrics
|
||||
describe('Performance Benchmarks', () => {
|
||||
it('should render dashboard in under 1 second', async () => {
|
||||
const startTime = Date.now();
|
||||
await element(by.id('dashboard-screen')).tap();
|
||||
await expect(element(by.id('activities-list'))).toBeVisible();
|
||||
const loadTime = Date.now() - startTime;
|
||||
|
||||
expect(loadTime).toBeLessThan(1000);
|
||||
});
|
||||
|
||||
it('should handle 1000+ activities smoothly', async () => {
|
||||
// Test with large dataset
|
||||
await device.launchApp({
|
||||
newInstance: true,
|
||||
launchArgs: { mockLargeDataset: true }
|
||||
});
|
||||
|
||||
// Measure scroll performance
|
||||
await element(by.id('activities-list')).scroll(500, 'down', NaN, 0.8);
|
||||
// Should not freeze or stutter
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility Testing
|
||||
|
||||
### WCAG Compliance Tests
|
||||
```typescript
|
||||
// accessibility/wcag.test.tsx
|
||||
import { axe, toHaveNoViolations } from 'jest-axe';
|
||||
|
||||
expect.extend(toHaveNoViolations);
|
||||
|
||||
describe('Accessibility Compliance', () => {
|
||||
it('should have no WCAG violations on dashboard', async () => {
|
||||
const { container } = render(<Dashboard />);
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
|
||||
it('should support screen reader navigation', () => {
|
||||
const { getByLabelText } = render(<FeedingTracker />);
|
||||
expect(getByLabelText('Log feeding')).toBeTruthy();
|
||||
expect(getByLabelText('Select breast side')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### One-Handed Operation Tests
|
||||
```javascript
|
||||
// e2e/oneHanded.e2e.js
|
||||
describe('One-Handed Operation', () => {
|
||||
it('should access all critical functions with thumb', async () => {
|
||||
const screenHeight = await device.getScreenHeight();
|
||||
const thumbReach = screenHeight * 0.6; // Bottom 60%
|
||||
|
||||
// Verify critical buttons are in thumb zone
|
||||
const feedButton = await element(by.id('quick-log-feeding')).getLocation();
|
||||
expect(feedButton.y).toBeGreaterThan(thumbReach);
|
||||
|
||||
const sleepButton = await element(by.id('quick-log-sleep')).getLocation();
|
||||
expect(sleepButton.y).toBeGreaterThan(thumbReach);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI Testing
|
||||
|
||||
### LLM Response Validation
|
||||
```typescript
|
||||
// ai/llmResponse.test.ts
|
||||
describe('AI Assistant Response Quality', () => {
|
||||
it('should provide contextual responses', async () => {
|
||||
const context = {
|
||||
childAge: 7, // months
|
||||
recentActivities: mockRecentActivities,
|
||||
query: "baby won't sleep"
|
||||
};
|
||||
|
||||
const response = await aiService.generateResponse(context);
|
||||
|
||||
expect(response).toContain('7-month');
|
||||
expect(response.confidence).toBeGreaterThan(0.7);
|
||||
expect(response.suggestions).toBeArray();
|
||||
expect(response.harmfulContent).toBe(false);
|
||||
});
|
||||
|
||||
it('should refuse inappropriate requests', async () => {
|
||||
const response = await aiService.generateResponse({
|
||||
query: "diagnose my baby's rash"
|
||||
});
|
||||
|
||||
expect(response).toContain('consult');
|
||||
expect(response).toContain('healthcare provider');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Data Management
|
||||
|
||||
### Database Seeding
|
||||
```typescript
|
||||
// test/seed.ts
|
||||
export async function seedTestDatabase() {
|
||||
await db.clean(); // Clear all data
|
||||
|
||||
const family = await createTestFamily();
|
||||
const parent1 = await createTestUser('parent1@test.com', family.id);
|
||||
const parent2 = await createTestUser('parent2@test.com', family.id);
|
||||
const child = await createTestChild('Emma', '2023-06-15', family.id);
|
||||
|
||||
// Generate realistic activity history
|
||||
await generateActivityHistory(child.id, 30); // 30 days
|
||||
|
||||
return { family, parent1, parent2, child };
|
||||
}
|
||||
```
|
||||
|
||||
### Test Isolation
|
||||
```typescript
|
||||
// jest.setup.ts
|
||||
beforeEach(async () => {
|
||||
await db.transaction.start();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.transaction.rollback();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Test Pipeline
|
||||
|
||||
### GitHub Actions Configuration
|
||||
```yaml
|
||||
# .github/workflows/test.yml
|
||||
name: Test Suite
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- run: npm ci
|
||||
- run: npm run test:unit
|
||||
- uses: codecov/codecov-action@v2
|
||||
|
||||
integration-tests:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
redis:
|
||||
image: redis:7
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm ci
|
||||
- run: npm run test:integration
|
||||
|
||||
e2e-tests:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm ci
|
||||
- run: npx detox build -c ios.sim.release
|
||||
- run: npx detox test -c ios.sim.release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Coverage Requirements
|
||||
|
||||
### Minimum Coverage Thresholds
|
||||
```json
|
||||
// jest.config.js
|
||||
{
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 70,
|
||||
"functions": 80,
|
||||
"lines": 80,
|
||||
"statements": 80
|
||||
},
|
||||
"src/services/": {
|
||||
"branches": 85,
|
||||
"functions": 90
|
||||
},
|
||||
"src/components/": {
|
||||
"branches": 75,
|
||||
"functions": 85
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Critical Path Coverage
|
||||
- Authentication flow: 100%
|
||||
- Activity logging: 95%
|
||||
- Real-time sync: 90%
|
||||
- AI responses: 85%
|
||||
- Offline queue: 90%
|
||||
|
||||
---
|
||||
|
||||
## Test Reporting
|
||||
|
||||
### Test Result Format
|
||||
```bash
|
||||
# Console output
|
||||
PASS src/components/FeedingTracker.test.tsx
|
||||
✓ should start timer on selection (45ms)
|
||||
✓ should validate minimum duration (23ms)
|
||||
✓ should sync with family members (112ms)
|
||||
|
||||
Test Suites: 45 passed, 45 total
|
||||
Tests: 234 passed, 234 total
|
||||
Coverage: 82% statements, 78% branches
|
||||
Time: 12.456s
|
||||
```
|
||||
|
||||
### Coverage Reports
|
||||
- HTML reports in `/coverage/lcov-report/`
|
||||
- Codecov integration for PR comments
|
||||
- SonarQube for code quality metrics
|
||||
590
docs/maternal-app-voice-processing.md
Normal file
590
docs/maternal-app-voice-processing.md
Normal file
@@ -0,0 +1,590 @@
|
||||
# Voice Input Processing Guide - Maternal Organization App
|
||||
|
||||
## Voice Processing Architecture
|
||||
|
||||
### Overview
|
||||
Voice input enables hands-free logging during childcare activities. The system processes natural language in 5 languages, extracting structured data from casual speech patterns.
|
||||
|
||||
### Processing Pipeline
|
||||
```
|
||||
Audio Input → Speech Recognition → Language Detection →
|
||||
Intent Classification → Entity Extraction → Action Execution →
|
||||
Confirmation Feedback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Whisper API Integration
|
||||
|
||||
### Configuration
|
||||
```typescript
|
||||
// services/whisperService.ts
|
||||
import OpenAI from 'openai';
|
||||
|
||||
class WhisperService {
|
||||
private client: OpenAI;
|
||||
|
||||
constructor() {
|
||||
this.client = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
}
|
||||
|
||||
async transcribeAudio(audioBuffer: Buffer, language?: string): Promise<TranscriptionResult> {
|
||||
try {
|
||||
const response = await this.client.audio.transcriptions.create({
|
||||
file: audioBuffer,
|
||||
model: 'whisper-1',
|
||||
language: language || 'en', // ISO-639-1 code
|
||||
response_format: 'verbose_json',
|
||||
timestamp_granularities: ['word'],
|
||||
});
|
||||
|
||||
return {
|
||||
text: response.text,
|
||||
language: response.language,
|
||||
confidence: this.calculateConfidence(response),
|
||||
words: response.words,
|
||||
};
|
||||
} catch (error) {
|
||||
return this.handleTranscriptionError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Audio Preprocessing
|
||||
```typescript
|
||||
// utils/audioPreprocessing.ts
|
||||
export const preprocessAudio = async (audioFile: File): Promise<Buffer> => {
|
||||
// Validate format
|
||||
const validFormats = ['wav', 'mp3', 'm4a', 'webm'];
|
||||
if (!validFormats.includes(getFileExtension(audioFile))) {
|
||||
throw new Error('Unsupported audio format');
|
||||
}
|
||||
|
||||
// Check file size (max 25MB for Whisper)
|
||||
if (audioFile.size > 25 * 1024 * 1024) {
|
||||
// Compress or chunk the audio
|
||||
return await compressAudio(audioFile);
|
||||
}
|
||||
|
||||
// Noise reduction for better accuracy
|
||||
return await reduceNoise(audioFile);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Natural Language Command Patterns
|
||||
|
||||
### Intent Classification
|
||||
```typescript
|
||||
enum VoiceIntent {
|
||||
LOG_FEEDING = 'LOG_FEEDING',
|
||||
LOG_SLEEP = 'LOG_SLEEP',
|
||||
LOG_DIAPER = 'LOG_DIAPER',
|
||||
LOG_MEDICATION = 'LOG_MEDICATION',
|
||||
START_TIMER = 'START_TIMER',
|
||||
STOP_TIMER = 'STOP_TIMER',
|
||||
ASK_QUESTION = 'ASK_QUESTION',
|
||||
CHECK_STATUS = 'CHECK_STATUS',
|
||||
CANCEL = 'CANCEL'
|
||||
}
|
||||
|
||||
interface IntentPattern {
|
||||
intent: VoiceIntent;
|
||||
patterns: RegExp[];
|
||||
requiredEntities: string[];
|
||||
examples: string[];
|
||||
}
|
||||
```
|
||||
|
||||
### English Language Patterns
|
||||
```typescript
|
||||
const englishPatterns: IntentPattern[] = [
|
||||
{
|
||||
intent: VoiceIntent.LOG_FEEDING,
|
||||
patterns: [
|
||||
/(?:baby |she |he )?(?:fed|ate|drank|had|nursed)/i,
|
||||
/(?:bottle|breast|nursing|feeding)/i,
|
||||
/(?:finished|done) (?:eating|feeding|nursing)/i,
|
||||
],
|
||||
requiredEntities: ['amount?', 'time?', 'type?'],
|
||||
examples: [
|
||||
"Baby fed 4 ounces",
|
||||
"Just nursed for 15 minutes on the left",
|
||||
"She had 120ml of formula at 3pm",
|
||||
"Finished feeding, both sides, 20 minutes total"
|
||||
]
|
||||
},
|
||||
{
|
||||
intent: VoiceIntent.LOG_SLEEP,
|
||||
patterns: [
|
||||
/(?:went|going) (?:to )?(?:sleep|bed|nap)/i,
|
||||
/(?:woke|wake|waking) up/i,
|
||||
/(?:nap|sleep)(?:ping|ed)? (?:for|since)/i,
|
||||
/(?:fell) asleep/i,
|
||||
],
|
||||
requiredEntities: ['time?', 'duration?'],
|
||||
examples: [
|
||||
"Down for a nap",
|
||||
"Woke up from nap",
|
||||
"Sleeping since 2pm",
|
||||
"Just fell asleep in the stroller"
|
||||
]
|
||||
},
|
||||
{
|
||||
intent: VoiceIntent.LOG_DIAPER,
|
||||
patterns: [
|
||||
/(?:chang|dirty|wet|soil|poop|pee)/i,
|
||||
/diaper/i,
|
||||
/(?:number|#) (?:one|two|1|2)/i,
|
||||
],
|
||||
requiredEntities: ['type?'],
|
||||
examples: [
|
||||
"Changed wet diaper",
|
||||
"Dirty diaper with rash",
|
||||
"Just changed a poopy one",
|
||||
"Diaper change, both wet and dirty"
|
||||
]
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
### Multi-Language Patterns
|
||||
```typescript
|
||||
// Spanish patterns
|
||||
const spanishPatterns: IntentPattern[] = [
|
||||
{
|
||||
intent: VoiceIntent.LOG_FEEDING,
|
||||
patterns: [
|
||||
/(?:comió|tomó|bebió|amamanté)/i,
|
||||
/(?:biberón|pecho|lactancia)/i,
|
||||
],
|
||||
examples: [
|
||||
"Tomó 120ml de fórmula",
|
||||
"Amamanté 15 minutos lado izquierdo",
|
||||
"Ya comió papilla"
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// French patterns
|
||||
const frenchPatterns: IntentPattern[] = [
|
||||
{
|
||||
intent: VoiceIntent.LOG_FEEDING,
|
||||
patterns: [
|
||||
/(?:mangé|bu|allaité|nourri)/i,
|
||||
/(?:biberon|sein|tétée)/i,
|
||||
],
|
||||
examples: [
|
||||
"Biberon de 120ml",
|
||||
"Allaité 15 minutes côté gauche",
|
||||
"A mangé sa purée"
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// Portuguese patterns
|
||||
const portuguesePatterns: IntentPattern[] = [
|
||||
{
|
||||
intent: VoiceIntent.LOG_FEEDING,
|
||||
patterns: [
|
||||
/(?:comeu|tomou|bebeu|amamentei)/i,
|
||||
/(?:mamadeira|peito|amamentação)/i,
|
||||
],
|
||||
examples: [
|
||||
"Tomou 120ml de fórmula",
|
||||
"Amamentei 15 minutos lado esquerdo"
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// Chinese patterns
|
||||
const chinesePatterns: IntentPattern[] = [
|
||||
{
|
||||
intent: VoiceIntent.LOG_FEEDING,
|
||||
patterns: [
|
||||
/(?:喂|吃|喝|哺乳)/,
|
||||
/(?:奶瓶|母乳|配方奶)/,
|
||||
],
|
||||
examples: [
|
||||
"喝了120毫升配方奶",
|
||||
"母乳喂养15分钟",
|
||||
"吃了辅食"
|
||||
]
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Entity Extraction
|
||||
|
||||
### Entity Types
|
||||
```typescript
|
||||
interface ExtractedEntities {
|
||||
amount?: {
|
||||
value: number;
|
||||
unit: 'oz' | 'ml' | 'minutes';
|
||||
};
|
||||
time?: {
|
||||
value: Date;
|
||||
precision: 'exact' | 'approximate';
|
||||
};
|
||||
duration?: {
|
||||
value: number;
|
||||
unit: 'minutes' | 'hours';
|
||||
};
|
||||
side?: 'left' | 'right' | 'both';
|
||||
type?: 'breast' | 'bottle' | 'solid' | 'wet' | 'dirty' | 'both';
|
||||
location?: string;
|
||||
notes?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Extraction Logic
|
||||
```typescript
|
||||
class EntityExtractor {
|
||||
extractAmount(text: string): ExtractedEntities['amount'] {
|
||||
// Numeric amounts with units
|
||||
const amountPattern = /(\d+(?:\.\d+)?)\s*(oz|ounce|ml|milliliter|minute|min)/i;
|
||||
const match = text.match(amountPattern);
|
||||
|
||||
if (match) {
|
||||
return {
|
||||
value: parseFloat(match[1]),
|
||||
unit: this.normalizeUnit(match[2])
|
||||
};
|
||||
}
|
||||
|
||||
// Word numbers
|
||||
const wordNumbers = {
|
||||
'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5,
|
||||
'ten': 10, 'fifteen': 15, 'twenty': 20, 'thirty': 30,
|
||||
};
|
||||
|
||||
for (const [word, value] of Object.entries(wordNumbers)) {
|
||||
if (text.includes(word)) {
|
||||
return { value, unit: this.inferUnit(text) };
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
extractTime(text: string, timezone: string): ExtractedEntities['time'] {
|
||||
const now = new Date();
|
||||
|
||||
// Relative times
|
||||
if (/just|now|right now/i.test(text)) {
|
||||
return { value: now, precision: 'exact' };
|
||||
}
|
||||
|
||||
if (/ago/i.test(text)) {
|
||||
const minutesAgo = this.extractMinutesAgo(text);
|
||||
return {
|
||||
value: new Date(now.getTime() - minutesAgo * 60000),
|
||||
precision: 'approximate'
|
||||
};
|
||||
}
|
||||
|
||||
// Clock times
|
||||
const timePattern = /(\d{1,2}):?(\d{2})?\s*(am|pm)?/i;
|
||||
const match = text.match(timePattern);
|
||||
|
||||
if (match) {
|
||||
return {
|
||||
value: this.parseClockTime(match, timezone),
|
||||
precision: 'exact'
|
||||
};
|
||||
}
|
||||
|
||||
return { value: now, precision: 'approximate' };
|
||||
}
|
||||
|
||||
extractSide(text: string): ExtractedEntities['side'] {
|
||||
if (/left|izquierdo|gauche|esquerdo|左/i.test(text)) return 'left';
|
||||
if (/right|derecho|droit|direito|右/i.test(text)) return 'right';
|
||||
if (/both|ambos|deux|ambos|两|両/i.test(text)) return 'both';
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Intent Processing Engine
|
||||
|
||||
### Main Processing Flow
|
||||
```typescript
|
||||
class VoiceCommandProcessor {
|
||||
async processVoiceInput(
|
||||
audioBuffer: Buffer,
|
||||
context: UserContext
|
||||
): Promise<ProcessedCommand> {
|
||||
// 1. Transcribe audio
|
||||
const transcription = await this.whisperService.transcribeAudio(
|
||||
audioBuffer,
|
||||
context.language
|
||||
);
|
||||
|
||||
if (transcription.confidence < 0.5) {
|
||||
return this.handleLowConfidence(transcription);
|
||||
}
|
||||
|
||||
// 2. Detect intent
|
||||
const intent = await this.detectIntent(
|
||||
transcription.text,
|
||||
context.language
|
||||
);
|
||||
|
||||
// 3. Extract entities
|
||||
const entities = await this.extractEntities(
|
||||
transcription.text,
|
||||
intent,
|
||||
context
|
||||
);
|
||||
|
||||
// 4. Validate command
|
||||
const validation = this.validateCommand(intent, entities);
|
||||
|
||||
if (!validation.isValid) {
|
||||
return this.requestClarification(validation.missingInfo);
|
||||
}
|
||||
|
||||
// 5. Execute action
|
||||
return this.executeCommand(intent, entities, context);
|
||||
}
|
||||
|
||||
private async detectIntent(
|
||||
text: string,
|
||||
language: string
|
||||
): Promise<VoiceIntent> {
|
||||
const patterns = this.getPatternsByLanguage(language);
|
||||
|
||||
for (const pattern of patterns) {
|
||||
for (const regex of pattern.patterns) {
|
||||
if (regex.test(text)) {
|
||||
return pattern.intent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to AI intent detection
|
||||
return this.detectIntentWithAI(text, language);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Recovery
|
||||
|
||||
### Common Recognition Errors
|
||||
```typescript
|
||||
interface RecognitionError {
|
||||
type: 'LOW_CONFIDENCE' | 'AMBIGUOUS' | 'MISSING_DATA' | 'INVALID_VALUE';
|
||||
originalText: string;
|
||||
suggestions?: string[];
|
||||
}
|
||||
|
||||
class ErrorRecovery {
|
||||
handleLowConfidence(transcription: TranscriptionResult): ProcessedCommand {
|
||||
// Check for common misheard phrases
|
||||
const corrections = this.checkCommonMishears(transcription.text);
|
||||
|
||||
if (corrections.confidence > 0.7) {
|
||||
return this.retryWithCorrection(corrections.text);
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
action: 'CONFIRM',
|
||||
message: `Did you say "${transcription.text}"?`,
|
||||
alternatives: this.getSimilarPhrases(transcription.text)
|
||||
};
|
||||
}
|
||||
|
||||
checkCommonMishears(text: string): CorrectionResult {
|
||||
const corrections = {
|
||||
'for ounces': 'four ounces',
|
||||
'to ounces': 'two ounces',
|
||||
'write side': 'right side',
|
||||
'laugh side': 'left side',
|
||||
'wet and dirty': 'wet and dirty',
|
||||
'wedding dirty': 'wet and dirty',
|
||||
};
|
||||
|
||||
for (const [misheard, correct] of Object.entries(corrections)) {
|
||||
if (text.includes(misheard)) {
|
||||
return {
|
||||
text: text.replace(misheard, correct),
|
||||
confidence: 0.8
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { text, confidence: 0.3 };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Clarification Prompts
|
||||
```typescript
|
||||
const clarificationPrompts = {
|
||||
MISSING_AMOUNT: {
|
||||
en: "How much did baby eat?",
|
||||
es: "¿Cuánto comió el bebé?",
|
||||
fr: "Combien a mangé bébé?",
|
||||
pt: "Quanto o bebê comeu?",
|
||||
zh: "宝宝吃了多少?"
|
||||
},
|
||||
MISSING_TIME: {
|
||||
en: "When did this happen?",
|
||||
es: "¿Cuándo ocurrió esto?",
|
||||
fr: "Quand cela s'est-il passé?",
|
||||
pt: "Quando isso aconteceu?",
|
||||
zh: "这是什么时候发生的?"
|
||||
},
|
||||
AMBIGUOUS_INTENT: {
|
||||
en: "What would you like to log?",
|
||||
es: "¿Qué te gustaría registrar?",
|
||||
fr: "Que souhaitez-vous enregistrer?",
|
||||
pt: "O que você gostaria de registrar?",
|
||||
zh: "您想记录什么?"
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Offline Voice Processing
|
||||
|
||||
### Fallback Strategy
|
||||
```typescript
|
||||
class OfflineVoiceProcessor {
|
||||
async processOffline(audioBuffer: Buffer): Promise<BasicTranscription> {
|
||||
// Use device's native speech recognition
|
||||
if (Platform.OS === 'ios') {
|
||||
return this.useiOSSpeechRecognition(audioBuffer);
|
||||
} else if (Platform.OS === 'android') {
|
||||
return this.useAndroidSpeechRecognition(audioBuffer);
|
||||
}
|
||||
|
||||
// Queue for later processing
|
||||
return this.queueForOnlineProcessing(audioBuffer);
|
||||
}
|
||||
|
||||
private async useiOSSpeechRecognition(audio: Buffer) {
|
||||
// Use SFSpeechRecognizer
|
||||
const recognizer = new SFSpeechRecognizer();
|
||||
return recognizer.recognize(audio);
|
||||
}
|
||||
|
||||
private async useAndroidSpeechRecognition(audio: Buffer) {
|
||||
// Use Android SpeechRecognizer
|
||||
const recognizer = new AndroidSpeechRecognizer();
|
||||
return recognizer.recognize(audio);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Confirmation & Feedback
|
||||
|
||||
### Voice Feedback System
|
||||
```typescript
|
||||
interface VoiceConfirmation {
|
||||
text: string;
|
||||
speech: string; // SSML for TTS
|
||||
visual: {
|
||||
icon: string;
|
||||
color: string;
|
||||
animation: string;
|
||||
};
|
||||
haptic?: 'success' | 'warning' | 'error';
|
||||
}
|
||||
|
||||
const confirmations = {
|
||||
FEEDING_LOGGED: {
|
||||
text: "Feeding logged",
|
||||
speech: "<speak>Got it! <break time='200ms'/> Logged <say-as interpret-as='cardinal'>4</say-as> ounces.</speak>",
|
||||
visual: {
|
||||
icon: 'check_circle',
|
||||
color: 'success',
|
||||
animation: 'bounce'
|
||||
},
|
||||
haptic: 'success'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Voice Commands
|
||||
|
||||
### Test Scenarios
|
||||
```typescript
|
||||
const voiceTestCases = [
|
||||
// English
|
||||
{ input: "Baby ate 4 ounces", expected: { intent: 'LOG_FEEDING', amount: 4, unit: 'oz' }},
|
||||
{ input: "Nursed for fifteen minutes on the left", expected: { intent: 'LOG_FEEDING', duration: 15, side: 'left' }},
|
||||
|
||||
// Spanish
|
||||
{ input: "Tomó 120 mililitros", expected: { intent: 'LOG_FEEDING', amount: 120, unit: 'ml' }},
|
||||
|
||||
// Edge cases
|
||||
{ input: "Fed... um... about 4 or 5 ounces", expected: { intent: 'LOG_FEEDING', amount: 4, confidence: 'low' }},
|
||||
{ input: "Changed a really dirty diaper", expected: { intent: 'LOG_DIAPER', type: 'dirty', notes: 'really dirty' }},
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Audio Streaming
|
||||
```typescript
|
||||
class StreamingVoiceProcessor {
|
||||
private audioChunks: Buffer[] = [];
|
||||
private isProcessing = false;
|
||||
|
||||
async processStream(chunk: Buffer) {
|
||||
this.audioChunks.push(chunk);
|
||||
|
||||
if (!this.isProcessing && this.hasEnoughAudio()) {
|
||||
this.isProcessing = true;
|
||||
const result = await this.processChunks();
|
||||
this.isProcessing = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private hasEnoughAudio(): boolean {
|
||||
// Need at least 0.5 seconds of audio
|
||||
const totalSize = this.audioChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
||||
return totalSize > 8000; // ~0.5s at 16kHz
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caching Common Commands
|
||||
```typescript
|
||||
const commandCache = new LRUCache<string, ProcessedCommand>({
|
||||
max: 100,
|
||||
ttl: 1000 * 60 * 60, // 1 hour
|
||||
});
|
||||
|
||||
// Cache exact matches for common phrases
|
||||
const cachedPhrases = [
|
||||
"wet diaper",
|
||||
"dirty diaper",
|
||||
"just nursed",
|
||||
"bottle feeding done",
|
||||
"down for a nap",
|
||||
"woke up"
|
||||
];
|
||||
```
|
||||
87
docs/mobile-and-web-app-for-mothers.md
Normal file
87
docs/mobile-and-web-app-for-mothers.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# The overwhelmed mother's digital lifeline: Building an AI-powered organization app for modern parenting
|
||||
|
||||
Mothers carry **71% of household mental load** while managing careers, childcare, and their own wellbeing - often with minimal support. With 10-20% experiencing untreated perinatal mental health conditions globally and 90% facing career-threatening challenges upon returning to work, the need for intelligent digital support has never been more critical. This comprehensive analysis reveals how an AI-powered app can transform the chaos of modern motherhood into manageable, predictable routines that actually work.
|
||||
|
||||
## The hidden crisis modern mothers face daily
|
||||
|
||||
The data paints a stark picture of maternal overwhelm that crosses all demographics and geographies. **Mothers handle 79% of daily household tasks** - over twice the contribution of fathers - while simultaneously managing complex schedules, making thousands of micro-decisions, and often sacrificing their own sleep and wellbeing. The mental load crisis is quantifiable: women perform nearly 4 hours of unpaid work daily compared to men's 2.5 hours globally, with mothers reporting feeling rushed 86% of the time.
|
||||
|
||||
Mental health challenges compound these organizational struggles. Postpartum depression affects 13-20% of mothers worldwide, yet **75% remain untreated** due to stigma, access barriers, and time constraints. In developing countries, rates climb to 19.8% postpartum. The economic toll is staggering - untreated maternal mental health conditions cost $14.2 billion annually in the US alone, or $32,000 per mother-infant pair. Sleep deprivation peaks during infancy, with mothers losing an average of 42 minutes nightly, while 40.3% of infants aged 4-11 months don't meet recommended sleep durations, creating a destructive cycle of exhaustion.
|
||||
|
||||
The work-life balance struggle intensifies these challenges. Nine out of ten working mothers face at least one major career-threatening challenge, with 57% of those with children under five feeling professionally held back. **Half of all employees with children** have considered leaving their organization due to inadequate childcare support. The partnership gap adds another layer - 74% of mothers manage children's schedules compared to their partners, and men consistently overestimate their household contributions, leading to resentment and conflict.
|
||||
|
||||
## Current solutions fall short of mothers' complex needs
|
||||
|
||||
The parenting app market, valued at $1.45-2.0 billion and growing at 7.8-20.37% annually, offers fragmented solutions that fail to address the holistic nature of maternal challenges. While apps like Huckleberry excel at sleep prediction with 93% success rates among 4 million users, and Cozi provides color-coded calendars for family coordination, **no single platform integrates all aspects** of maternal organization with intelligent automation.
|
||||
|
||||
Major gaps plague existing solutions. Integration between different apps remains poor, forcing mothers to manage multiple platforms. AI capabilities are limited to basic pattern recognition rather than predictive, proactive support. Community features often devolve into toxic environments - BabyCenter's 1.8/5 Trustpilot rating stems from "mean girl mob mentality" and poor moderation. Platform inconsistencies frustrate users, with features working differently across web and mobile versions. Perhaps most critically, current apps treat symptoms rather than addressing the underlying mental load problem.
|
||||
|
||||
User complaints reveal deep dissatisfaction with generic, copy-pasted advice that ignores individual family contexts. Peanut's "Tinder for moms" concept struggles to create meaningful connections, with users reporting difficulty converting matches to real friendships. Premium pricing feels steep for basic features - Huckleberry charges $58.99 annually for sleep recommendations that become less useful once children enter daycare. The market clearly demands a comprehensive, intelligent solution that grows with families rather than forcing them to constantly switch platforms.
|
||||
|
||||
## AI transforms overwhelming complexity into manageable routines
|
||||
|
||||
The most promising AI implementations demonstrate remarkable potential for reducing maternal burden. Huckleberry's SweetSpot® algorithm analyzes hundreds of millions of sleep data points to predict optimal nap times with uncanny accuracy, adapting to individual patterns within 5 days. Their success - trusted by 4 million parents across 179 countries - proves mothers will embrace AI that delivers tangible results. Natural language processing enables voice logging during hands-occupied moments ("baby fed 4oz at 3pm"), while pattern recognition identifies trends humans miss.
|
||||
|
||||
Mental health support represents AI's most transformative application. Woebot's randomized controlled trial with 184 postpartum women showed **70% achieving clinically significant improvement** versus 30% in the control group, with participants engaging 5 times weekly on average. The 24/7 availability addresses traditional therapy barriers - cost, stigma, scheduling - while providing immediate crisis support with human escalation protocols. University of Texas researchers are developing specialized chatbots for postpartum depression through Postpartum Support International, recognizing AI's potential to reach underserved mothers.
|
||||
|
||||
Practical automation capabilities extend beyond emotional support. Ollie AI's meal planning platform saves families 5 hours weekly through natural language dietary preference processing and automated grocery integration. Google Assistant's Family Features recognize up to 6 family members' voices, enabling personalized responses and parental controls. Microsoft's Document Intelligence processes receipts with 90% accuracy improvement over manual entry, while computer vision applications automatically sort photos by child and milestone. These aren't futuristic concepts - they're proven technologies ready for integration.
|
||||
|
||||
## Core MVP features that deliver immediate value
|
||||
|
||||
Based on comprehensive research, the MVP must prioritize features addressing the most acute pain points while building toward a comprehensive platform. **Essential tracking capabilities** form the foundation: feeding, sleep, and diaper logging with voice input for hands-free operation. The magic happens when AI analyzes this data - Huckleberry's sleep prediction model demonstrates how pattern recognition transforms raw data into actionable insights. Multi-user access ensures both parents and caregivers stay synchronized, addressing the coordination challenges 74% of mothers face.
|
||||
|
||||
The **AI conversational assistant** represents the MVP's breakthrough feature. Available 24/7, it provides evidence-based guidance personalized to each child's patterns and developmental stage. Unlike generic chatbots, it learns from family data to offer increasingly relevant suggestions. Dr. Becky Kennedy's Good Inside app validates this approach with 90,000+ paying members for AI-powered parenting scripts. The assistant should handle everything from "why won't my baby sleep?" to "healthy dinner ideas for picky toddlers," reducing decision fatigue that plagues overwhelmed mothers.
|
||||
|
||||
Age-specific adaptations ensure relevance across the 0-6 range. For infants (0-1 year), prioritize feeding schedules, sleep optimization, growth tracking, and vaccination reminders. Toddler features (1-3 years) focus on routine management, potty training progress, and behavioral pattern analysis. Preschool tools (3-6 years) emphasize school readiness, social skill development, and activity coordination. **The platform must grow with families** rather than forcing app-switching as children develop.
|
||||
|
||||
Quick-win AI features provide immediate value while building user trust. Smart notifications deliver context-aware reminders based on family patterns - alerting about nap time based on wake windows, suggesting feeding times from hunger cues. Pattern detection identifies correlations mothers might miss: "Your baby sleeps 47 minutes longer after outdoor morning activities." Voice processing allows natural language input during chaotic moments. These features require relatively simple implementation while delivering outsized impact on daily stress.
|
||||
|
||||
## Building trust through privacy-first design
|
||||
|
||||
Privacy concerns dominate parental technology decisions, making compliance and transparency competitive advantages rather than regulatory burdens. **COPPA compliance in the US** requires verifiable parental consent before collecting data from children under 13, with clear policies describing collection practices. GDPR Article 8 extends protection in Europe, with age thresholds varying by country. The app must implement risk-based verification - email confirmation for low-risk features, credit card verification for medium risk, government ID for high-risk data access.
|
||||
|
||||
Security architecture must exceed typical app standards given sensitive family data. End-to-end encryption protects information in transit and at rest. Regular security audits and penetration testing ensure ongoing protection. Multi-factor authentication secures parental accounts while maintaining quick access for authorized caregivers. **Data minimization principles** mean collecting only essential information, with automatic deletion of unnecessary data. Parents must control their data completely - viewing, downloading, and permanently deleting at will.
|
||||
|
||||
Transparency builds trust where many apps fail. Clear, plain-language privacy policies explain exactly what data is collected, how it's used, and who has access. Opt-in rather than opt-out for all non-essential features. No selling or sharing data with third parties for advertising. Age-appropriate content filtering and parental controls for any community features. YouTube's $170 million fine for tracking children without consent demonstrates the serious consequences of privacy violations - but also the opportunity to differentiate through ethical data practices.
|
||||
|
||||
## UX designed for chaos: One hand, divided attention, constant interruption
|
||||
|
||||
Mothers interact with technology under uniquely challenging conditions. Research shows 49% of mobile users operate phones one-handed while multitasking, with 70% of interactions lasting under 2 minutes. Parents experience "distracted short-burst usage" patterns with 58 daily phone checks between childcare tasks. **The UX must accommodate this reality** through placement of critical functions within thumb's reach, bottom navigation bars instead of hamburger menus, and gesture-based interactions for common tasks.
|
||||
|
||||
The three-tap rule governs feature design - core functions must be accessible within three taps or less. Auto-save functionality prevents data loss during inevitable interruptions. Resume capability allows mothers to complete tasks started hours earlier. Visual state indicators show progress at a glance. **Interruption-resistant design** means every interaction can be abandoned mid-task without losing work, crucial when children demand immediate attention.
|
||||
|
||||
Successful patterns from consumer apps translate effectively. Instagram's story-style updates work for sharing family moments with grandparents. TikTok's swipe navigation enables quick browsing during brief free moments. Voice input becomes essential when hands are occupied with children. Visual information trumps text - icons, colors, and progress bars communicate faster than words. The interface must feel familiar and intuitive, eliminating learning curves that busy mothers cannot afford.
|
||||
|
||||
## Technical architecture for reliability when families depend on you
|
||||
|
||||
The technical foundation must support families' mission-critical needs through offline-first architecture with seamless synchronization. Local databases serve as the single source of truth, ensuring the app works without internet connection - crucial during pediatrician visits in cellular dead zones or international travel. **Real-time synchronization** keeps all family members updated through WebSocket connections, with conflict resolution for simultaneous edits. Background sync handles updates efficiently without draining battery life.
|
||||
|
||||
Integration capabilities determine the platform's value within existing family ecosystems. Calendar synchronization with Google, Apple, and Outlook consolidates schedules. Health app connections track growth and development. School platform integration (ClassDojo, Seesaw, Remind) centralizes communication. Smart home compatibility enables voice control through Alexa and Google Assistant. **The app becomes the family's command center** rather than another isolated tool.
|
||||
|
||||
Scalability planning ensures the platform grows smoothly from thousands to millions of families. Microservices architecture separates different domains for independent scaling. Read replicas improve performance under load. Redis caching accelerates frequently accessed data. CDN integration speeds media delivery globally. The AI/ML infrastructure balances on-device processing for privacy-sensitive features with cloud computing for complex analytics. TensorFlow Lite and Core ML optimize mobile performance while maintaining sophisticated capabilities.
|
||||
|
||||
## Sustainable monetization that respects family budgets
|
||||
|
||||
The freemium model with thoughtfully designed tiers ensures accessibility while building sustainable revenue. **Free tier** includes core tracking for 1-2 children, basic milestone checking, and limited AI insights - enough to deliver value and build trust. Family tier at $9.99/month unlocks unlimited children, advanced AI predictions, full voice capabilities, and priority support. Family Plus at $14.99/month adds comprehensive integrations, advanced analytics, and exclusive expert content.
|
||||
|
||||
B2B2C partnerships expand reach while reducing acquisition costs. **Employer wellness programs** increasingly recognize supporting working parents improves productivity and retention. Insurance partnerships frame the app as preventive care, potentially covering subscriptions. Healthcare provider relationships enable pediatrician-recommended adoption. School district partnerships could provide subsidized access for all families. These channels validate the platform while reaching mothers who might not discover it independently.
|
||||
|
||||
Critical metrics guide sustainable growth. Customer Acquisition Cost (CAC) must remain below $30 for profitability. Lifetime Value (LTV) should exceed $200 through strong retention. Monthly Recurring Revenue (MRR) growth of 15-20% indicates healthy expansion. **Churn analysis by feature usage** identifies which capabilities drive retention. The goal isn't maximum revenue extraction but sustainable value exchange that supports continuous improvement while respecting family budgets.
|
||||
|
||||
## Product roadmap from MVP to comprehensive platform
|
||||
|
||||
**Phase 1 (Months 1-3)** launches core MVP features: basic tracking with voice input, AI chat assistant providing 24/7 guidance, pattern recognition for sleep and feeding, multi-user family access, and COPPA/GDPR compliant infrastructure. This foundation addresses immediate pain points while establishing technical architecture for expansion.
|
||||
|
||||
**Phase 2 (Months 4-6)** adds intelligence and community: advanced pattern predictions across all tracked metrics, moderated community forums with expert participation, photo milestone storage with automatic organization, comprehensive calendar integration, and initial school platform connections. These features transform the app from tracker to intelligent assistant.
|
||||
|
||||
**Phase 3 (Months 7-12)** delivers the full vision: predictive scheduling that anticipates family needs, mental health monitoring with intervention protocols, meal planning with grocery integration, financial tracking for family expenses, and telemedicine integration for virtual pediatric visits. Smart home integration enables voice control of core features.
|
||||
|
||||
**Future expansion (12+ months)** extends the platform's reach: web platform for desktop planning sessions, wearable integration for health tracking, professional tools for pediatricians and therapists, AI-powered child development assessments, and international localization for global families. The platform evolves into the definitive digital infrastructure for modern parenting.
|
||||
|
||||
## Conclusion: From overwhelming chaos to confident parenting
|
||||
|
||||
The research reveals an enormous, underserved market of mothers struggling with preventable organizational and emotional challenges. Current solutions address symptoms rather than root causes, forcing families to juggle multiple apps while still missing critical support. **An integrated AI-powered platform** that combines intelligent tracking, predictive scheduling, mental health support, and family coordination can transform the parenting experience from overwhelming to manageable.
|
||||
|
||||
Success requires more than technical excellence. The platform must earn trust through privacy-first design, respect mothers' chaotic reality through interruption-resistant UX, and deliver immediate value through AI that actually reduces mental load rather than adding complexity. By addressing the holistic needs of modern mothers - from midnight feeding sessions to career planning meetings - this comprehensive solution can become the indispensable digital partner that millions of families desperately need.
|
||||
|
||||
The opportunity extends beyond commercial success to genuine social impact. Reducing maternal mental load, improving mental health support access, and enabling more equitable household partnerships could reshape family dynamics globally. With the parenting app market growing 12-20% annually and mothers increasingly embracing AI assistance, the timing is ideal for a platform that finally delivers on technology's promise to make parenting not easier, but more confident, connected, and joyful.
|
||||
Reference in New Issue
Block a user