VibeWeek
Home/Grow/Customer Notes & Internal Annotations: Chat Prompts

Customer Notes & Internal Annotations: Chat Prompts

⬅️ Back to 6. Grow

Internal notes are how your team remembers what happened with each customer — context, preferences, history, warnings, opportunities — without exposing it to the customer themselves. "Champion is leaving the company in March." "Renewed early because procurement was confused; don't bring up auto-renewal in QBRs." "User reported they hate the new dashboard; don't auto-default them to it."

Most B2B SaaS ship a "Notes" textarea on the customer page in week one and then quietly add structure over time as it becomes obvious that one giant textarea doesn't scale: tagging, mentions, threading, attachments, search, role-based visibility, audit logs. This is the chat-prompt playbook for shipping internal notes that scale from a single CSM to a 50-person customer-success org.

When This Belongs

Use internal notes when:

  • Multiple internal team members touch each customer (sales → CS → support → expansion)
  • Per-customer context is meaningful and persistent
  • Handoffs between team members happen regularly
  • Memory of "we tried X with this customer" matters

Don't bother when:

  • Pre-revenue (founder remembers everything; no team yet)
  • All customers self-serve with no human touch

Data Model

I'm building internal notes on customer records. Help me design the data model.

Schema (Drizzle):
```sql
customer_notes:
  id, customer_id (or account_id depending on model),
  author_user_id, body (markdown), pinned (boolean),
  visibility (enum: 'internal' | 'team:specific_team_id' | 'private:author_only'),
  category (enum: 'general' | 'sales' | 'support' | 'cs' | 'risk' | 'opportunity'),
  created_at, updated_at, deleted_at (soft-delete),
  parent_note_id (nullable; for threading)

note_tags:
  note_id, tag (e.g. 'churn-risk', 'expansion-candidate', 'champion-leaving')

note_mentions:
  note_id, mentioned_user_id, mentioned_team_id (nullable)

note_attachments:
  id, note_id, storage_url, filename, content_type, size_bytes

note_audit_log:
  note_id, event_type (created | edited | deleted | visibility_changed),
  actor_user_id, payload (JSON), timestamp

Implement:

  • The schema + types
  • Helper functions: createNote(), editNote(), deleteNote(), pinNote()
  • Visibility check: canUserSeeNote(user, note) based on visibility field + user's team membership
  • Audit-log writes happen atomically with state changes

Stack: Next.js + Drizzle + Postgres.


## The UI: Notes Panel on Customer Page

Build the notes panel on the customer detail page:

Layout:

  • Right sidebar (or tab) titled "Internal Notes"
  • New-note composer at top (markdown editor)
  • Pinned notes section above scrollable history
  • Each note: author + timestamp + body + reactions/replies
  • Filter: All / Sales / Support / CS / Risk / Opportunity
  • Search across notes
  • @-mention auto-complete for users + teams
  • Hashtag auto-complete for tags

Composer features:

  • Markdown editing (bold, italic, lists, links)
  • @mentions trigger user-picker dropdown
  • #tags trigger tag-picker dropdown
  • Attachments via drag-drop
  • Visibility selector (default: internal)
  • Pin checkbox

Visual indicators:

  • Pinned: pinned icon + sticky to top
  • Tagged: small chips below note
  • Mentioned: highlight if note mentions current user
  • Edited: "edited [time ago]" tooltip

Stack: Next.js + Tailwind + shadcn/ui + TipTap or simple textarea+react-markdown.


## Mentions + Notifications

When @mentioning users or teams, generate notifications:

Implementation:

  1. Parse the note body for @username or @team-name patterns
  2. Resolve to user IDs / team IDs
  3. Insert rows into note_mentions table
  4. For each mention, send a notification:
    • In-app notification (your existing notification system)
    • Optional: email (digest by default; instant for "high priority" mentions)
    • Optional: Slack DM (if integrated)

Edge cases:

  • @everyone or @all: limit to admins-only to avoid spam
  • Editing a note adds new mentions: notify only newly added users
  • Self-mention: ignore
  • Mention in private note (visibility=private): no notification (recipient can't see anyway)

Stack: Next.js + Drizzle + your notification stack (in-app + email).


## Search Across Notes

For mid-to-large customer bases, search becomes essential.

Build search across all internal notes:

Use cases:

  1. Find all notes mentioning "churn" across all customers
  2. Find notes by author (e.g. all my notes from last month)
  3. Find notes from a specific customer in a date range
  4. Find all notes tagged "champion-leaving"

Search index options:

  • Postgres full-text search (good for <1M notes)
  • Algolia / Meilisearch / Typesense for richer + faster
  • ElasticSearch for enterprise scale

Implement:

  • An index update on note create/edit/delete
  • A search endpoint with filters (author, customer, tag, date range, full-text)
  • A search UI with result highlights

Permissions:

  • Search results filtered by visibility (only show notes user can access)
  • Audit search queries for compliance

Stack: Next.js + Postgres FTS (or Meilisearch for >100K notes).


## Customer Health Auto-Notes

The most powerful pattern: system-generated notes when customer behavior changes.

Auto-create internal notes when system events happen:

Event triggers:

  • Customer downgrades plan: auto-note "Downgraded from Pro to Free on [date]"
  • Customer hits usage anomaly (10x prior week): "Usage spike detected"
  • Customer's NPS drops to detractor: "NPS submitted: -3 (detractor)"
  • Renewal in 90 days: "Renewal upcoming on [date]; current ARR $X"
  • Champion (logged in primary user) hasn't logged in for 30 days: "Champion inactive 30 days"
  • Support ticket volume spikes: "5 tickets in past 7 days (vs normal 1/week)"
  • Payment failed: "Payment failed; dunning started"

Implementation:

  • Webhooks from each system into a "customer events" stream
  • Event processor evaluates rules; creates auto-notes with category='auto'
  • Auto-notes visually distinguished (system avatar; subtle background)
  • Auto-notes are searchable + tagged appropriately
  • CSM can pin auto-notes that are persistently relevant

Stack: Next.js + Inngest / Vercel Queues + Drizzle.


## Threaded Replies

For larger team discussions on a single topic:

Add threaded replies to notes:

Schema (already in data model):

  • parent_note_id allows threading
  • Nested 1-2 levels deep (don't allow infinite nesting; gets messy)

UI:

  • Reply button under each note
  • Replies indented and grouped under parent
  • Collapsible threads (click "X replies" to expand)
  • @-mention works in replies same as parent

Notification on replies:

  • Author of parent note gets notified
  • Anyone @mentioned in the reply gets notified
  • Anyone who replied previously stays subscribed (optional)

Stack: Next.js + Drizzle.


## Pinned Notes

Critical context that should stay top-of-mind:

Add pinned notes feature:

Behavior:

  • "Pin" toggle on each note
  • Pinned notes sort to top of customer's notes panel
  • Visually distinct (pin icon; subtle background)
  • Cap at 5 pinned notes per customer (force prioritization)
  • Pin/unpin actions audit-logged

Use cases:

  • "This account uses our beta API; not the standard one"
  • "Champion is leaving in March; build relationship with [new contact]"
  • "DO NOT discuss pricing changes; sensitive contract negotiation"

Stack: Next.js + Drizzle.


## Visibility / Privacy Controls

Implement visibility controls:

Visibility levels:

  1. Internal (default): all team members with access to the customer record see it
  2. Team-specific: only the named team (e.g. only Customer Success team)
  3. Private: only the author can see (rare; use sparingly)

UI:

  • Visibility selector when composing
  • Visual indicator on the note showing its visibility
  • Filter to show/hide private notes

Why team-specific:

  • Sales notes about deal negotiation shouldn't always be visible to support
  • Support notes about an irate customer shouldn't always be visible to sales

Why private (rare):

  • Personal observations the author isn't ready to commit to a team-shared narrative
  • Avoid normalizing private notes — they hide context from the team

Permissions enforcement:

  • Server-side filter on every query
  • Don't trust client to honor visibility
  • Audit-log access patterns

Stack: Next.js + Drizzle + your auth context.


## Audit Log

For compliance + accountability:

Maintain an audit log of all note actions:

Logged events:

  • Note created / edited / deleted
  • Visibility changed
  • Pinned / unpinned
  • Search query (high-volume; consider sampling for storage efficiency)

Storage:

  • Append-only table
  • Retain for 1+ year for SOC 2 / similar

Surfacing:

  • Per-note edit history (who edited when; what changed)
  • Per-customer activity log
  • Per-user activity log (audit a user's behavior if needed)

Stack: Next.js + Drizzle.


## CRM Integration

If you also use Salesforce / HubSpot / etc., notes need to flow.

Sync notes between your in-house customer profile and your CRM:

Patterns:

  1. In-house notes are source of truth: replicate to CRM via API on write
  2. CRM notes are source of truth: import from CRM via webhook / poll
  3. Both directions: tricky; needs conflict resolution

For most B2B SaaS:

  • In-house notes for product / support / detailed CS context
  • CRM (Salesforce / HubSpot) for sales-driven notes that the rev team manages
  • Sync sales notes from CRM into your platform; don't sync the other way (you trust CRM authoritative for sales)

Implementation:

  • Webhook from CRM on note creation (if available) or poll every 5 min
  • One-way mirror to your in-house notes with author = "CRM Sync (User)"
  • Deduplicate via external_id

Stack: Next.js + Drizzle + Salesforce / HubSpot SDK.


## Common Pitfalls

**Single text-blob "notes" field with no structure.** Doesn't scale past 10 notes. Build structured records from start.

**No visibility / privacy controls.** Sensitive sales notes leak to support team. Build visibility from day 1.

**No mentions / notifications.** Notes go unread. Add @-mention + notify.

**No search.** "What did we discuss with this customer last quarter?" → unsearchable. Index notes; expose search.

**No audit log.** Bad actor edits / deletes notes; no record. Append-only audit log.

**No pinning.** Critical context buried under recent activity. Pinning surfaces.

**Auto-notes that overwhelm.** System fires 50 auto-notes per customer per day; signal lost. Tune rules; bundle similar events into digests.

**Mentions that spam.** @everyone abused; users opt out of all mentions. Restrict @everyone; tier mention notifications.

**Notes accessible via API key without scope check.** API token returns all notes regardless of visibility. Apply scope to API too.

**No way to export notes.** GDPR DSAR requests need notes about the user. Plan for export.

**Notes not part of customer-record search.** Searching customer name doesn't surface notes. Index together.

**Editing without history.** Edit erases prior content; no record of what was originally written. Track edits.

**Soft-delete that returns deleted notes in queries.** Forgot to filter `deleted_at IS NULL`. Default-filter at query layer.

**Customer-visible accidentally.** Internal note accidentally shared to customer. UI must never expose internal notes externally.

**No threading.** Long discussions become 20-comment walls in chronological mess. Add reply threading.

**Notes scattered across systems.** Sales notes in Salesforce; support notes in Zendesk; CSM notes in your platform; nobody sees full picture. Centralize where it makes sense.

**Note format that doesn't render markdown.** Plain text only; users want bold + lists. Add markdown rendering.

**Tags free-text without governance.** Every CSM creates their own tags; "churn-risk" / "churnRisk" / "atrisk" all variants. Curated tag list.

**No "system" vs "human" distinction.** Auto-notes look identical to human notes; CSMs can't tell. Visual differentiation.

**Mentions that resolve to wrong people on team change.** Mention @sarah; sarah leaves; @sarah doesn't update. Use stable user IDs.

**Forgetting to surface notes during interactions.** Support agent picks up customer call; doesn't see the "champion is leaving" pinned note. Surface notes prominently in any customer-facing surface.

## See Also

- [Audit Logs](./audit-logs-chat.md)
- [Activity Feed / Timeline Implementation](./activity-feed-timeline-implementation-chat.md)
- [Comments / Threading / Mentions](./comments-threading-mentions-chat.md)
- [In-App Notifications](./in-app-notifications-chat.md)
- [Notification Preferences & Unsubscribe](./notification-preferences-unsubscribe-chat.md)
- [Roles & Permissions](./roles-permissions-chat.md)
- [Multi-Tenancy](./multi-tenancy-chat.md)
- [Internal Admin Tools](./internal-admin-tools-chat.md)
- [Customer Health Scoring](./customer-health-scoring-chat.md)
- [Customer Analytics Dashboards](./customer-analytics-dashboards-chat.md)
- [Settings & Account Pages](./settings-account-pages-chat.md)
- [Tags / Labels System](./tags-labels-system-chat.md)
- [Search & Autocomplete / Typeahead](./search-autocomplete-typeahead-chat.md)
- [Customer Reports & Scheduled Exports](./customer-reports-scheduled-exports-chat.md)
- [Account Deletion & Data Export](./account-deletion-data-export-chat.md) — GDPR exports include notes
- [Account Suspension & Fraud Holds](./account-suspension-fraud-holds-chat.md)
- [Approval Workflows & Multi-Step Routing](./approval-workflows-multi-step-routing-chat.md)
- [Customer Support](./customer-support-chat.md)
- [Microcopy & Product Copy Systems](./microcopy-product-copy-systems-chat.md)
- [Sidebar Navigation Implementation](./sidebar-navigation-implementation-chat.md)
- [In-App Status Banners & System Notifications](./in-app-status-banners-system-notifications-chat.md)
- [Toast Notifications UI](./toast-notifications-ui-chat.md)
- [Tooltip & Hint Systems](./tooltip-hint-systems-chat.md)
- [Strategic Account Planning (LaunchWeek)](https://launchweek.dev/content/4-convert/strategic-account-planning.md) — notes feed account plans
- [Customer Health Scoring Playbook (LaunchWeek)](https://launchweek.dev/content/4-convert/customer-health-scoring-playbook.md)
- [Voice of Customer Program (LaunchWeek)](https://launchweek.dev/content/4-convert/voice-of-customer-program.md)
- [CRM Providers (VibeReference)](https://viberef.dev/marketing-and-seo/crm-providers.md)
- [HubSpot (VibeReference)](https://viberef.dev/marketing-and-seo/hubspot.md)