field-sales-crm

byYH METech Oman

You are an expert SaaS product team consisting of: - Product Manager - UI/UX Designer - Frontend Engineer - Backend Engineer - Database Architect - DevOps Engineer - QA Engineer Build a production-ready Micro SaaS. Idea: A field-visit accountability layer that turns unstructured rep conversations into reliable CRM data and completed follow-ups. VisitLoop is the post-visit execution layer for field sales teams. Reps speak for 60 seconds after a visit; VisitLoop creates the CRM record, assigns follow-ups, and shows managers exactly what was completed. Requirements: Create: - Beautiful landing page - Dashboard - User authentication - Google Login - Email Login - Stripe subscriptions - Pricing page - Admin dashboard - Database - REST APIs - Responsive design - Dark mode - User settings - Billing page - Analytics - SEO - Error handling - Loading states Generate: - Frontend - Backend - Database schema - APIs - Authentication - Deployment configuration - Environment variables - README - Sample data Use a modern design similar to Linear, Notion or Vercel. Everything should be production-ready. Review the entire project. Find every bug. Improve the product Improve: - UI - UX - Mobile responsiveness - Performance - Accessibility - Animations - Dashboard - Pricing page - Onboarding - Empty states - Loading states Refactor the code. Follow best practices. Keep everything production-ready. Suggest 20 AI features that would significantly increase the value of this SaaS. For each feature include: - Problem solved - User benefit - AI model recommendation - Technical implementation - Difficulty Create a modern SaaS landing page. Include: - Hero section - Social proof - Problem - Solution - Features - Product screenshots - Testimonials - Pricing - FAQ - CTA

Landing pageSign Up
Landing page

Comments (0)

No comments yet. Be the first!

System Requirements

System Requirements Document for field-sales-crm

1. Introduction

VisitLoop is a production-ready Micro SaaS that acts as a field-visit accountability layer for field sales teams. It turns unstructured rep conversations into reliable CRM data and completed follow-ups. VisitLoop is positioned as the post-visit execution layer: a field sales rep speaks for approximately 60 seconds after a visit, and VisitLoop creates the CRM record, assigns follow-ups, and shows managers exactly what was completed.

The product serves three audiences: field sales reps who need to capture visit outcomes in seconds while still in the car, sales managers who need reliable visibility into completed versus outstanding post-visit work, and workspace administrators who keep the account operational, correctly provisioned, and correctly billed.

The design register is systematic product craft — warm paper ground, one hot tangerine accent, tabular numerals as ornament — in the spirit of Linear, Notion, and Vercel, but never the generic indigo/blue-on-white SaaS template.

Page 1 of 50

2. System Overview

VisitLoop is delivered as a full-stack web application with a public marketing surface, an application-owned identity layer, and a protected workspace shell.

Current delivery:

  • A public Landing page presenting hero, social proof, problem, solution, features, product screenshots, testimonials, pricing, FAQ, and CTA.
  • A public Pricing page for evaluating subscription plans before purchase.
  • Application-owned identity with Sign Up (self-service enrollment) and Login (Google Login and Email Login).
  • A protected Onboarding flow for new users and workspaces.
  • A protected workspace shell containing Dashboard, Visit Capture, Visit Records, Follow-ups, My Follow-ups, Execution, Analytics, Admin dashboard, Billing page, and User settings.
  • A backend exposing REST APIs, a relational database, Stripe subscription integration, and AI extraction of structured CRM data from spoken recaps.
  • Deployment configuration, environment variables, README, and sample data.

Actors:

  • Field Sales Rep — captures ~60-second spoken recaps after visits and completes assigned follow-ups.
  • Sales Manager — reviews execution accountability and analytics for the team.
  • Workspace Administrator — manages users, access, configuration, and billing.
  • System actors (non-persona): the AI extraction service, the Stripe billing provider, and the backend persistence layer.
Page 2 of 50

Narrow exclusions: VisitLoop is the post-visit layer. It does not replace the CRM of record, does not perform pre-visit route planning, and does not own the Stripe payment surface itself (Stripe owns checkout and payment collection).

2a. Product Interpretation and Delivery Boundary

VisitLoop owns the interaction where a rep speaks a recap and where a manager reads completion. The spoken recap is captured in a first-party surface; the AI extraction that turns speech into structured fields is a backend responsibility that the rep observes as filling fields. Subscription purchase is initiated from the Pricing page and completed on Stripe's own hosted surface; VisitLoop reflects the resulting subscription state on the Billing page. Identity is application-owned: users enroll themselves through Sign Up and return through Login using Google or Email. Protected workspace destinations require an authenticated session; the public Landing page, Pricing page, Sign Up, and Login do not.

Everything described in this document is current. The 20 AI feature recommendations requested by the user are captured in Section 3 as a current deliverable (a documented recommendation set), not as additional product surfaces.

2b. Source Content Inventory

No reference directive declares content_source; this section is intentionally omitted.

2c. Page Content and Component Coverage

Page 3 of 50

Landing page

  • Information/state: Public marketing surface. Hero headline "Your reps already said what happened. VisitLoop just writes it down." with a single tangerine text-link CTA ("Start free") and a muted 13px supporting line. Numbered section rules carrying micro-labels: 01 / PROBLEM, 02 / HOW IT WORKS, 03 / FEATURES, 04 / PROOF, 05 / PRICING, 06 / FAQ.
  • Primary actions: Start free (→ Sign Up); View pricing (→ Pricing page); Sign in (→ Login).
  • Supporting actions: FAQ accordion expand/collapse; testimonial and screenshot section anchors.
  • Domain entities: Plan (name, price, feature list), Testimonial (quote, attribution), FAQ item (question, answer), Feature (title, description), Product screenshot (surface name, image).
  • Component responsibilities: Asymmetric split hero (text column 5/12, product surface 7/12 bleeding off the right viewport edge); live voice-capture sheet rendering with animating tangerine waveform and three self-typing extracted CRM fields (Account, Outcome, Next step) plus a tabular 60s timer; social proof strip; problem statement; solution explanation; feature list; product screenshots on paper ground with hairline frames; testimonials; pricing summary; FAQ accordion; closing CTA.
  • States: Loading — skeleton blocks for screenshots and testimonials. Empty — if testimonials or screenshots are unavailable, the section renders its heading and a muted "Coming soon" line rather than a broken grid. Success — all sections render. Error — a section that fails to load renders a hairline-bordered inline notice with a retry control; the rest of the page remains usable. Recovery — retry re-fetches only the failed section.
Page 4 of 50

Sign Up

  • Information/state: Anonymous enrollment surface. Fields: full name, work email, password. Google enrollment button. Terms acknowledgement.
  • Primary actions: Create account with email; Continue with Google.
  • Supporting actions: Link to Login ("Already have an account?"); link to Pricing page.
  • Domain entities: User (name, email, auth provider), Workspace (created on first enrollment).
  • Component responsibilities: Form with inline field validation; provider button; password strength indicator; error banner region.
  • States: Loading — submit button shows an inline spinner and is disabled. Empty — pristine form. Success — redirect to Onboarding. Error — inline field errors for invalid email, weak password, or existing account; provider errors surface in the banner with a retry. Recovery — the form retains entered values so the user can correct and resubmit.
Page 5 of 50

Pricing page

  • Information/state: Public plan comparison. Each plan shows name, price, billing interval, and included feature list.
  • Primary actions: Choose plan (→ Sign Up if anonymous, or → Stripe checkout if authenticated).
  • Supporting actions: Toggle monthly/annual; link to FAQ on the Landing page.
  • Domain entities: Plan (name, price, interval, features), Subscription (current plan, status).
  • Component responsibilities: Plan columns with hairline separation; feature comparison rows; interval toggle; CTA per plan.
  • States: Loading — plan skeletons. Empty — if no plans are configured, a muted notice with a link to contact support. Success — plans render with the current plan marked when the visitor is authenticated. Error — inline notice with retry. Recovery — retry re-fetches plans.

Login

  • Information/state: Anonymous returning-verification surface. Fields: email, password. Google Login button.
  • Primary actions: Sign in with email; Continue with Google.
  • Supporting actions: Link to Sign Up; password reset link.
  • Domain entities: User (email, auth provider), Session.
  • Component responsibilities: Credential form; provider button; error banner; "remember me" control.
  • States: Loading — submit disabled with spinner. Empty — pristine form. Success — redirect to Dashboard (or the originally requested protected destination). Error — invalid credentials message that does not disclose whether the email exists; provider errors in the banner. Recovery — form retains email; password cleared.
Page 6 of 50

Onboarding

  • Information/state: Protected first-run setup. Steps: confirm workspace name, invite or defer teammates, connect CRM destination preference, choose default follow-up assignment rule, confirm timezone.
  • Primary actions: Complete each step; Finish setup.
  • Supporting actions: Skip a step; go back a step.
  • Domain entities: Workspace (name, timezone), User (role), Invitation (email, role), Workspace settings (CRM destination, default assignment rule).
  • Component responsibilities: Stepper with progress indicator; per-step form; skip and back controls; completion summary.
  • States: Loading — step content skeleton. Empty — first step with no prior data. Success — completion screen routing to Dashboard. Error — per-step validation errors; a failed save shows an inline retry without losing entered values. Recovery — the user can resume onboarding from the last incomplete step.
Page 7 of 50

Dashboard

  • Information/state: Authenticated overview. Metric row with tabular numerals: visits logged, follow-ups completed, follow-ups outstanding, average seconds to record. Recent visit records list. Recent follow-up ledger excerpt. Role-aware entry points.
  • Primary actions: Start a visit capture (→ Visit Capture); open a visit record (→ Visit Records); open the follow-up ledger (→ Follow-ups or My Follow-ups); open Execution (managers); open Analytics (managers).
  • Supporting actions: Filter metric range; dismiss a notice.
  • Domain entities: Visit record, Follow-up, Metric aggregate, User.
  • Component responsibilities: Metric row with count-up animation on first paint; ruled ledger rows with left-edge 3px status bars; empty-state panels; role-aware navigation.
  • States: Loading — metric skeletons and ledger row skeletons. Empty — first-run panels with a direct CTA to Visit Capture and a short explanation. Success — metrics and ledgers render. Error — per-panel inline notice with retry; other panels remain usable. Recovery — retry re-fetches only the failed panel.
Page 8 of 50

Visit Capture

  • Information/state: Focused recording workspace. Recording state with a breathing tangerine ring, live waveform, and a tabular 60-second timer. After recording: extracted fields (Account, Contact, Outcome, Next step, Sentiment, Products discussed) shown as editable inputs, plus the transcript.
  • Primary actions: Start recording; Stop recording; Re-record; Confirm and save record.
  • Supporting actions: Edit any extracted field; discard the draft; attach a photo.
  • Domain entities: Visit (account, contact, outcome, next step, sentiment, products, transcript, duration, captured_at), Follow-up (created from the record).
  • Component responsibilities: 72px round tangerine record button (the only fully-round element in the product); waveform visualiser; timer; extraction progress indicator; editable field list with per-field confidence hint; transcript panel.
  • States: Loading — microphone permission check and model warm-up indicator. Empty — pre-recording prompt with the record button. Success — extracted fields populated and the record saved; a confirmation shows the created record and any auto-assigned follow-ups. Error — microphone permission denied, network failure during upload, or extraction failure each show a distinct inline message with a retry; the audio is retained locally so the rep can retry without re-recording. Recovery — retry upload or extraction; manual entry fallback if extraction repeatedly fails.
Page 9 of 50

Visit Records

  • Information/state: Revisitable CRM-record workspace. Table of visit records with columns: date, account, contact, outcome, follow-up count, status. Detail view with all fields, transcript, and linked follow-ups.
  • Primary actions: Open a record; edit fields; create a follow-up from a record; delete a record.
  • Supporting actions: Search; filter by date, account, or status; sort columns.
  • Domain entities: Visit record, Follow-up, Account, Contact.
  • Component responsibilities: Real table with hairline row rules, right-aligned tabular numerals, no zebra striping; detail panel; edit form; delete confirmation.
  • States: Loading — table skeleton. Empty — "No visits recorded yet" with a CTA to Visit Capture. Success — rows render. Error — inline notice with retry. Recovery — retry re-fetches the list; a failed edit keeps the form open with the entered values.
Page 10 of 50

Follow-ups

  • Information/state: Workspace for creating and assigning follow-up work arising from visit records. Ruled ledger with columns: follow-up title, source visit, assignee, due date, status.
  • Primary actions: Create a follow-up; assign or reassign; set due date; mark complete; reopen.
  • Supporting actions: Filter by assignee, status, or due date; bulk assign.
  • Domain entities: Follow-up (title, description, source visit, assignee, due date, status), User.
  • Component responsibilities: Ledger rows with left-edge 3px status bars (tangerine = open, green = completed, muted = overdue); assignment control; due-date picker; bulk action bar.
  • States: Loading — ledger skeleton. Empty — "No follow-ups yet" with a CTA to create one or open Visit Capture. Success — rows render with correct status colours. Error — inline notice with retry; a failed assignment reverts the row and shows a message. Recovery — retry the failed action.
Page 11 of 50

My Follow-ups

  • Information/state: Focused recurring worklist for the signed-in rep. Rows: follow-up title, source account, due date, status.
  • Primary actions: Mark complete; reopen; open the source visit record.
  • Supporting actions: Sort by due date; filter by status.
  • Domain entities: Follow-up, Visit record, User.
  • Component responsibilities: Ledger scoped to the signed-in user; completion control; overdue emphasis via the muted status bar.
  • States: Loading — ledger skeleton. Empty — "You're all caught up" with a link to Visit Capture. Success — rows render. Error — inline notice with retry. Recovery — retry the failed completion.

Execution

  • Information/state: Manager-facing accountability view showing exactly what was completed and what remains outstanding after visits. Ledger grouped by rep, with per-rep completion counts and outstanding items.
  • Primary actions: Expand a rep's rows; open a visit record; reassign an outstanding follow-up; export the ledger.
  • Supporting actions: Filter by date range, rep, or status; sort by completion rate.
  • Domain entities: Follow-up, Visit record, User, Metric aggregate.
  • Component responsibilities: Ruled ledger with right-aligned tabular numerals; per-rep grouping; status bars; export control.
  • States: Loading — ledger skeleton. Empty — "No visits in this period" with a date-range suggestion. Success — ledger renders. Error — inline notice with retry. Recovery — retry re-fetches the ledger.
Page 12 of 50

Analytics

  • Information/state: Manager-facing analysis of visit and follow-up activity and completion trends. Charts: visits per day, completion rate over time, average seconds to record, follow-ups by status.
  • Primary actions: Change date range; change grouping (day/week/month); export a chart's data.
  • Supporting actions: Toggle series visibility; hover a data point for its exact value.
  • Domain entities: Metric aggregate, Visit record, Follow-up.
  • Component responsibilities: Charts using the tangerine accent for the single "completed this week" series and green for verified/completed states; tabular numerals in axis labels and tooltips; hairline chart frames.
  • States: Loading — chart skeletons. Empty — "Not enough data yet" with a note on the minimum period required. Success — charts render. Error — inline notice with retry. Recovery — retry re-fetches the selected range.
Page 13 of 50

Admin dashboard

  • Information/state: Protected workspace administration. Sections: users and roles, invitations, workspace configuration, integration status, audit log.
  • Primary actions: Invite a user; change a user's role; deactivate a user; edit workspace configuration; resend an invitation.
  • Supporting actions: Search users; filter by role or status; revoke an invitation.
  • Domain entities: User (name, email, role, status), Invitation (email, role, status), Workspace settings, Audit event.
  • Component responsibilities: User table with hairline rules; role selector; invitation form; configuration form; audit log list.
  • States: Loading — table and form skeletons. Empty — "No teammates yet" with an invite CTA. Success — tables and forms render. Error — inline notice with retry; a failed role change reverts and shows a message. Recovery — retry the failed action.
Page 14 of 50

Billing page

  • Information/state: Protected workspace billing destination reflecting the Stripe subscription. Shows current plan, billing interval, renewal date, payment method summary, and invoice history.
  • Primary actions: Change plan (→ Pricing page or Stripe checkout); open the Stripe customer portal; download an invoice.
  • Supporting actions: Update billing email; view past invoices.
  • Domain entities: Subscription (plan, status, interval, renewal date), Invoice (date, amount, status, download URL), Payment method (brand, last4).
  • Component responsibilities: Subscription summary with tabular numerals; invoice table with hairline rules; portal launch control.
  • States: Loading — summary and invoice skeletons. Empty — "No invoices yet" for a new subscription. Success — summary and invoices render. Error — if Stripe is unreachable, an inline notice with retry and a note that billing state may be stale. Recovery — retry re-fetches subscription state.
Page 15 of 50

User settings

  • Information/state: Authenticated user-level configuration. Sections: profile (name, email, avatar), preferences (theme: light/dark/system, default landing page, notification toggles), security (password change, connected Google account), and session management.
  • Primary actions: Save profile; change password; toggle theme; disconnect or connect Google; sign out other sessions.
  • Supporting actions: Cancel an edit; reset a section to its saved values.
  • Domain entities: User (name, email, avatar, theme preference, notification preferences), Session.
  • Component responsibilities: Sectioned form with per-section save; theme toggle that applies immediately; session list with revoke controls.
  • States: Loading — form skeletons. Empty — sections with no data show muted placeholders (for example, no avatar). Success — a saved confirmation appears per section. Error — inline field errors; a failed save keeps the entered values. Recovery — retry the save.

3. Functional Requirements

Each requirement is a distinct story point with provenance, lifecycle facts, and observable acceptance.

Page 16 of 50

Identity and Access

FR-1 — Self-service enrollment (required_inference) As a prospective user, I should create an account with my name, work email, and password, or continue with Google, so that I can begin using VisitLoop without an invitation.

  • Trigger: submission of the Sign Up form or the Google enrollment button.
  • Observable result: an account and a workspace are created; the user is routed to Onboarding.
  • Access state: anonymous.
  • Failure/recovery: invalid email, weak password, or an existing account shows an inline field error and retains entered values; a provider failure shows a banner with retry.
  • Continuation: successful enrollment proceeds to Onboarding.

FR-2 — Returning verification with Google Login (explicit) As a returning user, I should sign in with Google so that I can reach my workspace without entering a password.

  • Trigger: the Google Login button on Login.
  • Observable result: an authenticated session is established and the user is routed to the originally requested protected destination, or the Dashboard.
  • Access state: anonymous.
  • Failure/recovery: a provider error shows a banner with retry; the user can fall back to email sign-in.
  • Continuation: the user lands on the requested destination.
Page 17 of 50

FR-3 — Returning verification with Email Login (explicit) As a returning user, I should sign in with my email and password so that I can reach my workspace.

  • Trigger: submission of the Login form.
  • Observable result: an authenticated session is established and the user is routed to the originally requested protected destination, or the Dashboard.
  • Access state: anonymous.
  • Failure/recovery: invalid credentials show a message that does not disclose whether the email exists; the email is retained and the password cleared.
  • Continuation: the user lands on the requested destination.

FR-4 — First-run onboarding (required_inference) As a newly enrolled user, I should complete a short setup flow so that my workspace is configured before recurring visit work begins.

  • Trigger: first arrival at Onboarding after enrollment.
  • Observable result: workspace name, timezone, CRM destination preference, and default follow-up assignment rule are saved; the user is routed to the Dashboard.
  • Access state: authenticated.
  • Failure/recovery: per-step validation errors are shown inline; a failed save shows a retry without losing entered values; the user can resume from the last incomplete step.
  • Continuation: the Dashboard becomes the recurring entry point.
Page 18 of 50

FR-5 — Workspace authorization (required_inference) As a workspace member, I should have a role — Field Sales Rep, Sales Manager, or Workspace Administrator — so that I see the destinations and controls appropriate to my responsibilities.

  • Trigger: role assignment during onboarding or by an administrator.
  • Observable result: role-restricted destinations (Visit Capture, Visit Records, My Follow-ups for reps; Execution and Analytics for managers; Admin dashboard and Billing page for administrators) are reachable only by members holding the corresponding role.
  • Access state: authenticated with a role.
  • Failure/recovery: an unauthorized attempt shows a clear "not available for your role" state with a link back to the Dashboard.
  • Continuation: the user returns to a destination their role permits.
Page 19 of 50

Visit Capture and CRM Records

FR-6 — 60-second spoken recap (explicit) As a Field Sales Rep, I should speak for approximately 60 seconds after a visit so that the visit outcome is captured without typing.

  • Trigger: pressing the round record button on Visit Capture.
  • Observable result: recording begins with a breathing tangerine ring, a live waveform, and a tabular 60-second timer; stopping ends the recording and starts extraction.
  • Access state: authenticated, role Field Sales Rep.
  • Failure/recovery: microphone permission denied, network failure during upload, or extraction failure each show a distinct inline message with retry; the audio is retained locally so the rep can retry without re-recording.
  • Continuation: on success the rep reviews the extracted fields.

FR-7 — Automatic CRM record creation (explicit) As a Field Sales Rep, I should have VisitLoop create the CRM record from my spoken recap so that I do not have to fill in a form.

  • Trigger: completion of extraction after a recording.
  • Observable result: a visit record is created with Account, Contact, Outcome, Next step, Sentiment, Products discussed, transcript, duration, and captured_at; the fields are shown as editable inputs with per-field confidence hints.
  • Access state: authenticated, role Field Sales Rep.
  • Failure/recovery: if extraction fails, the rep can retry extraction or fall back to manual entry; the audio and transcript are preserved.
  • Continuation: the rep confirms and saves the record, or edits fields first.
Page 20 of 50

FR-8 — Follow-up assignment from a visit (explicit) As a Field Sales Rep, I should have follow-ups assigned from my visit record so that nothing is dropped.

  • Trigger: saving a visit record.
  • Observable result: one or more follow-ups are created and assigned according to the workspace's default assignment rule; the confirmation shows the created record and its assigned follow-ups.
  • Access state: authenticated, role Field Sales Rep.
  • Failure/recovery: if assignment fails, the record is still saved and the follow-ups appear unassigned in Follow-ups with an inline notice.
  • Continuation: the rep can open My Follow-ups to see the assigned work.

FR-9 — Review and update visit records (required_inference) As a Field Sales Rep, I should review and update the CRM records produced from my visit conversations so that the data stays reliable.

  • Trigger: opening Visit Records.
  • Observable result: a table of records with date, account, contact, outcome, follow-up count, and status; opening a record shows all fields, the transcript, and linked follow-ups; edits are saved.
  • Access state: authenticated, role Field Sales Rep.
  • Failure/recovery: a failed edit keeps the form open with entered values and shows an inline retry.
  • Continuation: the rep returns to the list or creates a follow-up from the record.
Page 21 of 50

Follow-up Execution

FR-10 — Create and assign follow-ups (required_inference) As a Field Sales Rep or Sales Manager, I should create and assign follow-up work arising from visit records so that post-visit commitments are owned.

  • Trigger: creating a follow-up from Follow-ups or from a visit record.
  • Observable result: a follow-up exists with title, description, source visit, assignee, due date, and status; the ledger row shows a left-edge status bar (tangerine = open, green = completed, muted = overdue).
  • Access state: authenticated, role Field Sales Rep or Sales Manager.
  • Failure/recovery: a failed assignment reverts the row and shows a message with retry.
  • Continuation: the assignee sees the item in My Follow-ups.

FR-11 — Complete assigned follow-ups (required_inference) As a Field Sales Rep, I should review and complete the follow-ups assigned to me so that no follow-up is dropped.

  • Trigger: opening My Follow-ups.
  • Observable result: a worklist scoped to the signed-in rep; marking an item complete sets its status to completed and turns its status bar green; reopening restores it to open.
  • Access state: authenticated, role Field Sales Rep.
  • Failure/recovery: a failed completion reverts the row and shows an inline retry.
  • Continuation: the rep continues down the list or opens the source visit record.
Page 22 of 50

Manager Accountability

FR-12 — Execution accountability view (explicit) As a Sales Manager, I should see exactly what was completed and what remains outstanding after visits so that I can hold the team accountable.

  • Trigger: opening Execution.
  • Observable result: a ruled ledger grouped by rep with per-rep completion counts and outstanding items, right-aligned tabular numerals, and status bars; the ledger can be filtered by date range, rep, or status, and exported.
  • Access state: authenticated, role Sales Manager.
  • Failure/recovery: an inline notice with retry; the rest of the ledger remains readable.
  • Continuation: the manager can open a visit record or reassign an outstanding follow-up.

FR-13 — Visit and follow-up analytics (explicit) As a Sales Manager, I should analyze visit and follow-up activity and completion trends so that I can see where execution is slipping.

  • Trigger: opening Analytics.
  • Observable result: charts for visits per day, completion rate over time, average seconds to record, and follow-ups by status; the date range and grouping (day/week/month) are adjustable; a chart's data can be exported.
  • Access state: authenticated, role Sales Manager.
  • Failure/recovery: an inline notice with retry; the selected range is preserved.
  • Continuation: the manager returns to Execution or the Dashboard.
Page 23 of 50

Workspace Administration and Billing

FR-14 — Workspace administration (explicit) As a Workspace Administrator, I should manage users, roles, invitations, and workspace configuration so that the account stays operational and correctly provisioned.

  • Trigger: opening the Admin dashboard.
  • Observable result: a user table with role and status; invitation creation and revocation; workspace configuration editing; integration status; an audit log of administrative actions.
  • Access state: authenticated, role Workspace Administrator.
  • Failure/recovery: a failed role change reverts and shows a message with retry.
  • Continuation: the administrator returns to the user table or configuration.

FR-15 — Subscription purchase (explicit) As a prospective or existing customer, I should subscribe to a VisitLoop plan through Stripe so that my workspace is provisioned at the right tier.

  • Trigger: choosing a plan on the Pricing page.
  • Observable result: an anonymous visitor is routed to Sign Up first; an authenticated user is taken to Stripe's hosted checkout; on completion the subscription state is reflected on the Billing page.
  • Access state: anonymous (routed to Sign Up) or authenticated.
  • Failure/recovery: a cancelled or failed checkout returns the user to the Pricing page with a clear message and no subscription change.
  • Continuation: the user lands on the Billing page or the Dashboard.
Page 24 of 50

FR-16 — Billing visibility and management (explicit) As a Workspace Administrator, I should see and manage the workspace subscription so that billing stays correct.

  • Trigger: opening the Billing page.
  • Observable result: current plan, billing interval, renewal date, payment method summary, and invoice history with download links; a control opens the Stripe customer portal for changes.
  • Access state: authenticated, role Workspace Administrator.
  • Failure/recovery: if Stripe is unreachable, an inline notice with retry and a note that billing state may be stale.
  • Continuation: the administrator returns to the Admin dashboard or the Dashboard.

User Configuration

FR-17 — User settings (explicit) As an authenticated user, I should configure my profile, preferences, and security so that the product fits how I work.

  • Trigger: opening User settings.
  • Observable result: profile fields save per section; the theme preference (light/dark/system) applies immediately; notification toggles persist; password change and Google account connection are available; other sessions can be signed out.
  • Access state: authenticated.
  • Failure/recovery: inline field errors; a failed save keeps entered values and offers retry.
  • Continuation: the user returns to the Dashboard or the previous destination.
Page 25 of 50

Cross-cutting Product Requirements

FR-18 — Responsive design (explicit) As any user, I should use VisitLoop on phone, tablet, and desktop so that I can capture a visit from the car and review execution from a desk.

  • Trigger: any page at 375px, 768px, or 1280px.
  • Observable result: layouts reflow — the app shell collapses to a bottom-anchored record button on mobile, the 3-column metric row stacks to one column, and the two-column lower area becomes a single column; headlines, labels, numbers, and controls stay entirely inside the viewport and their containers.
  • Access state: any.
  • Failure/recovery: not applicable.
  • Continuation: not applicable.

FR-19 — Dark mode (explicit) As any user, I should switch between light and dark mode so that the product is comfortable in a car at night and in an office.

  • Trigger: the theme control in User settings, or the system preference when set to "system".
  • Observable result: the ground inverts to graphite #141517 with #1C1E21 surfaces and #F2EFE9 text; the tangerine and green accents are unchanged between modes.
  • Access state: any.
  • Failure/recovery: not applicable.
  • Continuation: the preference persists across sessions.
Page 26 of 50

FR-20 — SEO (explicit) As a prospective customer, I should find VisitLoop through search so that I can evaluate it.

  • Trigger: a search engine crawl of the public Landing page and Pricing page.
  • Observable result: semantic headings, descriptive titles and meta descriptions, canonical URLs, structured data for the product and FAQ, and a sitemap covering the public pages.
  • Access state: anonymous.
  • Failure/recovery: not applicable.
  • Continuation: not applicable.

FR-21 — Error handling (explicit) As any user, I should see a clear, actionable message when something fails so that I can recover without losing work.

  • Trigger: any failed request, validation error, or provider failure.
  • Observable result: inline notices scoped to the failing panel or field, with a retry control where retry is meaningful; entered values are preserved.
  • Access state: any.
  • Failure/recovery: this requirement is the recovery behavior.
  • Continuation: the user retries or continues with the unaffected parts of the page.
Page 27 of 50

FR-22 — Loading states (explicit) As any user, I should see a loading indication while data is being fetched so that I know the product is working.

  • Trigger: any data fetch or long-running action.
  • Observable result: skeletons for lists, tables, and charts; inline spinners on submit buttons with the button disabled; a progress indicator during extraction.
  • Access state: any.
  • Failure/recovery: a loading state that exceeds a reasonable threshold transitions to the error state with retry.
  • Continuation: the loaded content replaces the skeleton.

FR-23 — REST APIs (explicit) As a client of VisitLoop, I should interact with the product through REST APIs so that the frontend and any future integrations use one consistent contract.

  • Trigger: any frontend data operation.
  • Observable result: versioned REST endpoints for authentication, visits, follow-ups, analytics, workspace administration, and billing; consistent JSON error envelopes with machine-readable codes.
  • Access state: authenticated for protected endpoints; anonymous for public plan and marketing data.
  • Failure/recovery: standard HTTP status codes with actionable error bodies.
  • Continuation: not applicable.
Page 28 of 50

FR-24 — Database and schema (explicit) As the product owner, I should have a relational database with a defined schema so that visit records, follow-ups, completion state, analytics, workspace administration, and billing state persist reliably.

  • Trigger: any write operation.
  • Observable result: tables for users, workspaces, memberships, invitations, visits, follow-ups, subscriptions, invoices, and audit events, with foreign keys and indexes supporting the ledger and analytics queries.
  • Access state: not applicable.
  • Failure/recovery: transactional writes; a failed write rolls back and surfaces an error to the caller.
  • Continuation: not applicable.

FR-25 — Deployment configuration, environment variables, README, and sample data (explicit) As the operator, I should have deployment configuration, documented environment variables, a README, and sample data so that the product can be run and evaluated.

  • Trigger: running the project locally or deploying it.
  • Observable result: a container composition defining the runnable services; an environment variable reference covering database, authentication providers, Stripe, and AI extraction credentials; a README covering setup, run, and deploy; seed data producing a workspace with sample visits and follow-ups.
  • Access state: not applicable.
  • Failure/recovery: missing required environment variables produce a clear startup error naming the missing variable.
  • Continuation: not applicable.
Page 29 of 50

FR-26 — Production readiness, review, and refactoring (explicit) As the product owner, I should have a production-ready, reviewed, refactored codebase following best practices so that the product can be operated with confidence.

  • Trigger: the review and refactor pass.
  • Observable result: identified bugs fixed; UI, UX, mobile responsiveness, performance, accessibility, animations, dashboard, pricing page, onboarding, empty states, and loading states improved; code refactored to follow best practices; the result remains production-ready.
  • Access state: not applicable.
  • Failure/recovery: not applicable.
  • Continuation: not applicable.

FR-27 — 20 AI feature recommendations (explicit) As the product owner, I should receive 20 AI feature recommendations that would significantly increase the value of VisitLoop, each with problem solved, user benefit, AI model recommendation, technical implementation, and difficulty, so that I can plan the product's AI roadmap.

  • Trigger: delivery of the recommendation set.
  • Observable result: a documented set of 20 features, each carrying all five required fields.
  • Access state: not applicable.
  • Failure/recovery: not applicable.
  • Continuation: not applicable.

4. User Personas

Page 30 of 50

Field Sales Rep

Product context. The rep is the primary in-product actor and the origin of every visit record. They work one-handed, often in a car immediately after leaving a customer site, and they log dozens of visits a day. Their tolerance for typing is near zero; their tolerance for a dropped follow-up is also near zero, because a dropped follow-up is a lost deal.

Primary goal. Capture what happened in a visit in about 60 seconds, without typing, and complete every follow-up assigned to them.

Distinct accepted responsibilities. Recording the ~60-second spoken recap on Visit Capture; reviewing and correcting the extracted CRM fields before saving; reviewing and updating the resulting visit records in Visit Records; creating follow-ups from a record when the extraction did not capture one; and completing the follow-ups assigned to them in My Follow-ups.

Relevant inputs and decisions. The spoken recap itself; the extracted Account, Contact, Outcome, Next step, Sentiment, and Products discussed fields, each of which the rep may edit; the decision to confirm and save a record or re-record; and the decision to mark a follow-up complete or reopen it.

Interactions with other accepted participants. The rep's saved record and its follow-ups become the raw material the Sales Manager reads in Execution and Analytics. The rep's role and workspace configuration are set by the Workspace Administrator. The rep does not see the manager's accountability ledger or the administrator's configuration surfaces.

Observable success. No visit goes unrecorded, and no follow-up assigned to the rep is dropped. Success is visible as a growing count of visits logged and a shrinking count of open items in My Follow-ups.

Page 31 of 50

Sales Manager

Product context. The manager consumes the accountability layer. They are not in the field; they read completion telemetry and need to know, at a glance, which visits produced follow-ups and which follow-ups actually got done. They scan dense ledgers rather than browsing cards.

Primary goal. Reliable visibility into completed versus outstanding post-visit work across the team.

Distinct accepted responsibilities. Reading the Execution ledger grouped by rep; filtering and exporting it; opening individual visit records to understand context; reassigning an outstanding follow-up; and analyzing visit and follow-up trends in Analytics across adjustable date ranges and groupings.

Relevant inputs and decisions. The date range and grouping selected in Analytics; the rep or status filter applied in Execution; and the decision to reassign an outstanding follow-up to a different rep.

Interactions with other accepted participants. The manager reads records and follow-ups created by Field Sales Reps and can reassign work between them. The manager's own role and access are provisioned by the Workspace Administrator. The manager does not capture visits and does not administer the workspace.

Observable success. The manager can state, without asking anyone, exactly what was completed after each visit and what remains outstanding, and can see whether completion is trending up or down.

Page 32 of 50

Workspace Administrator

Product context. The administrator keeps the account operational. They are the person who onboards teammates, fixes access problems, and makes sure the workspace is on the right plan and correctly billed. They are the only role that touches billing and workspace configuration.

Primary goal. A healthy, correctly provisioned, correctly billed workspace with appropriate user access.

Distinct accepted responsibilities. Inviting users and assigning roles in the Admin dashboard; deactivating users and revoking invitations; editing workspace configuration and reviewing integration status; reading the audit log; and viewing and managing the subscription on the Billing page, including opening the Stripe customer portal.

Relevant inputs and decisions. The email and role for each invitation; the decision to change a user's role or deactivate them; workspace configuration values such as the default follow-up assignment rule and CRM destination preference; and the decision to change plans.

Interactions with other accepted participants. The administrator provisions the roles that determine what Field Sales Reps and Sales Managers can reach, and configures the default assignment rule that governs how follow-ups are created from a rep's visit record. The administrator does not capture visits or read the manager's execution ledger as part of their administrative responsibility.

Observable success. Every teammate has the correct access, the workspace configuration matches how the team actually works, and the subscription state on the Billing page matches what the team is paying for.

5. Core User Flows

Page 33 of 50

Flow 1 — A rep enrolls and sets up their workspace

  1. The rep arrives on the Landing page and reads the hero: "Your reps already said what happened. VisitLoop just writes it down." They click the tangerine "Start free" link.
  2. They land on Sign Up and choose to continue with Google. Google verifies them and returns them to VisitLoop.
  3. VisitLoop creates their account and a workspace, and routes them to Onboarding.
  4. On Onboarding, the rep confirms the workspace name and timezone, skips the teammate-invitation step, selects their CRM destination preference, and accepts the default follow-up assignment rule ("assign to the rep who captured the visit").
  5. They finish setup and land on the Dashboard, which shows first-run empty panels with a direct CTA to Visit Capture.
  6. Failure/recovery: if the Google enrollment fails, the Sign Up page shows a banner with a retry and the email form remains available as a fallback. If a step's save fails during onboarding, the entered values are retained and an inline retry is offered; the rep can resume from the last incomplete step later.
Page 34 of 50

Flow 2 — A rep captures a visit in 60 seconds

  1. The rep is in the car after a customer visit. They open Visit Capture on their phone.
  2. They press the 72px round tangerine record button. A breathing tangerine ring appears, a live waveform animates, and a tabular 60-second timer starts.
  3. They speak for about 60 seconds: who they met, what was discussed, what the customer said, and what happens next.
  4. They press stop. The recording ends and extraction begins; a progress indicator shows while the transcript is processed.
  5. The extracted fields appear as editable inputs — Account, Contact, Outcome, Next step, Sentiment, Products discussed — each with a confidence hint, alongside the transcript.
  6. The rep corrects the Account name, which the model misheard, and leaves the rest as extracted.
  7. They press "Confirm and save record." VisitLoop creates the visit record and, per the workspace's default assignment rule, creates and assigns a follow-up to the rep.
  8. The confirmation shows the created record and its assigned follow-up, with a link to My Follow-ups.
  9. Failure/recovery: if the microphone permission is denied, the page explains how to grant it and offers manual entry. If the upload fails, the audio is retained locally and a retry control appears without requiring a re-record. If extraction fails, the rep can retry extraction or fall back to manual entry; the transcript is preserved either way.
Page 35 of 50

Flow 3 — A rep completes assigned follow-ups

  1. The rep opens My Follow-ups from the Dashboard or the app shell.
  2. They see a ledger of their assigned follow-ups with source account, due date, and status; overdue items carry a muted status bar.
  3. They open the top item, read the source visit record's context, make the call, and return to the worklist.
  4. They mark the item complete. Its status bar turns green and the open count on the Dashboard decreases.
  5. They continue down the list until it is empty, at which point the worklist shows "You're all caught up" with a link back to Visit Capture.
  6. Failure/recovery: if a completion fails to save, the row reverts to open and an inline retry appears; the rep can retry immediately or continue with other items.
Page 36 of 50

Flow 4 — A manager reviews execution accountability

  1. The manager opens Execution from the Dashboard.
  2. They see a ruled ledger grouped by rep, with per-rep completion counts and outstanding items, right-aligned tabular numerals, and left-edge status bars (tangerine = open, green = completed, muted = overdue).
  3. They filter to the last 7 days and sort by completion rate. One rep's outstanding count stands out.
  4. They expand that rep's rows, open a specific visit record to read the transcript and the extracted next step, and decide the follow-up needs a different owner.
  5. They reassign the follow-up to another rep. The row updates and the new assignee sees it in My Follow-ups.
  6. They export the ledger for the weekly review.
  7. Failure/recovery: if the ledger fails to load, an inline notice with retry appears and the rest of the page remains usable. If the reassignment fails, the row reverts and a message with retry is shown.

Flow 5 — A manager analyzes trends

  1. The manager opens Analytics.
  2. They see charts for visits per day, completion rate over time, average seconds to record, and follow-ups by status, with the "completed this week" series in tangerine and verified/completed states in green.
  3. They change the date range to the last quarter and the grouping to week.
  4. They hover a data point to read its exact value in tabular numerals.
  5. They notice completion rate dipped in one week and export that chart's data to share with the team.
  6. Failure/recovery: if the selected range has insufficient data, the page shows "Not enough data yet" with a note on the minimum period required, rather than an empty chart frame.
Page 37 of 50

Flow 6 — An administrator provisions the team

  1. The administrator opens the Admin dashboard.
  2. They invite three teammates by email, assigning two the Field Sales Rep role and one the Sales Manager role.
  3. They edit the workspace configuration to change the default follow-up assignment rule so that follow-ups from enterprise accounts go to the manager for triage.
  4. They review the audit log to confirm the changes were recorded.
  5. Failure/recovery: if an invitation fails to send, the row shows a failed status with a resend control. If a role change fails, the row reverts and a message with retry appears.

Flow 7 — An administrator subscribes and manages billing

  1. The administrator opens the Pricing page and compares plans, toggling between monthly and annual.
  2. They choose a plan. Because they are authenticated, they are taken to Stripe's hosted checkout.
  3. They complete payment on Stripe and are returned to VisitLoop.
  4. They land on the Billing page, which shows the current plan, billing interval, renewal date, payment method summary, and an empty invoice history with a note that the first invoice will appear after the billing period closes.
  5. Later, they return to the Billing page, open the Stripe customer portal, and change the plan. The Billing page reflects the new plan on return.
  6. Failure/recovery: if checkout is cancelled or fails, they return to the Pricing page with a clear message and no subscription change. If the Billing page cannot reach Stripe, it shows an inline notice with retry and a note that the displayed state may be stale.
Page 38 of 50

Flow 8 — A user configures their settings

  1. The user opens User settings.
  2. They update their display name and save the profile section; a per-section confirmation appears.
  3. They switch the theme to dark. The ground inverts to graphite immediately, with the tangerine and green accents unchanged.
  4. They toggle off a notification type and save the preferences section.
  5. They review their active sessions and sign out a session on a device they no longer use.
  6. Failure/recovery: if a save fails, the entered values are retained and an inline retry is offered.

6. Visuals, Colors, and Theme

The creative direction is authoritative for this section.

Muse: Rasmus Andersson. Headline register: systematic product craft with an opinion — warm paper ground, one hot tangerine accent, tabular numerals as ornament.

Page 39 of 50

Color tokens

Light mode

RoleHexUsage
Background#F6F3EEWarm paper ground; carries ~70% of every screen
Surface#FFFDF9Cards and panels
Hairline#E4DFD61px structural borders; the only separation mechanism
Text#141517All readable ink
Primary#E8552BTangerine — the only hot colour; rationed to ≤8% of a viewport
Accent#1F6F4ADeep green — completed/verified states only
Muted#8A857CMetadata, timestamps, tabular labels

Dark mode

RoleHexUsage
Background#141517Graphite ground
Surface#1C1E21Cards and panels
Hairline#2A2D311px structural borders
Text#F2EFE9All readable ink
Primary#E8552BUnchanged between modes
Accent#1F6F4AUnchanged between modes
Muted#8A857CUnchanged

Tangerine is never placed as text on tangerine. Status is never carried by tangerine alone — green always accompanies a completed/verified state.

Page 40 of 50

Typography

  • Headings: Inter Tight, tracking −0.02em to −0.04em, weights 500–600 only. Never 800/900. Sentence case.
  • Body: Inter Tight.
  • Numerals: JetBrains Mono with font-variant-numeric: tabular-nums for every figure that updates — visit counts, completion percentages, streaks, latency, timers.
  • Micro-labels: 11px uppercase, +0.08em tracking, muted.

Type scale (1.25 modular on a 4px baseline):

TokenSize
Displayclamp(44px, 7vw, 96px), line-height 1.05
H132px → 56px
H224px → 36px
H318px → 22px
Body15px / 24px
Small13px / 20px
Micro-label11px / 16px, uppercase, +0.08em

Line-height tightens as size grows: 1.05 at display, 1.5 at body.

Shape language

Honest rectangles with a small radius: 6px on controls, 10px on cards, 999px only on the single record button. No blobs, no glass, no soft-focus shadows. Separation is done with 1px hairlines and background value shifts. Borders are structural, not decorative.

Page 41 of 50

Layout

Strict 4/8pt spacing scale on a 12-column grid, max content width 1200px, gutters 24px at 1280, 16px at 768, 12px at 375. The app shell is a fixed 56px left icon rail (labels appear on hover and at ≥1280) plus a 240px contextual panel; the working area is a single dense column, not a card grid. The landing page uses asymmetric editorial columns: text column 5/12, product surface 7/12 bleeding off the right edge. Every table is a real table: aligned label/value pairs, tabular numerals right-aligned, hairline row rules, no zebra striping.

Imagery

The interface is the imagery. The landing page shows real product surfaces — the voice-capture sheet, the extracted CRM record with fields highlighting as they fill, the manager completion ledger — rendered as crisp screenshots on the paper ground with a hairline frame, occasionally cropped by the viewport edge. Supporting diagrams are schematic: a 3-node flow from "spoke" → "structured record" → "assigned follow-up" drawn in 1px strokes with tangerine on the active node. No stock photography of handshakes, no 3D blobs, no abstract gradients.

Page 42 of 50

7. Signature Design Concept

The hero is a working product surface, not a screenshot.

The public entry is a split asymmetric hero on the warm paper ground. The left 5 columns carry an oversized Inter Tight headline at clamp(44px, 7vw, 96px), set tight and quiet: "Your reps already said what happened. VisitLoop just writes it down." Beneath it sits a single tangerine text-link CTA ("Start free") and a muted 13px supporting line. No gradient, no blob, no centred stack, no blue button.

The right 7 columns are the product itself: a 1:1 rendering of the voice-capture sheet mid-recording, bleeding off the right viewport edge so it is cropped by the browser rather than contained in a card. Inside it, a live tangerine waveform animates, and beside it three extracted CRM fields — Account, Outcome, Next step — type themselves in as the waveform plays, with tabular numerals counting a 60-second timer. The loop runs on a 6-second cycle.

The gesture is carried entirely by imagery and motion: the capture sheet is cropped by the viewport edge, but every readable label, field name, and control inside it stays whole and inside its container at 375px, 768px, and 1280px. At narrow widths the hero stacks — headline first, then the capture sheet at full width — and the sheet's own contents reflow rather than shrink below legibility.

8. Interaction Model & Motion Direction

Interaction Model: Animated Motion Tempo: restrained Hero Dimensionality: flat

Page 43 of 50

Landing Hero Motion Brief

Focal subject. The voice-capture sheet mid-recording, bleeding off the right viewport edge, with a live tangerine waveform and three extracted CRM fields filling in beside it.

Input → transformation → outcome thesis. The waveform plays (input) → the three extracted fields type themselves in one after another (transformation) → the 60-second timer reaches its mark and the record is shown as saved (outcome). The loop demonstrates the product's defining act — speech becoming structured CRM data — using only accepted behavior.

Motion vocabulary. Functional 120–200ms on cubic-bezier(0.2, 0, 0, 1) for state changes. The waveform breathes at 1.4s intervals because that motion carries meaning: you are being recorded. Field text types in at a steady cadence. Numbers count up in 400ms on first paint and never re-animate on scroll. Section reveals are opacity + 8px translate, staggered 40ms, once.

Composed first frame. The capture sheet is already mid-recording at first paint — waveform active, timer at a nonzero value, the first extracted field partially typed. The headline sits fully rendered and still. Nothing waits for scroll to begin.

Reduced-motion state. With prefers-reduced-motion, the waveform renders as a static tangerine amplitude bar, the three extracted fields appear fully populated, and the timer shows its final value. The capture sheet remains cropped by the viewport edge as a static composition. No element moves, and every readable label and control remains whole and inside its container.

Page 44 of 50

9. Non-Functional Requirements

NFR-1 — Production readiness (explicit) The system must be production-ready: real error handling, real loading states, real persistence, and no placeholder behavior in shipped paths. Rationale: explicit user constraint.

NFR-2 — Best practices and refactoring (explicit) The codebase must follow best practices and be refactored, with identified bugs fixed. Rationale: explicit user constraint.

NFR-3 — Modern design register (explicit) The design must be modern in the register of Linear, Notion, and Vercel, expressed through the creative direction in Sections 6–8. Rationale: explicit user constraint plus authoritative creative direction.

NFR-4 — Responsive design (explicit) The product must be responsive across 375px, 768px, and 1280px. Readable text and controls must stay entirely inside the viewport and their containers at every breakpoint. Rationale: explicit user constraint.

NFR-5 — Dark mode (explicit) The product must support dark mode with the token mapping in Section 6. Rationale: explicit user constraint.

NFR-6 — SEO (explicit) Public pages must be search-engine optimized with semantic markup, metadata, structured data, and a sitemap. Rationale: explicit user constraint.

NFR-7 — Error handling (explicit) Every failure path must produce a clear, actionable message with a recovery route where recovery is possible, and must not discard user-entered data. Rationale: explicit user constraint.

Page 45 of 50

NFR-8 — Loading states (explicit) Every data fetch and long-running action must show a loading indication. Rationale: explicit user constraint.

NFR-9 — Accessibility (explicit) The product must be accessible: keyboard-operable controls, visible focus states, sufficient contrast, semantic landmarks, and a usable reduced-motion arrangement. Rationale: explicit user constraint ("Improve ... accessibility").

NFR-10 — Performance (explicit) The product must perform well: fast first paint on the landing page, responsive interaction on dense ledgers, and no unnecessary re-renders or re-animations. Rationale: explicit user constraint ("Improve ... performance").

NFR-11 — Mobile responsiveness for field use (explicit) The capture experience must be usable one-handed on a phone, with the record button reachable at the bottom-right of the mobile shell. Rationale: explicit user constraint plus the product's stated field context.

NFR-12 — Animations (explicit) Animations must be functional and restrained, per Section 8, and must respect prefers-reduced-motion. Rationale: explicit user constraint plus authoritative creative direction.

NFR-13 — Empty states (explicit) Every list, table, and chart must have a designed empty state with a clear next action. Rationale: explicit user constraint ("Improve ... empty states").

NFR-14 — Onboarding quality (explicit) Onboarding must be short, resumable, and skippable per step. Rationale: explicit user constraint ("Improve ... onboarding").

Page 46 of 50

NFR-15 — Data integrity (required_inference) Writes affecting visit records, follow-ups, and subscription state must be transactional so that a partial failure cannot leave a record without its follow-ups or a workspace with an inconsistent subscription state. Rationale: required to make the accepted accountability outcome reliable.

NFR-16 — Audio retention on failure (required_inference) Recorded audio must be retained locally until the record is successfully saved, so that a network or extraction failure does not force a re-record. Rationale: required to make the accepted 60-second capture lifecycle recoverable.

10. Tech Stack

  • Frontend: React with a modern component architecture, responsive layouts, and dark mode via the token system in Section 6.
  • Backend: Python with FastAPI, exposing the REST APIs in FR-23 and hosting the AI extraction pipeline.
  • Database: A relational database with the schema described in FR-24, supporting the ledger and analytics queries.
  • Authentication: Application-owned identity with Google OAuth and email/password, per FR-1 through FR-3.
  • Billing: Stripe subscriptions with hosted checkout and the Stripe customer portal, per FR-15 and FR-16.
  • AI extraction: A speech-to-structured-data pipeline invoked by the backend after a recording, per FR-7.
  • Deployment: Docker and docker-compose defining the runnable services, with environment variable configuration per FR-25.
Page 47 of 50

11. Assumptions and Constraints

Assumptions

  • A-1 (required_inference) — Self-service enrollment is the entry path because no invitation, provisioning, or pre-existing-account boundary is established for users beginning to use the SaaS.
  • A-2 (required_inference) — A workspace is created automatically on first enrollment, since the product's data (visits, follow-ups, configuration, billing) is workspace-scoped.
  • A-3 (required_inference) — The three roles (Field Sales Rep, Sales Manager, Workspace Administrator) are the minimum set needed to make the explicitly requested Dashboard, Admin dashboard, and Billing page reachable by an appropriate actor.
  • A-4 (required_inference) — The default follow-up assignment rule is configurable by the administrator, because FR-8 requires assignment to happen automatically and FR-14 gives the administrator workspace configuration responsibility.
  • A-5 (required_inference) — Audio is retained locally until a record is saved, per NFR-16.
  • A-6 — The 20 AI feature recommendations (FR-27) are a documented deliverable, not additional product surfaces in the current build.

Constraints

Page 48 of 50
  • C-1 (explicit) — Everything must be production-ready.
  • C-2 (explicit) — The codebase must follow best practices, be refactored, and be free of identified bugs.
  • C-3 (explicit) — The design must be modern, in the register of Linear, Notion, and Vercel.
  • C-4 (explicit) — The product must be responsive and support dark mode.
  • C-5 (explicit) — The product must include SEO, error handling, and loading states.
  • C-6 (creative direction) — The generic indigo/blue-on-white SaaS template is forbidden. Tangerine #E8552B is the only hot colour and is rationed to ≤8% of a viewport. Blue and indigo primaries (#0057FF, #2563EB, #4F46E5 and neighbours) are excluded. Plain Inter, Roboto, Arial, Helvetica, Open Sans, Lato, Poppins, and system-ui are excluded in favour of Inter Tight and JetBrains Mono. Gradient-blob heroes, mesh gradients, glassmorphism, frosted panels, drop shadows for elevation, stock photography of handshakes or smiling teams, bouncy or springy easing, and decorative loops that carry no state are all excluded. Only the record button is fully round.
  • C-7 (creative direction) — Readable text and controls stay whole at every viewport. Imagery, decoration, and motion may be cropped, bled off an edge, or overlapped, but must never cover readable text or a control.
Page 49 of 50

12. Glossary

  • VisitLoop — The product: a post-visit execution layer for field sales teams.
  • Field visit — A rep's in-person meeting with a customer or prospect.
  • Recap — The approximately 60-second spoken recording a rep makes after a field visit.
  • Visit record — The structured CRM record created from a recap, containing Account, Contact, Outcome, Next step, Sentiment, Products discussed, transcript, duration, and captured_at.
  • Follow-up — A unit of post-visit work created from a visit record, with a title, description, source visit, assignee, due date, and status.
  • Execution ledger — The manager-facing ruled ledger showing exactly what was completed and what remains outstanding after visits.
  • Status bar — The 3px left-edge indicator on a ledger row: tangerine = open, green = completed, muted = overdue.
  • Workspace — The account-scoped container for users, visits, follow-ups, configuration, and billing.
  • Role — One of Field Sales Rep, Sales Manager, or Workspace Administrator.
  • Extraction — The AI process that turns a recap's audio and transcript into structured visit-record fields.
  • Tabular numerals — Figures set in JetBrains Mono with font-variant-numeric: tabular-nums so columns of numbers align and can be scanned like a bank statement.
Page 50 of 50
Landing page design preview
Landing page: Start free
Sign Up: Continue with Google
Onboarding: Confirm workspace name and timezone
Onboarding: Skip teammate invitations
Onboarding: Select CRM destination preference
Onboarding: Accept default assignment rule
Onboarding: Finish setup
Dashboard: Open Visit Capture
Visit Capture: Start recording
Visit Capture: Stop recording
Visit Capture: Edit extracted Account field
Visit Capture: Confirm and save record
Visit Capture: Retry upload
Visit Capture: Retry extraction
Visit Capture: Enter fields manually
Visit Records: Open a record
Visit Records: Edit fields
Visit Records: Create follow-up from record
Follow-ups: Create follow-up
Follow-ups: Assign follow-up
My Follow-ups: Open source visit record
My Follow-ups: Mark complete
My Follow-ups: Reopen follow-up
User settings: Toggle theme
User settings: Save profile
Landing page design preview
Landing page: Start free
Sign Up: Continue with Google
Onboarding: Confirm workspace name and timezone
Onboarding: Skip teammate invitations
Onboarding: Select CRM destination preference
Onboarding: Accept default assignment rule
Onboarding: Finish setup
Dashboard: Open Visit Capture
Visit Capture: Start recording
Visit Capture: Stop recording
Visit Capture: Edit extracted Account field
Visit Capture: Confirm and save record
Visit Capture: Retry upload
Visit Capture: Retry extraction
Visit Capture: Enter fields manually
Visit Records: Open a record
Visit Records: Edit fields
Visit Records: Create follow-up from record
Follow-ups: Create follow-up
Follow-ups: Assign follow-up
My Follow-ups: Open source visit record
My Follow-ups: Mark complete
My Follow-ups: Reopen follow-up
User settings: Toggle theme
User settings: Save profile