# PRD: Stripe Card Collection Shortlink Tool

## Product Name
Stripe Card Collection Shortlink Tool

## Problem
No More Chores needs a reliable way to collect a customer's card for future charges.

Stripe can generate hosted setup flows, but the resulting URLs are long and not customer-friendly. In live testing, the full URL mattered, including the fragment portion, which means a normal URL shortener may not work reliably.

This makes the current workflow awkward for staff and poor for customer-facing communication.

## Goal
Build a lightweight internal tool that creates a short, clean No More Chores link which safely redirects a customer to Stripe's hosted card collection page.

## Users
### Primary users
- Mike
- Abigail (access in v1)

### End customer
- Customer receiving a secure link to add a card on file

## Job To Be Done
"Create a clean, safe link I can send to a customer so they can securely add a card on file without me sending a massive Stripe URL."

## Success Criteria
- Staff can create a card collection link in under 30 seconds
- Customer receives a short, clean URL on an No More Chores domain
- Customer successfully lands on the Stripe-hosted card capture page
- Completion is tracked automatically
- Stripe customer and payment method details can be recovered afterward
- Workflow can later be embedded into the custom internal booking form

## Background and Key Insight
During live testing:
- Stripe Checkout in `mode=setup` worked for card-on-file collection
- This Stripe account required `currency=cad`, even in setup mode
- The generated Stripe URL was very long
- Removing the fragment broke the link during testing
- A typical URL shortener is risky because fragments are handled client-side

This leads to the recommended architecture:
- store the full Stripe URL exactly as returned
- generate a short URL on a No More Chores domain
- use a browser-side redirect to the full Stripe URL

## MVP Scope
### Included in v1
- Internal authenticated page for staff
- Form to enter or select customer information
- Support for existing Stripe customer IDs
- Auto-creation of a new Stripe customer when no existing ID is provided
- Creation of Stripe Checkout Session with:
  - `mode=setup`
  - `currency=cad`
- Generation of unique short code
- Storage of short code and full Stripe URL
- Customer-facing short URL on NMC domain
- Redirect page using client-side JavaScript redirect
- Stripe webhook handling for completion tracking
- Basic internal status view for recent links

### Excluded from v1
- Full Launch27 auto-sync (planned for v2)
- Automatic sending by SMS or email from the tool (planned for v1.1)
- Full booking-form integration
- Advanced permissions/roles
- Reporting dashboard
- CRM workflow automation beyond status tracking

### Planned for v1.1
- SMS and email sending of the shortlink directly from the tool

### Planned for v2
- Auto-sync of captured payment method back to Launch27 (for v1, staff manually copy the Stripe customer ID into Launch27)

## User Stories
### Staff
- As staff, I want to create a secure card collection link quickly so I can send it to a customer while they are on the phone or in follow-up.
- As staff, I want to reuse an existing Stripe customer if one already exists.
- As staff, I want to see whether a card collection link is still open, expired, or completed.

### Customer
- As a customer, I want to click a clean link that feels trustworthy and lands me on a secure payment page.

### Operations
- As operations staff, I want proof that the customer completed card capture so I can continue the booking/payment workflow.

## Functional Requirements
### 1. Create card collection request
The tool must allow staff to:
- search/select an existing customer, or
- manually enter:
  - customer name
  - email
  - phone
  - optional Launch27 customer ID
- enter an existing Stripe customer ID, or have the system auto-create a new Stripe customer

### 2. Create Stripe setup session
The backend must create a Stripe Checkout Session with:
- `mode=setup`
- `customer=<stripe customer id>`
- `currency=cad`
- success URL on NMC domain
- cancel URL on NMC domain

### 3. Generate short URL
The system must:
- generate a short, non-guessable code
- store the full Stripe checkout URL exactly as returned
- return a short link such as:
  - `https://secure.nomorechores.com/abc123`

### 4. Redirect customer reliably
When a customer opens the short URL:
- the app must render a minimal page
- the page must redirect client-side to the full Stripe URL using JavaScript
- a fallback button must be shown in case automatic redirect fails

### 5. Track status
The system must track:
- open
- completed
- expired
- cancelled

### 6. Process webhooks
The backend must accept Stripe webhook events and update the internal record when relevant events occur, including:
- `checkout.session.completed`
- optionally `setup_intent.succeeded`

### 7. Persist important data
The system must store:
- short code
- Stripe customer ID
- Stripe checkout session ID
- Stripe checkout URL
- optional Launch27 customer ID
- customer identifying info
- status
- created by
- created at
- expires at
- completed at
- Stripe setup intent ID when available
- Stripe payment method ID when available

## Non-Functional Requirements
- Secret API keys must never be exposed to the frontend
- Short links must be customer-safe and visually clean
- Redirect behavior must be reliable on desktop and mobile
- Short codes must be unguessable
- Webhook signatures must be verified
- Internal tool must require authentication
- Links should expire automatically after the Stripe session expires
- Logs should support auditability for who created which link and when

## Proposed UX
### Internal staff flow
1. Open internal tool
2. Search customer or enter details
3. Confirm or create Stripe customer
4. Click "Create card collection link"
5. Tool shows:
   - short URL
   - Stripe customer ID
   - status = open
   - expiry time
6. Staff copies and sends short URL to customer

### Customer flow
1. Customer clicks short URL
2. Sees a minimal NMC page for a brief moment
3. Browser redirects to Stripe-hosted card collection page
4. Customer enters card details
5. Stripe confirms completion

### Internal follow-up flow
1. Webhook marks link completed
2. Internal page shows completed status
3. Staff can view associated Stripe customer/session/payment method data
4. Staff manually syncs to Launch27 for v1, or later the system syncs automatically

## Technical Design Direction
### Recommended architecture
Use a small standalone internal app with:
- backend API
- lightweight database
- Stripe SDK integration
- redirect page hosted on an NMC domain

### Suggested stack
Any of the following would work:
- Next.js
- Express
- Supabase-backed lightweight admin app

### Why client-side redirect is preferred
A simple server-side shortener may not preserve the exact behavior needed if the destination relies on the URL fragment.

Safer pattern:
- save the full Stripe URL exactly as returned
- on shortlink page load, run:
  - `window.location.replace(fullStripeUrl)`

## Data Model
### `card_collection_links`
Fields:
- `id`
- `code`
- `stripe_customer_id`
- `stripe_checkout_session_id`
- `stripe_checkout_url`
- `launch27_customer_id` nullable
- `customer_name` nullable
- `customer_email` nullable
- `customer_phone` nullable
- `status`
- `created_by`
- `created_at`
- `expires_at`
- `completed_at` nullable
- `stripe_setup_intent_id` nullable
- `stripe_payment_method_id` nullable
- `notes` nullable

## API Endpoints
### `POST /api/card-links`
Creates a new card collection request.

Input:
- customer info
- existing Stripe customer ID or create-new flag
- optional Launch27 customer ID

Output:
- short URL
- Stripe customer ID
- checkout session ID
- expires at

### `GET /card/:code`
Customer-facing shortlink route.

Behavior:
- loads stored record
- renders minimal redirect page
- redirects client-side to full Stripe URL
- shows fallback continue button if needed

### `POST /api/stripe/webhook`
Handles Stripe webhooks and updates link status.

## Risks
- Stripe may change hosted Checkout URL behavior in future
- Redirect behavior needs testing on iPhone/Safari and Android browsers
- Staff may want built-in sending sooner than planned
- Launch27 may remain partially manual until broader replacement work is done

## Decisions
- **Subdomain:** `secure.nomorechores.com` — `pay.nomorechores.com` was rejected because the customer is not paying, they are saving a card on file
- **Access in v1:** Both Mike and Abigail have access
- **SMS/email sending:** Planned for v1.1
- **Launch27 auto-sync:** Planned for v2; in v1 staff manually copy the Stripe customer ID into Launch27
- **Stripe customer creation:** Tool auto-creates a Stripe customer when no existing ID is provided

## Recommendation
Build this as a tiny standalone internal tool first.

Do not try to force it through Launch27.

Prove the workflow, validate that the shortlink redirect works consistently, then fold the same flow into the custom internal booking form later.

## Implementation Notes From Live Testing
- Standard Stripe secret key is required
- The Checkout Session was created successfully with:
  - `mode=setup`
  - `customer=cus_...`
  - `currency=cad`
- The full returned Stripe URL should be preserved exactly

## Future Vision
Once validated, this becomes one part of the custom NMC booking stack:
- create or find customer
- collect card on file
- save payment method
- sync customer/payment context
- continue into quote and booking workflows
