Talkamore backend (Node.js/TypeScript, PostgreSQL/Prisma, Railway). We need to add support for a Lifetime Access plan ("Founding 100") alongside existing Free, Monthly, and Yearly plans.
| Plan | Price | Message Cap | Duration | Stripe Price ID |
|---|---|---|---|---|
| Free | $0 | 100/month | — | — |
| Monthly | $9.99/mo | Unlimited | Recurring | (existing or create) |
| Yearly | $79.99/yr | Unlimited | Recurring | (existing or create) |
| Lifetime | $99 one-time | 5,000/month | Permanent | Create new one-time price |
Add to Plan enum or subscription model:
LIFETIME — one-time payment, never expires, 5000 msg/month cap
Schema updates needed:
subscriptionstable: supporttype: 'lifetime'with noexpires_at/ no renewaluserstable or profile: optionalfounding_member: booleanflag- Track Founding 100 count: either a counter or
SELECT COUNT(*) FROM subscriptions WHERE type = 'lifetime'
Return all available plans with pricing, features, and availability:
{
"plans": [
{ "id": "free", "price": 0, "messageLimit": 100, "features": ["basic_journaling", "maya_persona"] },
{ "id": "monthly", "price": 999, "interval": "month", "messageLimit": null, "features": ["unlimited_messages", "all_personas", "voice", "memory", "priority"] },
{ "id": "yearly", "price": 7999, "interval": "year", "messageLimit": null, "features": ["unlimited_messages", "all_personas", "voice", "memory", "priority"] },
{ "id": "lifetime", "price": 9900, "interval": null, "messageLimit": 5000, "features": ["unlimited_messages", "all_personas", "voice", "memory", "priority", "founding_badge", "early_access"], "remaining": 23, "totalSlots": 100 }
]
}- Accept
planId: 'lifetime' - Before creating Stripe session: check if Founding 100 slots remain
- If sold out, return
{ error: 'lifetime_sold_out' }with 409 - Create Stripe Checkout Session with
mode: 'payment'(not subscription) for lifetime - Use
mode: 'subscription'for monthly/yearly as usual
- On
checkout.session.completedfor lifetime:- Create subscription record with
type: 'lifetime',expires_at: null - Set
founding_member: trueon user - Increment lifetime sold counter (or just count from DB)
- Create subscription record with
- No renewal logic needed for lifetime
Return user's active plan, including lifetime status:
{
"plan": "lifetime",
"founding_member": true,
"message_limit": 5000,
"messages_used": 342,
"expires_at": null
}Update the message counting middleware:
if plan == 'free': limit = 100/month
if plan == 'lifetime': limit = 5000/month
if plan == 'monthly' || 'yearly': unlimited
Reset counts on 1st of each month for all plans.
- Race condition on Founding 100: use DB transaction or
SELECT FOR UPDATEwhen checking remaining slots - If user already has monthly/yearly and buys lifetime: cancel existing subscription, switch to lifetime
- Lifetime users should NOT see renewal prompts
- If Founding 100 sells out mid-checkout: handle gracefully in webhook (refund if needed, or honor it since they started before sellout)
- Expose
GET /api/plans/lifetime/remainingfor frontend to show live count - Cache this (Redis or in-memory) — doesn't need to be real-time, 1-5 min TTL is fine
STRIPE_LIFETIME_PRICE_ID— the one-time Stripe price for $99FOUNDING_100_LIMIT=100— configurable cap