# Data Model: M3 Expressive Design System Adoption

**Date**: 2025-07-18 | **Branch**: `20260513-160000-m3-expressive-adoption`

## Overview

This feature is primarily a UI/styling upgrade with minimal data model impact. The only new persistent state is the swipe-action discoverability hint preference.

## New Entities

### SwipeHintPreference

**Location**: `core/datastore` (user preferences)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `hasCompletedSwipeAction` | `Boolean` | `false` | Permanently dismisses swipe hint after first successful swipe action |

**Storage**: DataStore `UserPreferences` proto or preferences file (existing infrastructure).

**State Transitions**:
```
false → true  (on first successful swipe-to-action completion)
```
One-way flag. Never resets to false (permanent dismissal).

---

### SwipeHintSessionState (transient)

**Location**: In-memory, ViewModel-scoped

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `hasShownHintThisSession` | `Boolean` | `false` | Prevents repeated hint animation within same process lifecycle |

**Lifecycle**: Resets on process death. Within a session, hint shows once per list screen visit until `hasCompletedSwipeAction` becomes `true`.

---

## Modified Entities

### AppTypography (Type.kt)

**Current State**: `val AppTypography = Typography()` — empty default

**Target State**: Full expressive typescale definition:

| Property | Value Source |
|----------|-------------|
| `displayLarge` | Standard M3 default (auto-emphasized by expressive theme) |
| `displayMedium` | Standard M3 default |
| `displaySmall` | Standard M3 default |
| `headlineLarge` | Standard M3 default |
| `headlineMedium` | Standard M3 default |
| `headlineSmall` | Standard M3 default |
| `titleLarge` | Standard M3 default |
| `titleMedium` | Standard M3 default |
| `titleSmall` | Standard M3 default |
| `bodyLarge` | `fontSize = 16.sp` minimum (design standards §5) |
| `bodyMedium` | `fontSize = 16.sp` minimum (design standards §5) |
| `bodySmall` | Standard M3 default |
| `labelLarge` | Standard M3 default |
| `labelMedium` | Standard M3 default |
| `labelSmall` | Standard M3 default |

**Note**: Emphasized variants (`displayLargeEmphasized`, `titleMediumEmphasized`, etc.) are auto-generated by `MaterialExpressiveTheme` based on the standard scale. No manual definition needed.

---

## Component State Models

### SwipeToRevealState

**Location**: `core/ui/component/SwipeToRevealBox.kt`

| Field | Type | Description |
|-------|------|-------------|
| `anchoredDraggableState` | `AnchoredDraggableState<SwipeAnchor>` | Manages drag position and anchoring |
| `currentAnchor` | `SwipeAnchor` | Current snapped position |

**SwipeAnchor Enum**:
```kotlin
enum class SwipeAnchor {
    Start,       // Resting position (0 offset)
    RevealEnd,   // Left-swipe reveals end actions
    RevealStart, // Right-swipe reveals start actions
}
```

---

## Relationships

```
UserPreferences (DataStore)
  └── hasCompletedSwipeAction: Boolean

NodeListScreen
  ├── uses SwipeToRevealBox (per item)
  │     └── owns AnchoredDraggableState
  └── reads hasCompletedSwipeAction (via ViewModel)

MessageListScreen
  ├── uses SwipeToRevealBox (per item)
  │     └── owns AnchoredDraggableState
  └── reads hasCompletedSwipeAction (via ViewModel)
```

---

## Validation Rules

| Rule | Constraint |
|------|-----------|
| `bodyLarge.fontSize` | `>= 16.sp` (design standards §5 minimum) |
| `bodyMedium.fontSize` | `>= 16.sp` (design standards §5 minimum) |
| Touch target minimum | `44.dp × 44.dp` on all interactive elements (design standards accessibility) |
| Swipe threshold | Action reveals at ≥ 56.dp horizontal drag (comfortable thumb distance) |
| Swipe velocity threshold | Fling detected at ≥ 400.dp/s (standard Material swipe velocity) |
