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
586 lines
11 KiB
Markdown
586 lines
11 KiB
Markdown
# 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');
|
|
}
|
|
``` |