Add comprehensive test coverage for platform marketing homepage API: - test_pricing.py: 17 tests for tiers, add-ons, pricing endpoints - test_letzshop_vendors.py: 22 tests for vendor lookup and claiming - test_signup.py: 28 tests for multi-step signup flow Fix signup.py to use correct password hashing from middleware/auth.py and properly create Company with owner_user_id. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
522 lines
15 KiB
Markdown
522 lines
15 KiB
Markdown
# Platform Marketing Homepage
|
|
|
|
## Overview
|
|
|
|
The Wizamart marketing homepage serves as the main public entry point for Letzshop vendors looking to use the order management platform. It provides a complete self-service signup flow with Stripe payment integration.
|
|
|
|
**Target Audience:** Letzshop vendors in Luxembourg seeking order management solutions.
|
|
|
|
**Key Value Proposition:** "Lightweight OMS for Letzshop Sellers" - Order management, inventory, and invoicing built for Luxembourg e-commerce.
|
|
|
|
## Features Summary
|
|
|
|
| Feature | URL | Description |
|
|
|---------|-----|-------------|
|
|
| Marketing Homepage | `/` | Hero, pricing, add-ons, vendor finder |
|
|
| Pricing Page | `/pricing` | Detailed tier comparison |
|
|
| Find Your Shop | `/find-shop` | Letzshop vendor lookup |
|
|
| Signup Wizard | `/signup` | 4-step registration flow |
|
|
| Signup Success | `/signup/success` | Welcome & next steps |
|
|
|
|
---
|
|
|
|
## Pricing Tiers
|
|
|
|
Based on `docs/marketing/pricing.md`:
|
|
|
|
| Tier | Monthly | Annual | Orders/mo | Products | Users | Key Features |
|
|
|------|---------|--------|-----------|----------|-------|--------------|
|
|
| **Essential** | €49 | €490 | 100 | 200 | 1 | LU invoicing, basic inventory |
|
|
| **Professional** | €99 | €990 | 500 | Unlimited | 3 | EU VAT, warehouse locations |
|
|
| **Business** | €199 | €1,990 | 2,000 | Unlimited | 10 | Analytics, API, automation |
|
|
| **Enterprise** | €399+ | Custom | Unlimited | Unlimited | Unlimited | White-label, SLA, dedicated support |
|
|
|
|
**Annual Discount:** 2 months free (17% savings)
|
|
|
|
**Trial Period:** 30 days with card collection upfront (no charge until trial ends)
|
|
|
|
---
|
|
|
|
## Add-On Products
|
|
|
|
| Add-On | Price | Billing | Description |
|
|
|--------|-------|---------|-------------|
|
|
| Custom Domain | €15 | Annual | Use your own domain (mydomain.com) |
|
|
| Premium SSL | €49 | Annual | EV certificate for trust badges |
|
|
| Email Package (5) | €5 | Monthly | 5 professional email addresses |
|
|
| Email Package (10) | €9 | Monthly | 10 professional email addresses |
|
|
| Email Package (25) | €19 | Monthly | 25 professional email addresses |
|
|
|
|
---
|
|
|
|
## Page Descriptions
|
|
|
|
### 1. Marketing Homepage (`/`)
|
|
|
|
**Template:** `app/templates/platform/homepage-wizamart.html`
|
|
|
|
**Sections:**
|
|
|
|
1. **Hero Section**
|
|
- Headline: "Lightweight OMS for Letzshop Sellers"
|
|
- Subheadline: Order management, inventory, and invoicing
|
|
- CTAs: "Start Free Trial" and "Find Your Letzshop Shop"
|
|
- Badge: "30-Day Free Trial - No Credit Card Required to Start"
|
|
|
|
2. **Pricing Section**
|
|
- 4 tier cards (Essential, Professional, Business, Enterprise)
|
|
- Monthly/Annual toggle with savings indicator
|
|
- Feature lists per tier
|
|
- "Start Free Trial" buttons linked to signup
|
|
|
|
3. **Add-Ons Section**
|
|
- 3 add-on cards (Domain, SSL, Email)
|
|
- Icon, description, and pricing for each
|
|
|
|
4. **Letzshop Vendor Finder**
|
|
- Search input for shop URL
|
|
- Real-time lookup via API
|
|
- "Claim This Shop" button for unclaimed vendors
|
|
|
|
5. **Final CTA Section**
|
|
- Gradient background
|
|
- Strong call to action for trial signup
|
|
|
|
### 2. Pricing Page (`/pricing`)
|
|
|
|
**Template:** `app/templates/platform/pricing.html`
|
|
|
|
Standalone page with:
|
|
- Large tier cards
|
|
- Monthly/Annual toggle
|
|
- Detailed feature lists
|
|
- Back to home link
|
|
|
|
### 3. Find Your Shop (`/find-shop`)
|
|
|
|
**Template:** `app/templates/platform/find-shop.html`
|
|
|
|
- URL input with examples
|
|
- Real-time Letzshop vendor lookup
|
|
- Claim button for unclaimed shops
|
|
- Help section with alternatives
|
|
|
|
### 4. Signup Wizard (`/signup`)
|
|
|
|
**Template:** `app/templates/platform/signup.html`
|
|
|
|
**4-Step Flow:**
|
|
|
|
| Step | Name | Description |
|
|
|------|------|-------------|
|
|
| 1 | Select Plan | Choose tier + billing period |
|
|
| 2 | Claim Shop | Optional Letzshop connection |
|
|
| 3 | Create Account | User details + company info |
|
|
| 4 | Payment | Stripe card collection |
|
|
|
|
**URL Parameters:**
|
|
- `?tier=professional` - Pre-select tier
|
|
- `?annual=true` - Pre-select annual billing
|
|
- `?letzshop=my-shop` - Pre-fill Letzshop slug
|
|
|
|
### 5. Signup Success (`/signup/success`)
|
|
|
|
**Template:** `app/templates/platform/signup-success.html`
|
|
|
|
- Success confirmation
|
|
- Next steps checklist
|
|
- Dashboard link
|
|
- Support contact
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
All endpoints under `/api/v1/platform/`:
|
|
|
|
### Pricing Endpoints
|
|
|
|
```
|
|
GET /api/v1/platform/tiers
|
|
Returns all public subscription tiers
|
|
Response: TierResponse[]
|
|
|
|
GET /api/v1/platform/tiers/{tier_code}
|
|
Returns specific tier by code
|
|
Response: TierResponse
|
|
|
|
GET /api/v1/platform/addons
|
|
Returns all active add-on products
|
|
Response: AddOnResponse[]
|
|
|
|
GET /api/v1/platform/pricing
|
|
Returns complete pricing info (tiers + addons + trial_days)
|
|
Response: PricingResponse
|
|
```
|
|
|
|
### Letzshop Vendor Endpoints
|
|
|
|
```
|
|
GET /api/v1/platform/letzshop-vendors
|
|
Query params: ?search=&category=&city=&page=1&limit=20
|
|
Returns paginated vendor list (placeholder for future)
|
|
Response: LetzshopVendorListResponse
|
|
|
|
POST /api/v1/platform/letzshop-vendors/lookup
|
|
Body: { "url": "letzshop.lu/vendors/my-shop" }
|
|
Returns vendor info from URL lookup
|
|
Response: LetzshopLookupResponse
|
|
|
|
GET /api/v1/platform/letzshop-vendors/{slug}
|
|
Returns vendor info by slug
|
|
Response: LetzshopVendorInfo
|
|
```
|
|
|
|
### Signup Endpoints
|
|
|
|
```
|
|
POST /api/v1/platform/signup/start
|
|
Body: { "tier_code": "professional", "is_annual": false }
|
|
Creates signup session
|
|
Response: { "session_id": "...", "tier_code": "...", "is_annual": false }
|
|
|
|
POST /api/v1/platform/signup/claim-vendor
|
|
Body: { "session_id": "...", "letzshop_slug": "my-shop" }
|
|
Claims Letzshop vendor for session
|
|
Response: { "session_id": "...", "letzshop_slug": "...", "vendor_name": "..." }
|
|
|
|
POST /api/v1/platform/signup/create-account
|
|
Body: {
|
|
"session_id": "...",
|
|
"email": "user@example.com",
|
|
"password": "securepassword",
|
|
"first_name": "John",
|
|
"last_name": "Doe",
|
|
"company_name": "My Company"
|
|
}
|
|
Creates User, Company, Vendor, Stripe Customer
|
|
Response: { "session_id": "...", "user_id": 1, "vendor_id": 1, "stripe_customer_id": "cus_..." }
|
|
|
|
POST /api/v1/platform/signup/setup-payment
|
|
Body: { "session_id": "..." }
|
|
Creates Stripe SetupIntent
|
|
Response: { "session_id": "...", "client_secret": "seti_...", "stripe_customer_id": "cus_..." }
|
|
|
|
POST /api/v1/platform/signup/complete
|
|
Body: { "session_id": "...", "setup_intent_id": "seti_..." }
|
|
Completes signup, attaches payment method
|
|
Response: { "success": true, "vendor_code": "...", "vendor_id": 1, "redirect_url": "...", "trial_ends_at": "..." }
|
|
|
|
GET /api/v1/platform/signup/session/{session_id}
|
|
Returns session status for resuming signup
|
|
Response: { "session_id": "...", "step": "...", ... }
|
|
```
|
|
|
|
---
|
|
|
|
## Database Schema Changes
|
|
|
|
### Migration: `404b3e2d2865_add_letzshop_vendor_fields_and_trial_tracking`
|
|
|
|
**Vendor Table:**
|
|
```sql
|
|
ALTER TABLE vendors ADD COLUMN letzshop_vendor_id VARCHAR(100) UNIQUE;
|
|
ALTER TABLE vendors ADD COLUMN letzshop_vendor_slug VARCHAR(200);
|
|
CREATE INDEX ix_vendors_letzshop_vendor_id ON vendors(letzshop_vendor_id);
|
|
CREATE INDEX ix_vendors_letzshop_vendor_slug ON vendors(letzshop_vendor_slug);
|
|
```
|
|
|
|
**VendorSubscription Table:**
|
|
```sql
|
|
ALTER TABLE vendor_subscriptions ADD COLUMN card_collected_at DATETIME;
|
|
```
|
|
|
|
### Model Changes
|
|
|
|
**`models/database/vendor.py`:**
|
|
```python
|
|
# Letzshop Vendor Identity
|
|
letzshop_vendor_id = Column(String(100), unique=True, nullable=True, index=True)
|
|
letzshop_vendor_slug = Column(String(200), nullable=True, index=True)
|
|
```
|
|
|
|
**`models/database/subscription.py`:**
|
|
```python
|
|
# Card collection tracking
|
|
card_collected_at = Column(DateTime(timezone=True), nullable=True)
|
|
```
|
|
|
|
### Configuration Change
|
|
|
|
**`app/core/config.py`:**
|
|
```python
|
|
stripe_trial_days: int = 30 # Changed from 14 to 30
|
|
```
|
|
|
|
---
|
|
|
|
## Stripe Integration
|
|
|
|
### Trial Flow with Card Collection
|
|
|
|
The signup uses Stripe **SetupIntent** (not PaymentIntent) to collect card details without immediate charge:
|
|
|
|
```
|
|
1. User selects tier → POST /signup/start
|
|
└── Creates signup session
|
|
|
|
2. User claims Letzshop shop (optional) → POST /signup/claim-vendor
|
|
└── Links Letzshop vendor to session
|
|
|
|
3. User creates account → POST /signup/create-account
|
|
├── Creates User in database
|
|
├── Creates Company in database
|
|
├── Creates Vendor in database
|
|
├── Creates Stripe Customer
|
|
└── Creates VendorSubscription (status: trial)
|
|
|
|
4. User enters card → POST /signup/setup-payment
|
|
└── Creates Stripe SetupIntent
|
|
└── Returns client_secret for frontend
|
|
|
|
5. Frontend confirms card → stripe.confirmCardSetup(client_secret)
|
|
└── Validates card (no charge)
|
|
|
|
6. Signup completes → POST /signup/complete
|
|
├── Retrieves SetupIntent
|
|
├── Attaches PaymentMethod to Customer
|
|
├── Sets as default payment method
|
|
├── Records card_collected_at
|
|
└── Subscription starts 30-day trial
|
|
|
|
7. After 30 days → Stripe automatically charges card
|
|
```
|
|
|
|
### New StripeService Methods
|
|
|
|
**`app/services/stripe_service.py`:**
|
|
|
|
```python
|
|
def create_setup_intent(
|
|
self,
|
|
customer_id: str,
|
|
metadata: dict | None = None,
|
|
) -> stripe.SetupIntent:
|
|
"""
|
|
Create a SetupIntent to collect card without charging.
|
|
Used for trial signups where we collect card upfront.
|
|
"""
|
|
|
|
def attach_payment_method_to_customer(
|
|
self,
|
|
customer_id: str,
|
|
payment_method_id: str,
|
|
set_as_default: bool = True,
|
|
) -> None:
|
|
"""
|
|
Attach a payment method to customer and set as default.
|
|
"""
|
|
|
|
def create_subscription_with_trial(
|
|
self,
|
|
customer_id: str,
|
|
price_id: str,
|
|
trial_days: int = 30,
|
|
metadata: dict | None = None,
|
|
) -> stripe.Subscription:
|
|
"""
|
|
Create subscription with trial period.
|
|
Card will be charged automatically after trial ends.
|
|
"""
|
|
|
|
def get_setup_intent(self, setup_intent_id: str) -> stripe.SetupIntent:
|
|
"""Get a SetupIntent by ID."""
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
```
|
|
app/
|
|
├── api/
|
|
│ └── v1/
|
|
│ └── platform/
|
|
│ ├── __init__.py # Router aggregation
|
|
│ ├── pricing.py # Tier & addon endpoints
|
|
│ ├── letzshop_vendors.py # Vendor lookup endpoints
|
|
│ └── signup.py # Signup flow endpoints
|
|
├── routes/
|
|
│ └── platform_pages.py # Page routes (/, /pricing, etc.)
|
|
├── services/
|
|
│ └── stripe_service.py # SetupIntent methods (updated)
|
|
└── templates/
|
|
└── platform/
|
|
├── base.html # Base template (Wizamart branding)
|
|
├── homepage-wizamart.html # Marketing homepage
|
|
├── pricing.html # Pricing page
|
|
├── find-shop.html # Letzshop finder
|
|
├── signup.html # Signup wizard
|
|
└── signup-success.html # Success page
|
|
|
|
models/database/
|
|
├── vendor.py # letzshop_vendor_id, slug fields
|
|
└── subscription.py # card_collected_at field
|
|
|
|
alembic/versions/
|
|
└── 404b3e2d2865_add_letzshop_vendor_fields_and_trial_.py
|
|
|
|
main.py # Platform routes registered
|
|
app/api/main.py # Platform API router added
|
|
app/core/config.py # stripe_trial_days = 30
|
|
```
|
|
|
|
---
|
|
|
|
## Frontend Technology
|
|
|
|
- **Tailwind CSS** - Utility-first styling
|
|
- **Alpine.js** - Reactive components
|
|
- **Stripe.js** - Payment form (Stripe Elements)
|
|
|
|
### JavaScript Components (Embedded)
|
|
|
|
**Homepage (`homepageData()`):**
|
|
- `annual` - Billing toggle state
|
|
- `shopUrl` - Letzshop URL input
|
|
- `vendorResult` - Lookup result
|
|
- `lookupVendor()` - API call for lookup
|
|
|
|
**Signup Wizard (`signupWizard()`):**
|
|
- `currentStep` - Wizard step (1-4)
|
|
- `sessionId` - Backend session ID
|
|
- `selectedTier` - Selected tier code
|
|
- `isAnnual` - Annual billing toggle
|
|
- `letzshopUrl/Vendor` - Letzshop claim
|
|
- `account` - User form data
|
|
- `stripe/cardElement` - Stripe integration
|
|
- `startSignup()` - Step 1 submission
|
|
- `claimVendor()` - Step 2 submission
|
|
- `createAccount()` - Step 3 submission
|
|
- `initStripe()` - Initialize Stripe Elements
|
|
- `submitPayment()` - Step 4 submission
|
|
|
|
---
|
|
|
|
## Configuration Requirements
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Required for payment step
|
|
STRIPE_SECRET_KEY=sk_test_...
|
|
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_... # For webhook handling
|
|
|
|
# Trial period (defaults to 30)
|
|
STRIPE_TRIAL_DAYS=30
|
|
```
|
|
|
|
### Stripe Dashboard Setup
|
|
|
|
1. Create Products for each tier (Essential, Professional, Business)
|
|
2. Create Prices for monthly and annual billing
|
|
3. Configure Customer Portal
|
|
4. Set up webhook endpoint for subscription events
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Automated Tests
|
|
|
|
Test files located in `tests/integration/api/v1/platform/`:
|
|
|
|
| File | Tests | Description |
|
|
|------|-------|-------------|
|
|
| `test_pricing.py` | 17 | Tier and add-on pricing endpoints |
|
|
| `test_letzshop_vendors.py` | 22 | Vendor lookup and listing endpoints |
|
|
| `test_signup.py` | 28 | Multi-step signup flow |
|
|
|
|
**Run tests:**
|
|
```bash
|
|
pytest tests/integration/api/v1/platform/ -v
|
|
```
|
|
|
|
**Test categories:**
|
|
- `TestPlatformPricingAPI` - GET /tiers, /addons, /pricing
|
|
- `TestLetzshopVendorLookupAPI` - Vendor lookup and claiming
|
|
- `TestLetzshopSlugExtraction` - URL parsing edge cases
|
|
- `TestSignupStartAPI` - Signup initiation
|
|
- `TestClaimVendorAPI` - Letzshop vendor claiming
|
|
- `TestCreateAccountAPI` - Account creation
|
|
- `TestSetupPaymentAPI` - Stripe SetupIntent
|
|
- `TestCompleteSignupAPI` - Signup completion
|
|
- `TestSignupFullFlow` - End-to-end flow
|
|
|
|
### Manual Testing
|
|
|
|
1. **Homepage:** Visit `http://localhost:8000/`
|
|
2. **Pricing Toggle:** Click Monthly/Annual switch
|
|
3. **Vendor Lookup:** Enter a Letzshop URL in finder
|
|
4. **Signup Flow:**
|
|
- Click "Start Free Trial"
|
|
- Select tier
|
|
- Skip or enter Letzshop URL
|
|
- Fill account form
|
|
- Enter test card (4242 4242 4242 4242)
|
|
- Complete signup
|
|
|
|
### Test Cards (Stripe)
|
|
|
|
| Card | Scenario |
|
|
|------|----------|
|
|
| 4242 4242 4242 4242 | Success |
|
|
| 4000 0000 0000 0002 | Decline |
|
|
| 4000 0000 0000 3220 | 3D Secure required |
|
|
|
|
### API Testing
|
|
|
|
```bash
|
|
# Get pricing
|
|
curl http://localhost:8000/api/v1/platform/pricing
|
|
|
|
# Lookup vendor
|
|
curl -X POST http://localhost:8000/api/v1/platform/letzshop-vendors/lookup \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"url": "letzshop.lu/vendors/test-shop"}'
|
|
|
|
# Start signup
|
|
curl -X POST http://localhost:8000/api/v1/platform/signup/start \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"tier_code": "professional", "is_annual": false}'
|
|
```
|
|
|
|
---
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Letzshop Vendor Cache**
|
|
- Periodic sync of Letzshop vendor directory
|
|
- Browsable list instead of URL lookup only
|
|
|
|
2. **Email Verification**
|
|
- Verify email before trial starts
|
|
- Confirmation email with onboarding links
|
|
|
|
3. **Referral Program**
|
|
- Affiliate/referral codes
|
|
- Partner commission tracking
|
|
|
|
4. **A/B Testing**
|
|
- Test different pricing presentations
|
|
- Optimize conversion rates
|
|
|
|
5. **Analytics**
|
|
- Track signup funnel drop-off
|
|
- Monitor tier selection patterns
|
|
|
|
6. **Enterprise Contact Form**
|
|
- Lead capture for enterprise tier
|
|
- Sales team notification
|