Add billing and license integration plan
This commit is contained in:
231
IMPLEMENTATION_PLAN.md
Normal file
231
IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# DashCaddy License Server Implementation Plan
|
||||
|
||||
## Goal
|
||||
|
||||
Connect live Stripe billing to DashCaddy Premium licensing without inventing a second license model.
|
||||
|
||||
## Existing DashCaddy integration points
|
||||
|
||||
The main DashCaddy app already has the core license hooks:
|
||||
- `dashcaddy-api/license-keygen.js`
|
||||
- `dashcaddy-api/license-manager.js`
|
||||
- `dashcaddy-api/routes/license.js`
|
||||
|
||||
The app already supports:
|
||||
- `LICENSE_SERVER_URL`
|
||||
- online validation at `/api/license/validate`
|
||||
- online deactivation at `/api/license/deactivate`
|
||||
- offline HMAC validation fallback
|
||||
- premium feature checks for:
|
||||
- `sso`
|
||||
- `recipes`
|
||||
- `swarm`
|
||||
|
||||
## Locked product decisions
|
||||
|
||||
### Free tier
|
||||
Everything works without a license except premium-gated features.
|
||||
|
||||
### Premium tier
|
||||
Paid subscriptions unlock:
|
||||
- `sso`
|
||||
- `recipes`
|
||||
- `swarm`
|
||||
|
||||
### Stripe plans
|
||||
- 1 month — $25
|
||||
- 3 months — $50
|
||||
- 6 months — $65
|
||||
- 12 months — $99
|
||||
|
||||
### Subscription policy
|
||||
- recurring subscriptions
|
||||
- 7-day grace period on failed payment
|
||||
- cancel at period end
|
||||
- one active machine at a time
|
||||
- transfer requires deactivation from previous machine
|
||||
- no public lifetime plan
|
||||
|
||||
## Recommended system shape
|
||||
|
||||
### Website (`dashcaddy.net`)
|
||||
Responsibilities:
|
||||
- show Premium pricing cards
|
||||
- create Stripe Checkout sessions through the license server
|
||||
- redirect to Stripe Checkout
|
||||
- return users to success/cancel pages
|
||||
|
||||
### License server (`dashcaddy-license-server`)
|
||||
Responsibilities:
|
||||
- create Stripe Checkout sessions
|
||||
- ingest Stripe webhooks
|
||||
- maintain customer/license/subscription state
|
||||
- issue and renew DashCaddy-compatible licenses
|
||||
- validate license activations
|
||||
- enforce one-active-machine policy
|
||||
- accept deactivation requests
|
||||
- provide admin support tooling later
|
||||
|
||||
### Stripe
|
||||
Source of truth for:
|
||||
- customers
|
||||
- subscriptions
|
||||
- invoices
|
||||
- payment state
|
||||
- cancellation state
|
||||
|
||||
## Proposed API surface
|
||||
|
||||
### Public endpoints for website
|
||||
- `POST /api/checkout/session`
|
||||
- `GET /api/public/plans`
|
||||
|
||||
### DashCaddy app endpoints
|
||||
- `POST /api/license/validate`
|
||||
- `POST /api/license/deactivate`
|
||||
|
||||
### Stripe webhook endpoint
|
||||
- `POST /api/stripe/webhook`
|
||||
|
||||
### Future admin endpoints
|
||||
- `GET /api/admin/licenses/:code`
|
||||
- `POST /api/admin/licenses/:code/override`
|
||||
- `POST /api/admin/licenses/:code/reset-activation`
|
||||
|
||||
## Data model
|
||||
|
||||
### customers
|
||||
- id
|
||||
- email
|
||||
- stripe_customer_id
|
||||
- created_at
|
||||
- updated_at
|
||||
|
||||
### subscriptions
|
||||
- id
|
||||
- customer_id
|
||||
- stripe_subscription_id
|
||||
- stripe_price_id
|
||||
- plan_code
|
||||
- status
|
||||
- current_period_start
|
||||
- current_period_end
|
||||
- cancel_at_period_end
|
||||
- grace_until
|
||||
- created_at
|
||||
- updated_at
|
||||
|
||||
### licenses
|
||||
- id
|
||||
- customer_id
|
||||
- subscription_id
|
||||
- license_code
|
||||
- tier
|
||||
- features_json
|
||||
- status
|
||||
- expires_at
|
||||
- last_validated_at
|
||||
- created_at
|
||||
- updated_at
|
||||
|
||||
### activations
|
||||
- id
|
||||
- license_id
|
||||
- machine_fingerprint
|
||||
- hostname
|
||||
- platform
|
||||
- arch
|
||||
- cpu
|
||||
- mac_hash
|
||||
- activated_at
|
||||
- deactivated_at
|
||||
- status
|
||||
|
||||
### stripe_events
|
||||
- id
|
||||
- stripe_event_id
|
||||
- type
|
||||
- processed_at
|
||||
- payload_json
|
||||
|
||||
## Stripe plan mapping
|
||||
|
||||
One Premium product, four recurring prices:
|
||||
- `premium_monthly`
|
||||
- `premium_3month`
|
||||
- `premium_6month`
|
||||
- `premium_12month`
|
||||
|
||||
All plans unlock the same Premium features. Only the billing interval differs.
|
||||
|
||||
## Activation logic
|
||||
|
||||
### Validation request from DashCaddy
|
||||
Expected inputs:
|
||||
- license code
|
||||
- machine fingerprint
|
||||
- machine metadata
|
||||
|
||||
Validation rules:
|
||||
1. license exists and is active
|
||||
2. subscription is active or in grace period
|
||||
3. license not expired
|
||||
4. no active activation on a different machine
|
||||
5. if first activation, bind to this machine
|
||||
6. if same machine, refresh validation
|
||||
7. if different machine while old activation still active, reject
|
||||
|
||||
### Deactivation request
|
||||
1. find active activation for license
|
||||
2. mark activation deactivated
|
||||
3. free license for reuse on another machine
|
||||
|
||||
## Renewal logic
|
||||
|
||||
On successful Stripe renewal:
|
||||
- keep same customer/license relationship
|
||||
- extend effective entitlement through subscription period
|
||||
- license remains active continuously
|
||||
|
||||
On payment failure:
|
||||
- mark subscription past_due-like state
|
||||
- set `grace_until = current time + 7 days`
|
||||
|
||||
On cancellation:
|
||||
- keep access until current_period_end
|
||||
- then expire
|
||||
|
||||
## Website integration plan
|
||||
|
||||
The `dashcaddy.net` marketing site should be updated to:
|
||||
- add Premium pricing section buttons
|
||||
- each button POSTs to `/api/checkout/session` with a plan code
|
||||
- redirect to returned Stripe Checkout URL
|
||||
- success page explains license delivery/activation flow
|
||||
- cancellation page returns user to pricing
|
||||
|
||||
## Deployment target
|
||||
|
||||
Deploy `dashcaddy-license-server` on Contabo.
|
||||
|
||||
Initial env expected:
|
||||
- `STRIPE_SECRET_KEY`
|
||||
- `STRIPE_WEBHOOK_SECRET`
|
||||
- `STRIPE_PUBLISHABLE_KEY`
|
||||
- `APP_BASE_URL`
|
||||
- `DASHCADDY_WEBSITE_URL`
|
||||
- `DATABASE_URL`
|
||||
- `LICENSE_SIGNING_SECRET` or reused DashCaddy-compatible secret path
|
||||
|
||||
## Immediate next build steps
|
||||
|
||||
1. Scaffold Node service for `dashcaddy-license-server`
|
||||
2. Add Stripe SDK, Express, and SQLite/Postgres adapter layer
|
||||
3. Build `/api/public/plans`
|
||||
4. Build `/api/checkout/session`
|
||||
5. Build `/api/stripe/webhook`
|
||||
6. Port/reuse DashCaddy-compatible license generation/validation helpers
|
||||
7. Build `/api/license/validate`
|
||||
8. Build `/api/license/deactivate`
|
||||
9. Wire pricing CTA buttons into `dashcaddy.net`
|
||||
10. Test with Stripe test mode flow before flipping deployed env to live operation
|
||||
Reference in New Issue
Block a user