Skip to content

Memory Album: Client-Side Design

Vision: Transform user-curated memories into an emotional artifact system—like a family photo album that captures meaningful moments in the relationship with AICO.

Document Relationship: This document defines the client-side UI/UX for the Memory Album feature. See also: - feedback-overview.md - Backend architecture (storage schemas, dual storage pattern) - /docs/concepts/data/data-layer.md - Storage layer details

Scope: - ✅ UI/UX design (timeline, grid, story views) - ✅ User interactions (annotations, tags, favorites) - ✅ Frontend data models and state management - ✅ Visual design and animations - ❌ Backend storage schemas (see feedback-overview.md) - ❌ Database implementation (see feedback-overview.md)


1. Conceptual Framework

The Family Photo Album Metaphor

Traditional Photo Album: - Captures special moments - Organized chronologically or thematically - Revisited for nostalgia and connection - Curated by the person (not automatic) - Each photo tells a story

AICO Memory Album: - Captures meaningful conversation moments - Organized by time, topic, or emotional significance - Revisited to see relationship growth - Curated by user (explicit "Remember This") - Each memory tells part of the relationship story


2. Data Model (Client-Side)

Memory Entry Structure

// /frontend/lib/domain/entities/memory_entry.dart

class MemoryEntry {
  final String memoryId;           // Links to fact_id in backend
  final String conversationId;
  final String messageId;

  // Content
  final String content;            // The remembered text
  final MemoryType type;           // fact, insight, moment, milestone
  final String? aiContext;         // What AICO said that prompted this
  final String? userNote;          // Optional user annotation

  // Categorization
  final MemoryCategory category;   // personal, relationship, achievement, etc.
  final List<String> tags;         // User-defined tags
  final EmotionalTone? tone;       // happy, reflective, supportive, etc.

  // Temporal context
  final DateTime timestamp;
  final String conversationTitle;  // "Late night chat about career"
  final int conversationTurn;      // Which turn in the conversation

  // Visual metadata (for rich display)
  final String? snapshot;          // Conversation context snippet
  final Color? accentColor;        // Derived from emotional tone
  final String? iconEmoji;         // Visual marker

  // Relationship tracking
  final int daysSinceFirstChat;    // Relationship age at this moment
  final String relationshipPhase;  // "Getting to know you", "Deep trust", etc.

  // Engagement
  final int revisitCount;          // How many times user viewed this
  final DateTime? lastRevisited;
  final bool isFavorite;           // Star/pin feature
}

enum MemoryType {
  fact,        // "I'm allergic to shellfish"
  insight,     // "I realized I need to set boundaries"
  moment,      // "When AICO made me laugh"
  milestone,   // "First time I opened up about anxiety"
  wisdom,      // "AICO's advice that helped"
}

enum MemoryCategory {
  personal,      // About user
  relationship,  // About user's relationships
  achievement,   // Accomplishments
  challenge,     // Struggles/growth
  joy,          // Happy moments
  support,      // When AICO provided comfort
  discovery,    // Learning/realizations
}

enum EmotionalTone {
  joyful,
  reflective,
  vulnerable,
  proud,
  grateful,
  hopeful,
  peaceful,
}

3. UI/UX Design

3.1 Entry Point: "Remember This" Action

In-Conversation Flow:

User reads AICO's message
Long-press message bubble
Contextual menu appears:
  ✨ Remember This
  🔄 Regenerate
  📋 Copy
  💭 Explain
User taps "Remember This"
Haptic feedback + Purple glow animation
Quick annotation modal (optional):
  "Add a note about this memory?"
  [Optional text field]
  [Category picker: Personal, Relationship, Achievement...]
  [Save] [Skip]
Confirmation: "Added to your Memory Album ✨"
Subtle prompt: "View in Album" (dismissible)

3.2 Memory Album Screen

Navigation: - Accessible from main menu: "Memory Album" or "Our Moments" - Badge shows total memory count - Subtle animation when new memories added

Layout Options:

Option A: Timeline View (Default)

┌─────────────────────────────────────┐
│  Memory Album                    ⚙️  │
│  247 moments • 89 days together      │
├─────────────────────────────────────┤
│                                      │
│  🎯 This Week                        │
│  ┌──────────────────────────────┐  │
│  │ ✨ "I realized I need..."    │  │
│  │ 2 days ago • Reflective       │  │
│  │ Late night chat about work    │  │
│  └──────────────────────────────┘  │
│                                      │
│  📅 Last Week                        │
│  ┌──────────────────────────────┐  │
│  │ 💡 "AICO's advice about..."   │  │
│  │ 5 days ago • Grateful         │  │
│  └──────────────────────────────┘  │
│  ┌──────────────────────────────┐  │
│  │ 🎉 "I got the promotion!"     │  │
│  │ 6 days ago • Proud            │  │
│  └──────────────────────────────┘  │
│                                      │
│  🗓️ Earlier This Month              │
│  ...                                 │
└─────────────────────────────────────┘

Option B: Grid View (Photo Album Style)

┌─────────────────────────────────────┐
│  Memory Album          [≡] [⊞] [⚙️] │
├─────────────────────────────────────┤
│  ┌────────┐ ┌────────┐ ┌────────┐ │
│  │   ✨   │ │   💡   │ │   🎉   │ │
│  │ I rea..│ │ AICO's │ │ I got..│ │
│  │ 2d ago │ │ 5d ago │ │ 6d ago │ │
│  └────────┘ └────────┘ └────────┘ │
│  ┌────────┐ ┌────────┐ ┌────────┐ │
│  │   🌟   │ │   💭   │ │   ❤️   │ │
│  │ First..│ │ Deep...│ │ When...│ │
│  │ 12d ago│ │ 18d ago│ │ 23d ago│ │
│  └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────┘

Option C: Journey Map View (Chronological Exploration)

┌─────────────────────────────────────┐
│  Our Journey Together           🔍±  │
│  89 days • 247 moments               │
├─────────────────────────────────────┤
│                                      │
│  Oct 2024     Dec 2024     Feb 2025 │
│     ●━━━━━━━━━━⬤━━━━━━━━━━●       │
│   First    Breakthrough   Current   │
│   Chat        Phase                  │
│   (12)        (85)        (150)      │
│                                      │
│  Chapters:                           │
│  🌱 Getting to Know You (Oct-Nov)   │
│  💡 Opening Up (Dec-Jan)            │
│  🌟 Deep Trust (Feb-Present)        │
│                                      │
│  [Pinch to zoom • Tap nodes]        │
└─────────────────────────────────────┘

Features:
- Zoomable timeline (year → month → week)
- Node size reflects importance (favorites, revisits)
- Auto-detected relationship chapters
- Milestone markers (🎊 100th memory, etc.)
- Density heatmap shows active periods
- Spatial exploration vs. linear reading

3.3 Memory Detail View

Tap on any memory card:

┌─────────────────────────────────────┐
│  ← Memory Album              ⋮ ⭐   │
├─────────────────────────────────────┤
│                                      │
│  ✨ Personal • Reflective            │
│  2 days ago • 11:47 PM               │
│  87 days into our relationship       │
│                                      │
│  ┌──────────────────────────────┐  │
│  │ "I realized I need to set    │  │
│  │ boundaries at work. I can't  │  │
│  │ keep saying yes to everyone."│  │
│  └──────────────────────────────┘  │
│                                      │
│  💭 Your Note:                       │
│  "This was a breakthrough moment"   │
│  [Edit note]                         │
│                                      │
│  📖 Conversation Context:            │
│  Late night chat about work stress  │
│  Turn 12 of 18                       │
│  [View full conversation →]          │
│                                      │
│  🏷️ Tags: #work #boundaries #growth │
│  [Add tag]                           │
│                                      │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  │
│                                      │
│  Related Memories (2):               │
│  • "Feeling overwhelmed" (1 week ago)│
│  • "Learning to say no" (3 days ago) │
│                                      │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  │
│                                      │
│  [Share Memory] [Delete]             │
│                                      │
└─────────────────────────────────────┘

3.4 Filtering & Organization

Filter Options: - By Time: Today, This Week, This Month, All Time - By Category: Personal, Relationship, Achievement, Support, etc. - By Emotion: Joyful, Reflective, Vulnerable, Proud, etc. - By Type: Facts, Insights, Moments, Milestones, Wisdom - Favorites Only: ⭐ Starred memories

Search: - Full-text search across memory content - Search by tags - Search by date range

Sort Options: - Newest first (default) - Oldest first (chronological story) - Most revisited (favorites) - By emotional tone


4. Special Features

4.1 Memory Milestones

Auto-generated milestone cards:

┌──────────────────────────────────┐
│  🎊 Milestone Reached!           │
│                                   │
│  100 Memories Together            │
│  You've been curating our story  │
│  for 89 days. Here's to many     │
│  more meaningful moments! ✨      │
│                                   │
│  [View your journey →]            │
└──────────────────────────────────┘

Milestone triggers: - First memory - 10, 50, 100, 250, 500 memories - 30, 90, 180, 365 days together - First memory in each category - Revisiting old memories

4.2 Memory Connections

Visual relationship graph: - Show how memories relate to each other - "You remembered this after talking about..." - Thematic clusters (work, relationships, personal growth) - Temporal patterns (what you remember at night vs. morning)

4.3 Reflection Prompts

Weekly/Monthly:

┌──────────────────────────────────┐
│  💭 This Week's Reflection        │
│                                   │
│  You remembered 5 moments this   │
│  week, mostly about work and     │
│  boundaries. How are you feeling │
│  about this growth?               │
│                                   │
│  [Journal about it]               │
│  [Remind me later]                │
└──────────────────────────────────┘

4.4 Memory Export

Share your story: - Export as PDF timeline - Create shareable memory card (image) - Export to journal app - Print-friendly format


5. Technical Architecture

5.1 Backend Integration

Storage Architecture: See feedback-overview.md for: - Database schemas (feedback_events, facts_metadata) - Dual storage pattern - Query patterns

5.2 Local Storage (Flutter)

// /frontend/lib/data/repositories/memory_album_repository.dart

class MemoryAlbumRepository {
  final LocalDatabase _localDb;
  final ApiClient _apiClient;

  // Local cache for offline access
  Future<List<MemoryEntry>> getMemories({
    MemoryCategory? category,
    DateTime? startDate,
    DateTime? endDate,
    bool favoritesOnly = false,
  }) async {
    // Query local SQLite database
    // Fallback to API if not cached
  }

  // Sync with backend
  Future<void> syncMemories() async {
    // Fetch new memories from backend
    // Update local cache
    // Handle conflicts
  }

  // Add new memory
  Future<MemoryEntry> createMemory({
    required String messageId,
    required String content,
    String? userNote,
    MemoryCategory? category,
    List<String>? tags,
  }) async {
    // 1. Store locally first (optimistic UI)
    // 2. Call backend API
    // 3. Update with backend response (fact_id, etc.)
  }

  // Update memory metadata
  Future<void> updateMemory(String memoryId, {
    String? userNote,
    List<String>? tags,
    bool? isFavorite,
  }) async {
    // Update local + sync to backend
  }

  // Track revisits
  Future<void> recordRevisit(String memoryId) async {
    // Increment revisit count
    // Update last_revisited timestamp
    // Send feedback event to backend
  }
}

5.3 State Management (Riverpod/Bloc)

// /frontend/lib/presentation/providers/memory_album_provider.dart

@riverpod
class MemoryAlbumNotifier extends _$MemoryAlbumNotifier {
  @override
  Future<MemoryAlbumState> build() async {
    return MemoryAlbumState(
      memories: [],
      isLoading: true,
      filters: MemoryFilters(),
    );
  }

  Future<void> loadMemories() async {
    state = AsyncValue.loading();
    final memories = await ref.read(memoryRepositoryProvider).getMemories();
    state = AsyncValue.data(state.value!.copyWith(
      memories: memories,
      isLoading: false,
    ));
  }

  Future<void> addMemory(MemoryEntry memory) async {
    // Optimistic update
    final currentMemories = state.value!.memories;
    state = AsyncValue.data(state.value!.copyWith(
      memories: [memory, ...currentMemories],
    ));

    // Persist to backend
    try {
      final savedMemory = await ref.read(memoryRepositoryProvider).createMemory(
        messageId: memory.messageId,
        content: memory.content,
        userNote: memory.userNote,
        category: memory.category,
        tags: memory.tags,
      );

      // Update with backend data
      final updatedMemories = currentMemories.map((m) => 
        m.memoryId == memory.memoryId ? savedMemory : m
      ).toList();

      state = AsyncValue.data(state.value!.copyWith(
        memories: updatedMemories,
      ));
    } catch (e) {
      // Rollback on error
      state = AsyncValue.data(state.value!.copyWith(
        memories: currentMemories,
      ));
      // Show error to user
    }
  }

  void applyFilters(MemoryFilters filters) {
    state = AsyncValue.data(state.value!.copyWith(filters: filters));
  }
}

5.4 Backend API Endpoints

Note: Backend implementation details in feedback-overview.md

# /backend/api/memory_album/router.py

@router.get("/memory-album")
async def get_memory_album(
    user_uuid: str = Depends(get_current_user),
    category: Optional[MemoryCategory] = None,
    start_date: Optional[datetime] = None,
    end_date: Optional[datetime] = None,
    favorites_only: bool = False,
    limit: int = 50,
    offset: int = 0,
):
    """
    Get user's memory album entries.
    Combines data from:
    - facts_metadata (the actual memories)
    - feedback_events (user actions, revisit counts)
    """

    # Query facts with extraction_method='user_curated'
    memories = await db.execute("""
        SELECT 
            f.fact_id,
            f.content,
            f.category,
            f.source_conversation_id,
            f.source_message_id,
            f.created_at,
            fe.payload as feedback_payload
        FROM facts_metadata f
        LEFT JOIN feedback_events fe 
            ON fe.payload->>'$.fact_id' = f.fact_id
            AND fe.event_category = 'remember'
        WHERE f.user_id = ?
            AND f.extraction_method = 'user_curated'
            AND (? IS NULL OR f.category = ?)
            AND (? IS NULL OR f.created_at >= ?)
            AND (? IS NULL OR f.created_at <= ?)
        ORDER BY f.created_at DESC
        LIMIT ? OFFSET ?
    """, (user_uuid, category, category, start_date, start_date, 
          end_date, end_date, limit, offset))

    # Enrich with conversation context
    enriched_memories = []
    for memory in memories:
        # Get conversation title/context
        conv_context = await get_conversation_context(
            memory['source_conversation_id']
        )

        # Parse feedback payload for user notes, tags, etc.
        feedback_data = json.loads(memory['feedback_payload'] or '{}')

        enriched_memories.append({
            'memory_id': memory['fact_id'],
            'content': memory['content'],
            'category': memory['category'],
            'timestamp': memory['created_at'],
            'conversation_context': conv_context,
            'user_note': feedback_data.get('user_note'),
            'tags': feedback_data.get('tags', []),
            'revisit_count': feedback_data.get('revisit_count', 0),
            'is_favorite': feedback_data.get('is_favorite', False),
        })

    return {
        'memories': enriched_memories,
        'total_count': len(enriched_memories),
        'has_more': len(enriched_memories) == limit,
    }


@router.post("/memory-album/{memory_id}/revisit")
async def record_memory_revisit(
    memory_id: str,
    user_uuid: str = Depends(get_current_user),
):
    """Record that user revisited a memory (for analytics)"""

    # Record feedback event
    await record_feedback_event(
        user_uuid=user_uuid,
        conversation_id="memory_album_view",  # Special conversation_id
        event_type=FeedbackEventType.ACTION,
        event_category="memory_revisit",
        payload={
            "memory_id": memory_id,
            "revisit_timestamp": int(time.time()),
        }
    )

    return {"success": True}


@router.patch("/memory-album/{memory_id}")
async def update_memory_metadata(
    memory_id: str,
    update: MemoryUpdateRequest,
    user_uuid: str = Depends(get_current_user),
):
    """Update memory metadata (note, tags, favorite status)"""

    # Update feedback event payload
    # (Store metadata in feedback_events, not facts_metadata)

    return {"success": True, "memory": updated_memory}

6. Design Principles

6.1 Emotional Design

Visual Language: - Warm, nostalgic color palette (sepia tones, soft purples) - Gentle animations (fade-ins, subtle parallax) - Handwritten-style fonts for user notes - Polaroid/scrapbook aesthetic for memory cards

Micro-interactions: - Haptic feedback when adding memories - Satisfying "bookmark" animation - Gentle pulse on milestone achievements - Smooth transitions between views

6.2 Privacy & Control

User Ownership: - Clear "This is YOUR album" messaging - Easy export/backup options - Granular deletion controls - No AI can access without permission

Transparency: - Show what AICO remembers vs. what user curated - Clear distinction between automatic facts and user memories - Explain how memories improve conversations

6.3 Progressive Disclosure

First-time Experience: 1. User adds first memory → Celebration modal 2. After 5 memories → Introduce categories 3. After 20 memories → Introduce filtering 4. After 50 memories → Introduce memory connections

Avoid Overwhelm: - Start simple (just timeline) - Gradually reveal advanced features - Optional complexity (power users can go deep)


7. Implementation Phases

Phase 1: Core Functionality (Weeks 1-2)

  • ✅ "Remember This" action in chat
  • ✅ Basic timeline view
  • ✅ Memory detail view
  • ✅ Local storage + sync

Phase 2: Rich Metadata (Weeks 3-4)

  • Categories and tags
  • User notes
  • Favorites/starring
  • Search and filtering

Phase 3: Emotional Design (Weeks 5-6)

  • Visual polish (animations, colors)
  • Memory connections
  • Milestones
  • Reflection prompts

Phase 4: Advanced Features (Weeks 7-8)

  • Grid and story views
  • Memory export
  • Relationship graph
  • Analytics dashboard

8. Success Metrics

Engagement: - % of users who add at least 1 memory - Average memories per user - Revisit frequency - Time spent in Memory Album

Emotional Connection: - User feedback on feature - Milestone celebration engagement - Memory sharing rate - Retention correlation (do users with more memories stay longer?)

Quality: - Average note length (indicates thoughtfulness) - Tag usage (indicates organization) - Favorite ratio (indicates curation)


9. Future Enhancements

9.1 Collaborative Memories

  • Share specific memories with family/friends
  • "Remember when we talked about..." prompts
  • Collaborative tagging

9.2 AI-Assisted Curation

  • AICO suggests moments worth remembering
  • "You might want to remember this" prompts
  • Auto-categorization suggestions

9.3 Physical Artifacts

  • Print memory album as book
  • Generate memory cards for special occasions
  • Create shareable memory videos

9.4 Temporal Intelligence

  • "One year ago today" reminders
  • Growth tracking over time
  • Pattern recognition ("You often remember work insights on Sundays")

Conclusion

The Memory Album transforms AICO from a conversational AI into a relationship companion. By treating user-curated memories as emotional artifacts—not just data points—we create a space for reflection, growth, and genuine connection.

This is not just a feature. It's the heart of the AICO experience.