# Dewemoji User Flow & UX Brief

**Version:** 1.0  
**Date:** February 8, 2026  
**Purpose:** Define seamless user experience across visitor → logged → paid states  
**Related Doc:** dewemoji-direction-2026.md  

---

## Executive Summary

Dewemoji implements a **hybrid quick-add flow** where Personal users can add keywords instantly from emoji detail pages (80% of use cases) while maintaining full CRUD power in the dashboard (20% management). This creates a frictionless progression: discovery → personalization → habit, without disrupting the free user experience.

**Core UX Principle:** *"Add keywords where you discover emojis, manage them where you organize."*

---

## 1. User State Definitions

### 1.1 Visitor (Non-Logged)
**Who:** Anyone landing on dewemoji.com or using Chrome extension (no account)  
**Intent:** Quick emoji search and usage  
**Experience:** Zero friction, no login walls  

### 1.2 Free User (Logged, No Subscription)
**Who:** Registered account, free tier  
**Intent:** Exploring Personal features, considering upgrade  
**Experience:** Full free features + gentle upgrade hints  

### 1.3 Personal User (Logged, Paid)
**Who:** Active Personal subscription ($4.99/mo, $49/yr, or $99 lifetime)  
**Intent:** Building and syncing personal keyword library  
**Experience:** Full personalization power across all touchpoints  

---

## 2. Primary User Flows

### 2.1 Discovery Flow (All Users)

```
User lands on dewemoji.com
    ↓
Search bar: "bekicot"
    ↓
Results page: 🐌 snail (public keywords: "snail, escargot")
    ↓
Click emoji → Detail page
    ↓
[State-dependent experience - see Section 3]
```

**Key Insight:** All users start here. Free discovery hooks them; Personal lets them own it.

---

### 2.2 Personalization Flow (Personal Users)

#### Primary: Quick Add from Detail Page (80% Usage)

```
Personal user searches "snail"
    ↓
Detail page shows:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ Your Keywords: (none yet)          │
│ [+ Add Your Keyword]               │
└─────────────────────────────────────┘
    ↓
User clicks [+ Add Your Keyword]
    ↓
Inline modal appears:
┌─────────────────────────────────────┐
│ What do you call this emoji?       │
│ ┌─────────────────────────────────┐│
│ │ bekicot, siput                  ││
│ └─────────────────────────────────┘│
│ Language: [Indonesian ▾]           │
│ [Cancel]  [Save Keyword]           │
└─────────────────────────────────────┘
    ↓
Saves instantly → Toast: "Added 'bekicot' to your library ✓"
    ↓
Detail page now shows:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ Your Keywords:                      │
│ • bekicot (ID) [edit] [×]          │
│ • siput (ID) [edit] [×]            │
│ [+ Add Another]                    │
└─────────────────────────────────────┘
    ↓
Next search: "bekicot" → 🐌 appears in results!
```

**Why This Flow:**
- **Contextual:** User is *already looking at* the emoji they want to name
- **Fast:** 2 clicks (add button → save), ~5 seconds total
- **Immediate gratification:** See change instantly in searches
- **Low friction:** No navigation away from discovery flow

---

#### Secondary: Dashboard Management (20% Usage)

**When Used:**
- Bulk editing/organizing keywords
- Reviewing all keywords at once
- Exporting/importing keyword libraries
- Fixing typos across multiple entries

```
User navigates to Dashboard → My Keywords tab
    ↓
Table view:
┌───────────────────────────────────────────────────────────┐
│ Emoji | Your Keywords      | Lang | Actions              │
├───────────────────────────────────────────────────────────┤
│ 🐌    | bekicot, siput     | ID   | [Edit] [Delete]      │
│ 😊    | senyum, happy      | ID   | [Edit] [Delete]      │
│ 🔥    | api, fire, lit     | ID   | [Edit] [Delete]      │
└───────────────────────────────────────────────────────────┘
[+ Add Keyword] [Import JSON] [Export JSON] [Search/Filter]
    ↓
User clicks [+ Add Keyword]
    ↓
Modal: Search emoji picker → Select 🎉 → Add keywords
    ↓
Saves to table → Auto-sync to extension
```

**Why Dashboard Exists:**
- Power users want bulk operations
- Easy to review/audit entire library
- Import/export for backup
- Edit mistakes without finding emoji again

---

### 2.3 Upgrade Flow (Free → Personal)

#### Trigger Points

**1. On Detail Page (Soft Prompt)**
```
Free user on emoji detail page sees:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ 💎 Want to add your own keywords?  │
│    like 'bekicot' or 'siput'?      │
│    [Upgrade to Personal →]         │
└─────────────────────────────────────┘
```

**2. On Search Miss (Strong Prompt)**
```
User searches "bekicot" → No results
    ↓
Results page shows:
┌─────────────────────────────────────┐
│ No results for "bekicot"           │
│                                     │
│ 💡 With Personal, you can create   │
│    "bekicot → 🐌" and sync it      │
│    everywhere.                      │
│    [Try Personal Free for 7 Days]  │
└─────────────────────────────────────┘
```

**3. From Extension (Contextual)**
```
Extension user searches "bekicot" → Not found
    ↓
Extension shows inline banner:
"Add 'bekicot' to your library with Personal"
[Upgrade] button → Opens dewemoji.com/upgrade
```

**4. From Dashboard (Clear Path)**
```
Free user clicks "My Keywords" tab
    ↓
Shows empty state:
┌─────────────────────────────────────┐
│ 📚 Your Personal Keyword Library   │
│                                     │
│ You have 0 keywords.               │
│                                     │
│ Upgrade to Personal to:            │
│ ✓ Add unlimited keywords           │
│ ✓ Search in your language          │
│ ✓ Sync across all devices          │
│                                     │
│ [Start 7-Day Free Trial]           │
└─────────────────────────────────────┘
```

---

## 3. State-Dependent UI Elements

### 3.1 Emoji Detail Page

#### Visitor (Non-Logged)
```html
<!-- Public info only -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  <section class="public-keywords">
    <h3>Keywords</h3>
    <ul>
      <li>snail</li>
      <li>escargot</li>
      <li>slow</li>
    </ul>
  </section>
  
  <div class="cta-banner">
    <p>💡 Want to search in your language?</p>
    <button>Sign Up Free</button>
  </div>
</div>
```

#### Free User (Logged)
```html
<!-- Public info + muted personal section -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  
  <section class="public-keywords">
    <h3>Keywords</h3>
    <ul><li>snail</li><li>escargot</li></ul>
  </section>
  
  <section class="user-keywords muted">
    <h3>Your Keywords</h3>
    <div class="upgrade-overlay">
      <p>💎 Add personal keywords like 'bekicot'</p>
      <button class="upgrade-btn">Upgrade to Personal</button>
    </div>
  </section>
</div>
```

#### Personal User (Logged + Paid)
```html
<!-- Full personalization active -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  
  <section class="public-keywords">
    <h3>Public Keywords</h3>
    <ul><li>snail</li><li>escargot</li><li>slow</li></ul>
  </section>
  
  <section class="user-keywords active">
    <h3>Your Keywords</h3>
    <ul class="keyword-list">
      <li>
        <span class="keyword">bekicot</span>
        <span class="lang-tag">ID</span>
        <button class="edit-btn">edit</button>
        <button class="delete-btn">×</button>
      </li>
      <li>
        <span class="keyword">siput</span>
        <span class="lang-tag">ID</span>
        <button class="edit-btn">edit</button>
        <button class="delete-btn">×</button>
      </li>
    </ul>
    <button class="add-keyword-btn">+ Add Keyword</button>
  </section>
</div>

<!-- Add Keyword Modal (hidden until clicked) -->
<dialog id="add-keyword-modal">
  <h3>What do you call this emoji?</h3>
  <input type="text" placeholder="Enter keywords (comma-separated)" />
  <select name="language">
    <option value="en">English</option>
    <option value="id">Indonesian</option>
    <option value="ko">Korean</option>
    <option value="ja">Japanese</option>
  </select>
  <div class="modal-actions">
    <button class="cancel">Cancel</button>
    <button class="save primary">Save Keyword</button>
  </div>
</dialog>
```

---

### 3.2 Search Results Page

#### All Users (Public Results)
```html
<div class="search-results">
  <div class="emoji-card">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">snail</span>
  </div>
</div>
```

#### Personal User (Blended Results)
```html
<div class="search-results">
  <!-- Private keyword match (appears first) -->
  <div class="emoji-card user-match">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">
      bekicot
      <span class="badge personal">Your keyword</span>
    </span>
    <button class="quick-edit">Edit</button>
  </div>
  
  <!-- Public keyword matches (below) -->
  <div class="emoji-card">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">snail</span>
  </div>
</div>
```

---

### 3.3 Dashboard (Personal Users Only)

```html
<div class="dashboard">
  <nav class="tabs">
    <button class="active">My Keywords</button>
    <button>API Keys</button>
    <button>Billing</button>
  </nav>
  
  <!-- My Keywords Tab -->
  <div class="tab-content" id="keywords">
    <div class="toolbar">
      <button class="primary">+ Add Keyword</button>
      <button>Import JSON</button>
      <button>Export JSON</button>
      <input type="search" placeholder="Search your keywords..." />
    </div>
    
    <table class="keyword-table">
      <thead>
        <tr>
          <th>Emoji</th>
          <th>Your Keywords</th>
          <th>Language</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>🐌</td>
          <td>bekicot, siput</td>
          <td><span class="lang-tag">ID</span></td>
          <td>
            <button class="edit">Edit</button>
            <button class="delete">Delete</button>
          </td>
        </tr>
        <!-- More rows... -->
      </tbody>
    </table>
  </div>
</div>
```

---

## 4. API Endpoints for UX Flows

### 4.1 Detail Page Quick Add

**Fetch user's keywords for specific emoji:**
```
GET /v1/emoji/:slug?include_user_keywords=true
Authorization: Bearer dew_abc123...

Response:
{
  "emoji": {...},
  "public_keywords": ["snail", "escargot"],
  "user_keywords": [
    {"id": "uk_1", "keyword": "bekicot", "lang": "id"},
    {"id": "uk_2", "keyword": "siput", "lang": "id"}
  ]
}
```

**Add keyword from detail page:**
```
POST /v1/keywords/quick
Authorization: Bearer dew_abc123...

Body:
{
  "emoji_slug": "snail",
  "keywords": ["bekicot", "siput"],
  "lang": "id"
}

Response:
{
  "success": true,
  "added": ["bekicot", "siput"],
  "emoji_slug": "snail"
}
```

**Edit single keyword:**
```
PATCH /v1/keywords/:id
Authorization: Bearer dew_abc123...

Body:
{
  "keyword": "bekicot kecil"
}
```

**Delete keyword:**
```
DELETE /v1/keywords/:id
Authorization: Bearer dew_abc123...
```

---

### 4.2 Dashboard Bulk Operations

**List all user keywords:**
```
GET /v1/keywords?page=1&limit=50
Authorization: Bearer dew_abc123...

Response:
{
  "keywords": [
    {
      "id": "uk_1",
      "emoji_slug": "snail",
      "emoji": "🐌",
      "keyword": "bekicot",
      "lang": "id",
      "created_at": "2026-02-08T10:30:00Z"
    }
    // ... more
  ],
  "total": 47,
  "page": 1
}
```

**Bulk import:**
```
POST /v1/keywords/import
Authorization: Bearer dew_abc123...

Body:
{
  "keywords": [
    {"emoji_slug": "snail", "keywords": ["bekicot"], "lang": "id"},
    {"emoji_slug": "fire", "keywords": ["api"], "lang": "id"}
  ]
}

Response:
{
  "imported": 2,
  "skipped": 0,
  "errors": []
}
```

**Export:**
```
GET /v1/keywords/export?format=json
Authorization: Bearer dew_abc123...

Response: (Download JSON file)
```

---

## 5. Frontend Implementation Specs

### 5.1 Emoji Detail Page Changes

**File:** `/pages/emoji/[slug].js` (or equivalent)

**Required Elements:**

1. **User keywords section** (Personal only)
   - Fetch on page load: `GET /v1/emoji/:slug?include_user_keywords=true`
   - Show list of user's keywords with edit/delete buttons
   - Show "Add Keyword" button

2. **Add keyword modal**
   - Input: comma-separated keywords
   - Dropdown: language selector (EN, ID, KO, JA, etc.)
   - Save button → POST `/v1/keywords/quick`
   - Success → update UI without page reload

3. **Inline edit**
   - Click "edit" → input becomes editable
   - Save → PATCH `/v1/keywords/:id`
   - Cancel → revert

4. **Inline delete**
   - Click "×" → confirm modal
   - Yes → DELETE `/v1/keywords/:id` → remove from UI

**State Management:**
```javascript
const [userKeywords, setUserKeywords] = useState([]);
const [isPersonal, setIsPersonal] = useState(false);

// On mount
useEffect(() => {
  if (user?.tier === 'personal') {
    fetchUserKeywords(emojiSlug);
  }
}, [emojiSlug, user]);

// Add keyword
const handleAddKeyword = async (keywords, lang) => {
  const result = await api.post('/keywords/quick', {
    emoji_slug: emojiSlug,
    keywords: keywords.split(',').map(k => k.trim()),
    lang
  });
  
  if (result.success) {
    fetchUserKeywords(emojiSlug); // Refresh list
    toast.success('Keywords added!');
  }
};
```

---

### 5.2 Dashboard Implementation

**File:** `/pages/dashboard.js`

**Tabs:**
1. My Keywords (default)
2. API Keys
3. Billing

**My Keywords Tab Components:**

```javascript
// Main table component
<KeywordTable 
  keywords={keywords}
  onEdit={handleEdit}
  onDelete={handleDelete}
  onSearch={handleSearch}
/>

// Toolbar actions
<Toolbar>
  <AddKeywordButton onClick={openModal} />
  <ImportButton />
  <ExportButton />
  <SearchInput onChange={handleSearch} />
</Toolbar>

// Add keyword modal (with emoji picker)
<AddKeywordModal
  onSave={handleAddKeyword}
  onCancel={closeModal}
/>
```

**Features:**
- Pagination (50 per page)
- Search/filter by keyword or emoji
- Bulk select + delete
- Sort by: date added, emoji name, language

---

### 5.3 Upgrade Flow Pages

**File:** `/pages/upgrade.js` or `/pages/pricing.js`

**Components:**

1. **Feature comparison table**
   ```html
   <table class="pricing-comparison">
     <tr>
       <th>Feature</th>
       <th>Free</th>
       <th>Personal</th>
     </tr>
     <tr>
       <td>Public emoji search</td>
       <td>✅ Unlimited</td>
       <td>✅ Unlimited</td>
     </tr>
     <tr>
       <td>Private keywords</td>
       <td>❌</td>
       <td>✅ Unlimited</td>
     </tr>
     <!-- ... -->
   </table>
   ```

2. **Pricing cards**
   ```html
   <div class="pricing-cards">
     <div class="card">
       <h3>Monthly</h3>
       <p class="price">$4.99/mo</p>
       <button>Subscribe</button>
     </div>
     <div class="card recommended">
       <span class="badge">Best Value</span>
       <h3>Annual</h3>
       <p class="price">$49/year</p>
       <p class="savings">Save 17%</p>
       <button>Subscribe</button>
     </div>
     <div class="card">
       <h3>Lifetime</h3>
       <p class="price">$99 once</p>
       <button>Buy Now</button>
     </div>
   </div>
   ```

3. **Stripe checkout integration**
   ```javascript
   const handleCheckout = async (plan) => {
     const session = await api.post('/stripe/checkout', {
       plan, // 'monthly' | 'annual' | 'lifetime'
       success_url: `${baseUrl}/dashboard?upgraded=true`,
       cancel_url: `${baseUrl}/upgrade`
     });
     
     window.location.href = session.url;
   };
   ```

---

## 6. UX Copy & Messaging

### 6.1 Upgrade Prompts

**Soft (Detail Page):**
> 💡 Want to search in your language? Add personal keywords like 'bekicot' for 🐌  
> [Upgrade to Personal →]

**Strong (Search Miss):**
> No results for "bekicot"  
>   
> 💎 **Create your own keywords with Personal**  
> Add "bekicot → 🐌" and sync it across all devices  
> [Try Free for 7 Days]

**Empty State (Dashboard):**
> 📚 **Your Personal Keyword Library**  
>   
> You have 0 keywords.  
>   
> Upgrade to Personal to:  
> ✓ Add unlimited keywords  
> ✓ Search in your language  
> ✓ Sync across all devices  
>   
> [Start 7-Day Free Trial]

---

### 6.2 Success Messages

**After adding keyword:**
> ✓ Added "bekicot" to your library

**After editing:**
> ✓ Keyword updated

**After deleting:**
> ✓ Keyword removed

**After upgrade:**
> 🎉 Welcome to Personal! Start adding your keywords.

---

### 6.3 Error Messages

**Duplicate keyword:**
> ⚠️ You already have "bekicot" for this emoji

**Network error:**
> ❌ Couldn't save. Check your connection and try again.

**Unauthorized:**
> 🔒 Please log in to add personal keywords

---

## 7. Mobile Considerations

### 7.1 Detail Page on Mobile

- Add keyword button: **sticky bottom bar** (always visible)
- Modal: **full-screen** on mobile (easier typing)
- Keyword list: **swipeable cards** (swipe left to delete)

### 7.2 Dashboard on Mobile

- Tabs: **horizontal scroll** or bottom nav
- Table: **card view** (stack columns vertically)
- Actions: **swipe gestures** (edit/delete)

---

## 8. Performance & Optimization

### 8.1 Caching Strategy

**Client-side:**
- Cache user keywords in localStorage/sessionStorage
- Only refetch when:
  - User adds/edits/deletes
  - Page reload after 5 minutes
  
**API-side:**
- ETag support (already implemented)
- Cache user keywords per user_id (Redis)
- Invalidate on mutation

### 8.2 Loading States

**Detail page:**
```
Loading user keywords...
└─ Skeleton: [▯▯▯▯] [▯▯▯] [▯▯▯▯▯]
```

**Dashboard:**
```
Loading your library...
└─ Table skeleton (5 rows)
```

---

## 9. Analytics & Tracking

### Key Events to Track

**Discovery:**
- `emoji_viewed` (slug, user_tier)
- `public_search` (query, has_results)
- `search_miss` (query) → upgrade opportunity

**Personalization:**
- `keyword_added` (method: 'quick_add' | 'dashboard')
- `keyword_edited`
- `keyword_deleted`
- `keywords_exported`

**Conversion:**
- `upgrade_prompt_shown` (location: 'detail' | 'search' | 'dashboard')
- `upgrade_clicked` (location)
- `trial_started`
- `subscription_created` (plan: 'monthly' | 'annual' | 'lifetime')

**Usage:**
- `private_keyword_searched` (query, has_results)
- `extension_synced` (keyword_count)

---

## 10. Testing Checklist

### 10.1 User State Tests

- [ ] Visitor can search and view emoji details (no login)
- [ ] Visitor sees upgrade CTA (non-intrusive)
- [ ] Free user sees muted keyword section
- [ ] Free user can't add keywords without upgrade
- [ ] Personal user sees active keyword section
- [ ] Personal user can add keywords from detail page
- [ ] Personal user can edit/delete keywords inline

### 10.2 Flow Tests

- [ ] Quick add: add keyword → appears in list immediately
- [ ] Quick add: new keyword searchable instantly
- [ ] Dashboard: bulk add works correctly
- [ ] Dashboard: export downloads valid JSON
- [ ] Dashboard: import restores keywords
- [ ] Search: private keywords appear first in results
- [ ] Search: private keywords have "Your keyword" badge

### 10.3 Edge Cases

- [ ] Add duplicate keyword → shows error
- [ ] Delete last keyword for emoji → removes emoji from search
- [ ] Offline: queue mutations, sync when online
- [ ] Rate limit: show friendly error
- [ ] API error: show retry option

---

## 11. Implementation Priority

### Phase 1: Detail Page Quick Add (Week 1)
1. Add user keywords section to detail page
2. Build add keyword modal
3. Implement POST /keywords/quick endpoint
4. Add inline edit/delete

### Phase 2: Search Blending (Week 1)
1. Update search to blend private + public
2. Add "Your keyword" badge to results
3. Show private matches first

### Phase 3: Dashboard (Week 2)
1. Build My Keywords tab with table
2. Add bulk actions (import/export)
3. Implement search/filter

### Phase 4: Upgrade Flow (Week 2)
1. Build upgrade prompts (detail, search miss, dashboard)
2. Create pricing page
3. Integrate Stripe checkout

---

## 12. Open Questions & Future Enhancements

1. **Keyword suggestions:** Should we suggest keywords based on emoji name/category?
2. **Keyboard shortcuts:** Quick add keyword with hotkey (Ctrl+K)?
3. **Recently added:** Show "Recently added keywords" widget on dashboard?
4. **Keyword collections:** Group keywords by category/theme?
5. **Sharing:** Allow users to share their keyword libraries with friends?

---

**End of UX Brief**

This document defines the seamless user experience for Dewemoji's core value proposition: instant, contextual personalization. Implementation should prioritize the detail page quick-add flow (80% of usage) while building dashboard for power users (20%).