233 lines
5.3 KiB
Markdown
233 lines
5.3 KiB
Markdown
# 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.
|
|
There is no Premium free trial. Premium is simply locked until a paid subscription activates a license.
|
|
|
|
### 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, with no trial period:
|
|
- `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
|