Files
dashcaddy-license-server/IMPLEMENTATION_PLAN.md
2026-04-17 20:04:29 -07:00

5.1 KiB

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

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