DocHub
Contact management, media browser, AI personalities, reminder labels, settings overhaul

WANK 2.0 — WhatsApp Web Client Feature Expansion

Everything built on top of WANK 1 (the base system documented in PROJECT-BREAKDOWN.md). This covers all new features, database changes, backend services, frontend components, and deployment infrastructure added across multiple development sessions.


Table of Contents

  1. What Changed Since WANK 1
  2. Architecture Additions
  3. Database Migrations
  4. Backend — New Services
  5. Backend — New & Enhanced Controllers
  6. Backend — New Routes
  7. Frontend — New Pages
  8. Frontend — New Components
  9. Frontend — Enhanced Components
  10. Frontend — New Hooks & Contexts
  11. Frontend — Type Additions
  12. Frontend — API Layer Additions
  13. Tooltip System
  14. Background Backfill System
  15. Avatar System
  16. Production Deployment Infrastructure
  17. Complete File Reference
  18. Key Lessons & Gotchas

What Changed Since WANK 1

WANK 1 delivered a working WhatsApp Web replacement: session management, chat list, message sending/receiving, media archival, QR login, and a dark-themed UI. WANK 2 adds everything that makes it useful:

Category What Was Added
AI Auto-Reply Per-contact AI personalities with configurable providers (Mistral, OpenAI, Groq), delay modes, pause/resume, conversation context, activity logging
Contact Management Editable contact fields (name, company, email, notes, tags, social media), VCF/CSV import/export with fuzzy phone matching
Background Backfill Idle-time system that auto-populates phone numbers, contact details, message history, media, thumbnails, and avatars for top 25 recent chats
Avatar System Custom avatar selection from contact’s media photos or WhatsApp profile pic, fetched via Puppeteer window.Store.ProfilePic API
Message Actions Reply, react, star, pin, forward, copy, download media, delete (with for-everyone option)
Chat Pinning Pin/unpin chats with timestamp ordering
Phone Mismatch Detection Warning when a different phone number connects to an existing session
Media Storage Controls Toggle original/thumbnail retention for outgoing media
Tooltip System App-wide hover tooltips on every interactive element, toggleable from TopBar
Multi-Slice Deployment 8 isolated WhatsApp instances on a single DigitalOcean droplet, managed by one script

By the numbers:

Metric WANK 1 WANK 2 Growth
Backend services 2 6 +4 new
Controllers 4 8 +4 new, 4 enhanced
Route files 4 8 +4 new
Frontend components 12 22 +10 new, 8 enhanced
Frontend pages 4 6 +2 new
Types 10 22 +12 new
API methods 14 45+ +31 new
Database tables 3 8 +5 new
Database columns ~30 80+ +50 new
Total LOC ~5,000 ~11,500 +130%

Architecture Additions

WANK 1’s architecture remains intact. WANK 2 adds these layers:

Phone (linked device)
    ↕
WhatsApp Servers
    ↕
Headless Chromium (Puppeteer)
    ↕ whatsapp-web.js
    ↕ window.Store.ProfilePic ← NEW: Direct WA internal API for avatars
Express Backend (port 3101)
    ↕ PersonalityService   ← NEW: AI personality assignment
    ↕ AIService            ← NEW: LLM completion (Mistral/OpenAI/Groq)
    ↕ BackfillService      ← NEW: Background contact enrichment
    ↕ ContactImportService ← NEW: VCF/CSV import with fuzzy matching
    ↕ REST API + Socket.io
React Frontend (port 3100)
    ↕ useIdleBackfill      ← NEW: Idle detection + polling
    ↕ TooltipContext        ← NEW: App-wide hover tips
    ↕ Vite dev proxy → backend
Browser
    ↕
Nginx (production)          ← NEW: Reverse proxy for 8 slices
    ↕ wa1-wa8.ipnoelp.com

Key new design decisions:

  • AI auto-reply uses OpenAI-compatible endpoint abstraction (works with any provider)
  • Backfill is frontend-driven: idle detection in browser, one-step-per-call to backend
  • Avatars fetched via Puppeteer page evaluate (bypasses WA API limitations)
  • Tooltip state persisted in localStorage (survives page reload)
  • Multi-slice deployment shares one frontend, proxies API to per-slice backends

Database Migrations

8 ordered migrations, all backwards-compatible (nullable columns or defaults).

Migration 001: AI Personality Auto-Reply System

File: database/migrations/001-ai-personalities.sql (79 lines)

5 new tables:

Table Purpose
ai_config Single-row provider config (base_url, api_key, model, max_tokens, temperature)
personalities Named personalities with emoji + system_prompt
contact_personalities Which personality is assigned to which contact, plus mode/delay settings
auto_reply_log Every AI-generated reply with timing + token metrics
user_settings Generic key-value store for app settings

Also adds messages.is_ai_reply BOOLEAN to track AI-generated messages.

Migration 002: Delay Presets & Custom Traits

File: database/migrations/002-delay-presets-and-custom-fields.sql (7 lines)

  • Replaces delay_seconds INT with delay_preset VARCHAR (‘30s’, ‘5m’, ‘random’)
  • Adds custom_traits TEXT and known_facts TEXT to contact_personalities

Migration 003: Contact Management & Media Storage

File: database/migrations/003-contact-management-and-media-storage.sql (36 lines)

Contact fields: full_name, company, email, notes, location_met, tags TEXT[]

New media_files table for tracking storage tiers:

  • original_path, thumbnail_path, mime_type, file_size_bytes, thumb_size_bytes
  • storage_state (‘original’ | ‘thumbnail’ | ‘deleted’)
  • from_me boolean for sent vs received

Settings: outgoing_store_original, outgoing_store_thumbnail

Migration 004: Social Media Fields

File: database/migrations/004-social-media-fields.sql (6 lines)

Adds instagram, tiktok, telegram to contacts.

Migration 005: Avatar Media ID

File: database/migrations/005-avatar-media-id.sql (4 lines)

Adds avatar_media_id INTEGER referencing media_files.id for custom avatars.

Migration 006: Backfill Settings

File: database/migrations/006-backfill-settings.sql (5 lines)

Seeds backfill_contact_count = '25' and backfill_photo_days = '28'.

Migration 007: Pinned Timestamp

File: database/migrations/007-pinned-at.sql (5 lines)

Adds pinned_at TIMESTAMPTZ to chats for pin ordering.

Migration 008: Avatar Checked

File: database/migrations/008-avatar-checked.sql (2 lines)

Adds avatar_checked BOOLEAN to contacts (tracks if WA profile pic has been fetched).


Backend — New Services

PersonalityService.ts (364 lines)

Singleton managing AI personalities and contact assignments.

Key methods:

  • getAll() / getById(id) / create() / update() / delete()
  • setDefault(id) — marks one personality as the default for new contacts
  • getAssignments() — all contacts with personality assignments
  • assignContact(waId, config) — assign personality + mode + delay + traits
  • togglePause(waId) — pause/resume auto-reply for one contact
  • removeAssignment(waId) — remove personality from contact

State: pendingDelays: Map<string, NodeJS.Timeout> for managing delayed reply timers.

AIService.ts (99 lines)

Singleton for LLM completion via OpenAI-compatible API.

Key methods:

  • getConfig() — fetch provider config from ai_config table
  • updateConfig(updates) — save new provider/model/key
  • generateReply(systemPrompt, history[], incomingMessage){ reply, tokensUsed, responseTimeMs }

Supports any OpenAI-compatible endpoint: Mistral, OpenAI, Groq, local models.

BackfillService.ts (617 lines)

Singleton for background contact enrichment. Processes one step per call (non-blocking).

6 steps per contact:

# Step What It Does
1 resolve_phone Get phone number from chat via client.getContactById()
2 fetch_details Pull push_name, saved_name, about, is_business from WA
3 archive_messages Fetch last 10 messages, upsert to messages table
4 sync_media Download photos from last N days via mediaService.saveMedia()
5 generate_thumbs Create micro-thumbnails via mediaService.generateMissingMicroThumbnails()
6 cache_avatar Fetch WhatsApp profile pic via pupPage Puppeteer approach

State (in-memory, resets on restart):

{ initialized, contacts: [{waId, chatName, currentStep, completed}],
  currentIndex, totalContacts, completedContacts }

All operations are idempotent — safe to re-run after restart.

ContactImportService.ts (357 lines)

Import contacts from VCF/CSV with fuzzy phone matching.

Key methods:

  • parseVCF(content)ParsedContact[]
  • parseCSV(content)ParsedContact[]
  • matchContacts(parsed){ matched[], unmatched[] } (fuzzy match on last 10 digits)
  • applyImport(matches){ applied: number } (upsert matched data)
  • exportVCF() / exportCSV() — export all contacts

Backend — New & Enhanced Controllers

personalityController.ts (236 lines) — NEW

Handles both personality CRUD and AI config. Endpoints:

Personality CRUD:

  • GET /api/personalities → all personalities
  • POST /api/personalities → create { name, emoji, system_prompt }
  • PUT /api/personalities/:id → update
  • DELETE /api/personalities/:id → delete
  • PUT /api/personalities/:id/default → set as default

Contact Assignments:

  • GET /api/personalities/assignments → all assignments
  • GET /api/personalities/assign/:waId → one contact’s assignment
  • PUT /api/personalities/assign/:waId → assign { personality_id, auto_reply_mode, delay_preset, custom_traits, known_facts }
  • PUT /api/personalities/assign/:waId/toggle-pause → pause/resume
  • DELETE /api/personalities/assign/:waId → remove assignment

AI Config (also in this controller):

  • GET /api/ai/config → provider config
  • PUT /api/ai/config → update { provider_name, base_url, api_key, model, max_tokens, temperature }
  • POST /api/ai/test → test reply { message }{ reply, tokensUsed, responseTimeMs }
  • GET /api/ai/log → auto-reply log
  • DELETE /api/ai/log/:id → delete log entry

backfillController.ts (28 lines) — NEW

  • GET /api/backfill/status → current backfill state
  • POST /api/backfill/next → process one step, return progress

contactImportController.ts (82 lines) — NEW

  • POST /api/contacts/import (multipart) → parse + match → preview
  • POST /api/contacts/import/apply → apply confirmed matches

contactController.ts (515 lines) — NEW

Contact CRUD:

  • GET /api/contacts → list all contacts
  • GET /api/contacts/:waId → full contact details
  • PUT /api/contacts/:waId → update editable fields
  • GET /api/contacts/tags → all unique tags

Avatar Management:

  • GET /api/contacts/:waId/avatar → avatar image data
  • PUT /api/contacts/:waId/avatar → set avatar from media_id
  • GET /api/contacts/:waId/avatar-photos → list photos in contact’s media folder
  • POST /api/contacts/:waId/avatar-from-photo → set specific photo as avatar

chatController.ts (415 lines) — ENHANCED

New endpoint:

  • POST /api/chats/:chatId/pin → toggle pin with timestamp

messageController.ts (341 lines) — ENHANCED

New endpoints:

  • POST /api/messages/:chatId/react → emoji reaction { messageId, emoji }
  • POST /api/messages/:chatId/reply → quoted reply { messageId, text }
  • POST /api/messages/:chatId/forward → forward { messageId, targetChatId }
  • POST /api/messages/:chatId/star → toggle star { messageId }
  • POST /api/messages/:chatId/pin → pin message { messageId }
  • POST /api/messages/:chatId/delete → delete { messageId, forEveryone }
  • POST /api/messages/:chatId/download-media → download { messageId }{ data, mimetype, filename }

Backend — New Routes

File Lines Mounts At
personalityRoutes.ts 20 /api/personalities
aiRoutes.ts 20 /api/ai
backfillRoutes.ts 9 /api/backfill
contactRoutes.ts 29 /api/contacts

Frontend — New Pages

PersonalitiesPage.tsx (289 lines)

Full-page personality manager at /personalities.

Sections:

  • Personality Cards — grid of cards with emoji, name, system prompt preview. Each has star (set default), edit, delete buttons.
  • Contact Assignments Table — shows all assigned contacts with personality emoji/name, auto-reply mode (disabled/instant/delayed), delay preset, pause state. Remove button per row.
  • Create/Edit Modal — emoji input, name input, system_prompt textarea. Validation requires all three fields.

AISettingsPage.tsx (292 lines)

AI provider configuration at /ai-settings.

Sections:

  • Provider Presets — one-click buttons for Mistral, OpenAI, Groq (fills base_url + model)
  • Configuration Form — base_url, API key (password field with show/hide), model, max_tokens, temperature
  • Test Panel — send a test message, see AI reply + tokens + response time
  • Reply Log — scrollable list of all auto-replies with incoming message, AI response, personality, tokens, timing, timestamp

Frontend — New Components

PersonalityPicker.tsx (251 lines)

Inline personality assignment widget embedded in ContactProfile.

  • Dropdown to select personality (or None)
  • Mode selector: Disabled / Instant / Delayed
  • Delay preset: 30s / 5m / Random 1-5m
  • Custom traits textarea
  • Known facts textarea
  • Pause/play toggle button
  • Auto-saves on every change

AvatarPicker.tsx (173 lines)

Modal for selecting a contact’s avatar.

  • Grid of photos from contact’s media folder
  • “Use WhatsApp profile picture” button (fetches via pupPage)
  • “Clear avatar” button
  • Single selection with confirm

BackfillBanner.tsx (157 lines)

Banner between ActionBar and content area showing backfill progress.

Phases:

Phase Display
idle Hidden
intro “Leave the app idle and I’ll populate your contacts’ info” (auto-dismiss 8s)
running Spinner + current action + “5/25 (20%)” + thin green progress bar
paused Paused indicator (user became active)
complete Checkmark + “Backfill complete”
error Error state

ContactEditForm.tsx (286 lines)

Editable contact details form in ContactProfile.

  • Full name, company, email, location met (text inputs)
  • Notes (multiline textarea)
  • Tags (type + Enter to add, autocomplete from all existing tags)
  • Instagram, TikTok, Telegram handles
  • Auto-save with 500ms debounce (no save button)

ContactImportExport.tsx (210 lines)

Import/export panel in Settings page.

  • File upload area (drag-drop or click) for VCF/CSV
  • Preview modal showing matched vs unmatched contacts
  • Apply button to commit matched data
  • Export VCF / Export CSV buttons
  • Help accordion with platform-specific instructions (Google, iCloud, Android, Outlook)

ForwardModal.tsx (99 lines)

Chat picker modal for message forwarding.

  • Search input to filter chats
  • Chat list with avatars and names
  • Single selection → forward

MediaStorageSettings.tsx (147 lines)

Toggle switches for outgoing media storage in Settings.

  • Store outgoing originals toggle
  • Store outgoing thumbnails toggle
  • Storage stats display (total tracked, originals, thumb-only, expunged, bytes used)

MessageContextMenu.tsx (223 lines)

Right-click context menu on messages.

Actions: Reply, React (emoji), Star/Unstar, Pin, Forward, Copy text, Download media, Delete (with for-everyone option)

  • Positioned relative to click coordinates
  • Click-outside dismissal
  • All actions call messageAPI methods

PersonalityBadge.tsx (24 lines)

Small emoji + name badge showing a contact’s assigned personality.

CollapsibleSection.tsx (76 lines)

Generic expandable section with chevron animation. Used in ContactProfile to organize Contact Details, AI Auto-Reply, and WhatsApp Info.


Frontend — Enhanced Components

TopBar.tsx (334 lines, was 190)

Added:

  • Tooltip toggle button (? icon, toggles all hover tips app-wide)
  • Backfill status indicator
  • Navigation to new pages (Personalities, AI Settings)

ActionBar.tsx (214 lines, was 209)

Added:

  • Tip wrappers on all action buttons

ContactProfile.tsx (219 lines, was 163)

Restructured into collapsible sections:

  • Contact Details → ContactEditForm
  • AI Auto-Reply → PersonalityPicker
  • WhatsApp Info → existing WA data display
  • Avatar click → AvatarPicker modal
  • Social media links (Instagram, TikTok, Telegram)

ChatListItem.tsx (212 lines, was 76)

Added:

  • Pin/unpin toggle (pin icon appears on hover)
  • Custom avatar display (from avatar_media_id)
  • Avatar retry logic (useRef → useState + useEffect fix)
  • Red X indicator when WA profile pic unavailable

ConversationView.tsx (153 lines, was 55)

Added:

  • Forward modal integration
  • Message context menu integration
  • Reply-to preview

MessageBubble.tsx (140 lines, was 48)

Added:

  • Dropdown arrow for context menu
  • Star indicator
  • AI reply indicator
  • Reaction display

MessageComposer.tsx (105 lines, was 77)

Added:

  • Reply-to preview with cancel
  • Tip wrappers on buttons

ChatList.tsx (146 lines, was 84)

Added:

  • Pinned chats sorted to top by pinned_at timestamp

LoginPage.tsx (173 lines, was 69)

Added:

  • Phone mismatch detection and warning UI
  • Confirm/disconnect buttons when different phone connects
  • Loading progress bar
  • Connect elapsed timer

SettingsPage.tsx (336 lines, was 62)

Added:

  • MediaStorageSettings component
  • ContactImportExport component
  • Backfill configuration section

Frontend — New Hooks & Contexts

useIdleBackfill.ts (169 lines)

Manages idle-time background contact backfill.

How it works:

  1. On WA ready, shows intro toast for 8 seconds
  2. After intro, starts monitoring user activity (mousemove, keydown, click, touchstart, scroll)
  3. After 5 seconds idle → begins polling POST /api/backfill/next every 3 seconds
  4. Each poll processes ONE step for ONE contact (~1-3s each)
  5. Any user activity → pauses polling immediately
  6. User goes idle again → resumes where it left off
  7. When all contacts complete → shows completion message

Returns: { phase, totalContacts, completedContacts, currentContact, currentStep, detail }

TooltipContext.tsx (28 lines)

Context provider for app-wide tooltip toggle.

  • enabled: boolean — persisted in localStorage as tooltips_enabled
  • toggle() — flip enabled state
  • Wraps entire app in TooltipProvider

Frontend — Type Additions

12 new types added to frontend/src/types/index.ts (252 lines, was 105):

Type Fields
Personality id, name, emoji, system_prompt, is_default, created_at, updated_at
ContactAssignment contact_wa_id, personality_id, auto_reply_mode, delay_preset, is_paused, custom_traits, known_facts, personality_name, personality_emoji
AIConfig id, provider_name, base_url, api_key_preview, model, max_tokens, temperature
AutoReplyLog id, contact_wa_id, personality_id, incoming_message, ai_response, model_used, tokens_used, response_time_ms, personality_name, personality_emoji, created_at
UserSettings key-value: auto_reply_enabled, away_mode, backfill_contact_count, etc.
ContactEditable full_name, company, email, notes, location_met, tags[], instagram, tiktok, telegram
ContactFull extends ContactEditable + avatar_media_id, avatar_url
ImportPreview matched[], unmatched[], totalParsed
MatchResult wa_id, push_name, imported_name, imported_phone, imported_email, imported_company
MediaFile id, message_wa_id, chat_wa_id, original_path, thumbnail_path, mime_type, storage_state
ReplyContext messageId, text, senderName
BackfillState phase, totalContacts, completedContacts, currentContact, currentStep, detail

Frontend — API Layer Additions

frontend/src/services/api.ts (268 lines, was 84) now exports 8 API modules:

personalityAPI (10 methods)

getAll, create, update, delete, setDefault,
getAssignments, getContactAssignment, assignContact, togglePause, removeAssignment

aiAPI (5 methods)

getConfig, updateConfig, test, getLog, deleteLogEntry

backfillAPI (4 methods)

getStatus, processNext, initialize, reset

contactAPI (10 methods)

listContacts, getContact, updateContact, getTags,
getAvatar, setAvatar, getAvatarPhotos, setAvatarFromPhoto,
importContacts, applyImport, exportContacts

messageAPI — Enhanced (7 new methods)

react, reply, forward, star, pin, deleteMessage, downloadMedia

mediaStorageAPI (3 methods)

getSettings, updateSettings, getStats

statusAPI — Enhanced (1 new method)

confirmPhone

Tooltip System

A complete app-wide tooltip system added across every interactive element.

Infrastructure

File Purpose
TooltipContext.tsx Boolean enabled state + localStorage persistence
Tip.tsx Wrapper component: hover-triggered, 4-position, viewport-clamped
TopBar toggle button ? icon in top bar to enable/disable all tips

Tip Component Details

<Tip text="Descriptive help text" position="bottom">
  <button>Click me</button>
</Tip>
  • Positions: top, bottom, left, right
  • Styling: bg-wa-bg-deep/95, green border (border-wa-green/30), backdrop blur
  • Max width: 280px, multiline support via whitespace-pre-line
  • Viewport clamping: Auto-adjusts horizontal position if tooltip overflows screen edges
  • Zero-cost when disabled: Returns bare {children} when enabled === false

Files with Tips (22 total)

Every interactive element in the app has a descriptive tooltip:

Components (16): TopBar, ActionBar, ChatList, ChatListItem, ConversationView, MessageComposer, MessageBubble, ContactProfile, ContactEditForm, PersonalityPicker, AvatarPicker, CollapsibleSection, MessageContextMenu, ForwardModal, ContactImportExport, MediaStorageSettings

Pages (6): LoginPage, ChatPage, SettingsPage, PersonalitiesPage, AISettingsPage, MediaBrowserPage


Background Backfill System

Problem

When opening the app, the chat list shows names but no photos, contact details, or message history.

Solution

Frontend-driven idle polling: detect user inactivity, process contacts one step at a time.

Flow

App loads → WA ready → intro toast (8s)
    ↓
User goes idle (5s no activity)
    ↓
Poll POST /api/backfill/next every 3s
    ↓ (each call = 1 step for 1 contact)
User moves mouse → pause
    ↓
User idle again (5s) → resume
    ↓
All 25 contacts × 6 steps = 150 calls ≈ 7-8 min
    ↓
"Backfill complete" toast

Settings (user_settings table)

Key Default Purpose
backfill_contact_count '25' How many recent non-group chats to process
backfill_photo_days '28' How far back to sync media

Avatar System

The Problem

WhatsApp profile pictures aren’t available through the standard whatsapp-web.js API for many contacts.

The pupPage Breakthrough

The client.pupPage property exposes the Puppeteer page running WhatsApp Web internally. We can page.evaluate() to call WhatsApp’s internal JavaScript APIs directly:

const url = await client.pupPage.evaluate(async (jid: string) => {
  const result = await window.Store.ProfilePic.profilePicFind(jid);
  return result?.eurl || null;
}, contact.id._serialized);

This uses WhatsApp Web’s internal Store.ProfilePic module to query the profile picture cache, which has far better coverage than the official API.

Avatar Priority

  1. Custom avatar (user-selected from media photos via avatar_media_id)
  2. WhatsApp profile picture (fetched via pupPage, cached on disk)
  3. Default placeholder

Red X Indicator

When a contact’s WhatsApp profile pic is unavailable (private or no photo), ChatListItem shows a small red X on the avatar to indicate the photo couldn’t be fetched. Controlled by the avatar_checked flag — only shows after we’ve actually tried to fetch.


Production Deployment Infrastructure

Multi-Slice Architecture

DigitalOcean Droplet (178.128.183.166)
    ↓
Nginx (ports 80/443)
    ├── wa1.ipnoelp.com → wa-slice-1 (port 4001, db: wa_slice_1)
    ├── wa2.ipnoelp.com → wa-slice-2 (port 4002, db: wa_slice_2)
    ├── wa3.ipnoelp.com → wa-slice-3 (port 4003, db: wa_slice_3)
    └── ... up to wa8 (port 4008)
    └── All share: /deploy/frontend-dist/ (static React build)

Each slice is a fully isolated WhatsApp client: own database, own WA session, own media storage. Managed by a single script.

manage.sh (285 lines)

./manage.sh status          # Show all slices
./manage.sh create N        # Create + start slice N
./manage.sh stop N          # Stop slice N
./manage.sh start N         # Start existing slice N
./manage.sh restart N       # Restart slice N
./manage.sh destroy N       # Stop + keep data
./manage.sh purge N         # Delete everything
./manage.sh logs N          # Tail logs
./manage.sh build           # Rebuild Docker image
./manage.sh start-all       # Start all slices
./manage.sh stop-all        # Stop all

Deployment Workflow

# 1. Sync source to droplet
rsync -avz --exclude='node_modules' --exclude='dist' \
  -e "ssh -i ~/.ssh/cms_droplet" \
  frontend/src/ root@178.128.183.166:/home/chas-watkins/code/WhatsApp/frontend/src/

# 2. Build on droplet
ssh -i ~/.ssh/cms_droplet root@178.128.183.166 \
  "cd /home/chas-watkins/code/WhatsApp/frontend && npx vite build"

# 3. Copy to Nginx root (all slices share this)
ssh -i ~/.ssh/cms_droplet root@178.128.183.166 \
  "cp -r /home/chas-watkins/code/WhatsApp/frontend/dist/* \
         /home/chas-watkins/code/WhatsApp/deploy/frontend-dist/"

Per-Slice Resources

Resource Pattern
Backend port 400N (4001-4008)
Database port 543N (5431-5438)
Database name wa_slice_N
Docker container wa-slice-N
Session volume wa_session_N
Media directory /data/wa-slice-N/media/

Complete File Reference

New Backend Files

File Lines Purpose
backend/src/services/PersonalityService.ts 364 AI personality CRUD + contact assignments
backend/src/services/AIService.ts 99 LLM completion via OpenAI-compatible API
backend/src/services/BackfillService.ts 617 Background contact enrichment pipeline
backend/src/services/ContactImportService.ts 357 VCF/CSV import with fuzzy phone matching
backend/src/controllers/personalityController.ts 236 Personality + AI config endpoints
backend/src/controllers/backfillController.ts 28 Backfill status + next-step endpoint
backend/src/controllers/contactImportController.ts 82 Import/export endpoints
backend/src/controllers/contactController.ts 515 Contact CRUD + avatar management
backend/src/routes/personalityRoutes.ts 20 Personality endpoint routing
backend/src/routes/aiRoutes.ts 20 AI config endpoint routing
backend/src/routes/backfillRoutes.ts 9 Backfill endpoint routing
backend/src/routes/contactRoutes.ts 29 Contact endpoint routing

Enhanced Backend Files

File Lines Was Change
backend/src/services/MediaService.ts 622 ~455 +media_files tracking, storage states, deletion
backend/src/services/WhatsAppService.ts 448 ~341 +auto-reply, personality integration, conversation history
backend/src/controllers/chatController.ts 415 ~200 +pin/unpin, avatar integration
backend/src/controllers/messageController.ts 341 ~124 +react, reply, forward, star, pin, delete, download
backend/src/controllers/mediaController.ts 346 ~347 ~same (minor adjustments)

New Frontend Files

File Lines Purpose
frontend/src/pages/PersonalitiesPage.tsx 289 AI personality management page
frontend/src/pages/AISettingsPage.tsx 292 AI provider config + test + log page
frontend/src/components/PersonalityPicker.tsx 251 Inline personality assignment widget
frontend/src/components/AvatarPicker.tsx 173 Modal avatar selection from photos/WA
frontend/src/components/BackfillBanner.tsx 157 Backfill progress banner
frontend/src/components/ContactEditForm.tsx 286 Editable contact fields with auto-save
frontend/src/components/ContactImportExport.tsx 210 VCF/CSV import/export UI
frontend/src/components/ForwardModal.tsx 99 Chat picker for message forwarding
frontend/src/components/MediaStorageSettings.tsx 147 Outgoing media storage toggles
frontend/src/components/MessageContextMenu.tsx 223 Right-click message action menu
frontend/src/components/PersonalityBadge.tsx 24 Emoji + name badge
frontend/src/components/CollapsibleSection.tsx 76 Generic expandable section
frontend/src/components/Tip.tsx 90 Hover tooltip component
frontend/src/hooks/useIdleBackfill.ts 169 Idle detection + backfill polling
frontend/src/contexts/TooltipContext.tsx 28 Tooltip enabled state + localStorage

Enhanced Frontend Files

File Lines Was Change
frontend/src/App.tsx 67 46 +TooltipProvider, AppLayout extraction, backfill integration
frontend/src/services/api.ts 268 84 +6 new API modules (31 new methods)
frontend/src/types/index.ts 252 105 +12 new type interfaces
frontend/src/contexts/WhatsAppContext.tsx 321 233 +phone mismatch, confirmPhone, backfill state
frontend/src/components/TopBar.tsx 334 190 +tooltip toggle, new page links
frontend/src/components/ActionBar.tsx 214 209 +tip wrappers
frontend/src/components/ContactProfile.tsx 219 163 +collapsible sections, personality, edit form, avatar
frontend/src/components/ChatListItem.tsx 212 76 +pinning, custom avatar, retry logic, red X
frontend/src/components/ConversationView.tsx 153 55 +forward modal, context menu, reply preview
frontend/src/components/MessageBubble.tsx 140 48 +context menu trigger, star/AI indicators, reactions
frontend/src/components/MessageComposer.tsx 105 77 +reply preview, tip wrappers
frontend/src/components/ChatList.tsx 146 84 +pinned sort
frontend/src/components/QRCode.tsx 61 21 +enhanced styling
frontend/src/pages/LoginPage.tsx 173 69 +phone mismatch UI, progress bar
frontend/src/pages/ChatPage.tsx 100 64 +backfill banner integration
frontend/src/pages/SettingsPage.tsx 336 62 +media storage, import/export, backfill config
frontend/src/pages/MediaBrowserPage.tsx 903 835 +tip wrappers, minor enhancements

Database Files

File Lines Purpose
database/migrations/001-ai-personalities.sql 79 5 tables + is_ai_reply column
database/migrations/002-delay-presets-and-custom-fields.sql 7 Delay preset + custom traits
database/migrations/003-contact-management-and-media-storage.sql 36 Contact fields + media_files table
database/migrations/004-social-media-fields.sql 6 Instagram, TikTok, Telegram
database/migrations/005-avatar-media-id.sql 4 Custom avatar reference
database/migrations/006-backfill-settings.sql 5 Backfill defaults
database/migrations/007-pinned-at.sql 5 Chat pin timestamp
database/migrations/008-avatar-checked.sql 2 Avatar fetch tracking

Deployment Files

File Lines Purpose
deploy/manage.sh 285 Multi-slice management script
deploy/docker-compose.yml ~100 Production orchestration
deploy/init-databases.sh ~150 Per-slice DB initialization
deploy/Dockerfile.backend ~44 Production backend image
deploy/nginx/ various Reverse proxy configs

Key Lessons & Gotchas

  1. pupPage is the avatar breakthroughclient.pupPage.evaluate() lets you call WhatsApp Web’s internal window.Store.ProfilePic API, which has far better profile picture coverage than the official whatsapp-web.js methods. Use string-template evaluate to avoid TypeScript window reference errors.

  2. useRef → useState for avatar retryChatListItem avatar loading used a useRef for retry count, but changes to refs don’t trigger re-renders. Converting to useState + useEffect fixed the avatar display bug.

  3. Frontend-driven backfill beats backend cron — Making the frontend poll (with idle detection) instead of running a background job means zero wasted work when nobody’s watching, natural pause/resume on user activity, and simple state management.

  4. All new columns must be nullable or have defaults — Every migration adds nullable columns. This keeps the schema backwards-compatible and means migrations can run on a live database without downtime.

  5. Auto-save with debounce > explicit save buttonsContactEditForm saves every field change with a 500ms debounce. Users never lose data, and there’s no “did I save?” anxiety.

  6. One frontend, N backends — Production deploys a single built frontend to Nginx’s root directory (/deploy/frontend-dist/). All 8 WhatsApp slices share the same UI. API calls are routed by Nginx based on subdomain.

  7. Backend runs from dist/ not src/ — After editing .ts files, you MUST run npx tsc before restarting. The Docker container runs compiled JS from dist/, not TypeScript from src/.

  8. node_modules lives inside Docker only — On the host machine, node_modules is empty. To run tsc --noEmit or any Node tooling, use docker exec whatsapp-frontend npx tsc --noEmit.

  9. Tooltip zero-cost pattern — When enabled === false, the Tip component returns bare {children} with no wrapper div, event listeners, or state. This means tooltips have literally zero runtime cost when disabled.

  10. VCF phone matching uses last-10-digits fuzzy — International phone number normalization is unreliable, so the import system falls back to matching on the last 10 digits of normalized numbers. This handles most country code / formatting differences.