Files
dewemoji/dewemoji-ux-flow-brief.md
2026-02-12 00:52:40 +07:00

873 lines
22 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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%).