Skip to content

PRD: Lead & subscriber capture

ModuleMarketingPRD IDPRD-CAP-001
StatusReady to devFEATCAP
EpicPlaneBANA-1510
Date2026-04-03Versionv1.1
Packages@nx/outreachURDCAP
SurfaceBO · Ops
OwnerPhát Nguyễn

TL;DR

Lets the public marketing site collect leads - consult/contact/sales/demo/partner inquiries and newsletter subscribers. Subscribe is idempotent by email, unsubscribe is honored via a one-click token, and every new inquiry notifies our operations team (NEXPANDO & VNPAY) in real time - a clean, opt-out-respecting audience ready for the Phase 2 campaigns. The back-office read (subscriber list + statistics) is specified in PRD-SUB-001.

1. Context & Problem

Merchants want to grow an audience from their public site - visitors who request a demo, contact sales, or opt into the newsletter. Without a capture surface those signals are lost or scattered: no deduplicated list, no enforced unsubscribe, no read on how the audience is growing. That gap blocks any future outbound campaign, which depends on a clean, opt-out-respecting base.

This feature lays the capture foundation: it records inquiries and newsletter opt-ins from the public site, keeps the subscriber list idempotent and opt-out-safe, and notifies the operations team the moment a new lead arrives.

2. Goals & Non-Goals

Goals

  • Capture inquiries from the public site with 5 types (consult, contact, sales, demo, partner), with a real-time notification to the operations team.
  • Make newsletter subscribe idempotent by email - re-subscribing reactivates a previously unsubscribed record rather than duplicating it.
  • Honor token-based unsubscribe before any reactivation or send.

Non-Goals

  • The back-office subscriber list and statistics - specified in PRD-SUB-001 (single source).
  • Working inquiries in the back office (assign, reply, convert) - specified in PRD-CAP-002.
  • Campaigns, drip automation, and A/B testing - owned by Campaigns & Automation (CMP, P2).
  • Email/SMS delivery infrastructure - provided by external providers.
  • Promotional pricing - owned by the Campaign module.

3. Success Metrics

MetricTarget / signal
DeduplicationZero duplicate active subscribers per email
Opt-out integrityEvery unsubscribe token resolves to a deactivated record; no send to deactivated subscribers
Capture latencyInquiry submit → operations-team notification is near real-time

4. Personas & Use Cases

PersonaGoal in this feature
VisitorSubmit an inquiry or subscribe to the newsletter from the public site
SubscriberUnsubscribe at any time via a one-click token link
Operations team (NEXPANDO & VNPAY)Be told the moment a new inquiry arrives, to respond quickly

Core scenario: a visitor submits an inquiry (operations team notified in real time) or subscribes to the newsletter (idempotent by email) → a subscriber later clicks the unsubscribe link (token-resolved, deactivated) → a previously opted-out address subscribes again and is reactivated, with no duplicate.

5. User Stories

  • As a visitor, I want to submit a consult/contact/sales/demo/partner inquiry from the public site, so the business can follow up.
  • As a visitor, I want to subscribe to the newsletter with my email, so I receive updates - and subscribing twice never creates a duplicate.
  • As a subscriber, I want to unsubscribe via a token link, so I stop receiving messages.
  • As a previously-unsubscribed visitor, I want re-subscribing to reactivate my record, so I rejoin without a duplicate entry.
  • As the operations team, I want a real-time notification when an inquiry arrives, so we can respond quickly.

6. Functional Requirements

#RequirementStatusURD ref
FR-1Capture an inquiry from the public site - a full form with fields and validation (detailed below)✅ builtURD-CAP-001
FR-2Newsletter subscribe is idempotent by email; an active email returns the existing record, no duplicate✅ builtURD-CAP-002
FR-3Re-subscribing a previously unsubscribed email reactivates it (subscribe timestamp reset, unsubscribe timestamp cleared, status set to active)✅ builtURD-CAP-002
FR-4Token-based unsubscribe resolves a subscriber by their token and deactivates it; an invalid token is rejected✅ builtURD-CAP-003
FR-5Back-office read of the subscriber list and statistics - specified, with build status, in PRD-SUB-001 (single source; this PRD does not restate it)-URD-CAP-004
FR-6A new inquiry submission emits a real-time notification to the operations team✅ builtURD-CAP-001

FR-1 - Inquiry capture (public form)

FieldRequiredRule
Inquiry typeOne of 5: Consult · Contact · Sales · Demo · Partner
First nameMust not be empty
Last name-
EmailValid email format
PhoneValid phone format
Business name-
Business type-
Location count-Free entry
Estimated revenue-Free entry
Subject-
Message-Multiline
  • The form is open to anonymous visitors - no sign-in required.
  • A new inquiry enters the system with status New and appears immediately in the operations team's workbench (PRD-CAP-002).

FR-2 / FR-3 - Newsletter subscribe (idempotent)

The public newsletter form collects: email (required, valid format), topics of interest (optional), preferred language (optional - Vietnamese / English).

Idempotency rules, by email:

  • Email not seen before → create a new subscriber (status active) with a unique unsubscribe token.
  • Email already active → return the existing record; no duplicate, no error.
  • Email previously unsubscribed → reactivate: reset the subscribe timestamp to now, clear the unsubscribe timestamp, set status to active.

FR-4 - Token-based unsubscribe

  • The unsubscribe link carries a unique, hard-to-guess token issued at sign-up; one click deactivates - no sign-in needed.
  • An invalid token → rejected as not-found; no subscriber information is revealed.
  • A deactivated record is honored before any future send (constraint C-01).

FR-6 - Real-time notification

  • When a new inquiry is submitted from the public site, operations users with the Back Office open see it immediately: the menu badge increments (counting New + In review inquiries) and a toast notification appears - no page reload.

Acceptance criteria

  1. Submitting the inquiry form with First name, Email, Phone, or Type missing → a field-level error, nothing recorded.
  2. A malformed email or phone number on the inquiry form → a field-level error.
  3. A valid inquiry submission → the inquiry appears in the Back Office list with status New; the badge and toast fire for operators online.
  4. Subscribing the same email twice in a row → exactly one active record exists.
  5. Re-subscribing a previously unsubscribed email → the record is reactivated (active status, fresh subscribe timestamp, unsubscribe timestamp cleared) - no second record.
  6. Clicking a valid unsubscribe link → the record deactivates on the first click.
  7. Opening an unsubscribe link with an invalid token → a not-found response.

7. Non-Functional Requirements

AreaRequirement
Data integritySubscribe is idempotent by email - one active record per email
Opt-out integrityUnsubscribe is honored before any reactivation or send; deactivation is via token only
TenancyCapture data is global (not confined to a single merchant) per module constraint C-02
AuthzPublic capture entry points are open to anonymous visitors; back-office reads are permission-gated (see PRD-SUB-001)
i18nA subscriber's preferred language is captured so future sends can localize; user-facing labels are bilingual (EN/VI)

8. UX & Flows

Key screens: the public-site capture forms (inquiry + newsletter). The back-office read (subscriber list, statistics) belongs to PRD-SUB-001; the inquiry workbench belongs to PRD-CAP-002.

9. Data & Domain

ConceptRole
InquiryA consult/contact/sales/demo/partner request captured from the public site - contact (first name, last name, email, phone), business (name, type, location count, estimated revenue), content (subject, message)
SubscriberA newsletter opt-in - email, preferred language, topics, status (active/deactivated), subscribe timestamp, unsubscribe timestamp, unsubscribe token

Conceptual only - full schema and invariants in the outreach developer docs.

10. Dependencies & Assumptions

Depends on

  • The capture capability - hosts inquiry/subscriber capture and lookup.
  • Real-time notification channel - pushes new-inquiry events to the operations team.

Assumptions

  • Capture data is global (constraint C-02); no per-merchant confinement on subscribers/inquiries.
  • Each subscriber holds a unique unsubscribe token issued at capture time for one-click unsubscribe.
  • External providers (out of scope) handle eventual email/SMS delivery.

11. Risks & Open Questions

Risk / questionMitigation / status
Duplicate subscribers on rapid double-submitSubscribe is idempotent by email - existing active record returned, no insert
Sending to an unsubscribed addressUnsubscribe deactivates the record; constraint C-01 requires opt-out be honored before any send
Global (non-confined) data across merchantsAccepted per constraint C-02
Spam through the public formNo dedicated anti-spam yet; monitor inquiry volume, add protection if abused

12. Release Plan & Launch Criteria

AspectPlan
PhaseP1 (foundation) - marketing/CAP in the URD feature catalog
RolloutAll sites; no feature flag
MigrationNone (new entities; global data)
Launch criteriaAll §6 acceptance criteria pass
MonitoringSubscribe/unsubscribe volume, duplicate-subscriber rate (expect 0), inquiry notification reliability

13. FAQ

What if the same email subscribes twice? Nothing duplicates - an already-active email returns the existing record; a previously unsubscribed email is reactivated.

How does unsubscribe work? Via a token link: the unsubscribe token resolves to the subscriber, which is then deactivated. Opt-out is always honored before any send.

Are subscribers scoped per merchant? No - capture data is global per constraint C-02.

Where do I see the subscriber list or statistics? In the back-office read - specified in PRD-SUB-001.

Does this send any campaigns? No - sending is out of scope here and owned by Campaigns & Automation (CMP, P2). This feature only captures the audience.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.