mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
Rebrand paid tier to $99 Founding Lifetime Member
Replace the $10 "Premium" pitch with a $99 Founding Lifetime Member offer (first 1,000 accounts) and list every bonus feature in the join@ upgrade prompt: personal email + webmail, custom domains, Tor access, and lifetime locked-in pricing. - payments: PremiumPriceLabel/default amount $10 -> $99, add FoundingCap - join@ offer + already-paid welcome + gated-route upsell copy - README + interface doc comments Price stays env-overridable via AGENTBBS_PREMIUM_AMOUNT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
52b06d8cfe
commit
2a9d841ddb
4 changed files with 30 additions and 19 deletions
|
|
@ -13,9 +13,10 @@ Just two SSH front doors: **`join@`** to onboard a new key, then
|
|||
domains are all reached from there.
|
||||
|
||||
**Membership:** a verified-email account is **free** — you get a personal Docker
|
||||
pod and a homepage at `https://bbs.profullstack.com/~name`. **Premium** ($10
|
||||
one-time, lifetime) adds a personal `name@bbs.profullstack.com` email (via
|
||||
forwardemail.net) and custom domains.
|
||||
pod and a homepage at `https://bbs.profullstack.com/~name`. **Founding Lifetime
|
||||
Member** ($99 one-time, first 1,000 accounts only) adds, for life: a personal
|
||||
`name@bbs.profullstack.com` email + webmail (via forwardemail.net), custom
|
||||
domains, and Tor access (`ssh tor@` — fetch URLs & join IRC over Tor).
|
||||
|
||||
No browser, no install, no client download. The BBS is a hub of hot-swappable
|
||||
plugins around one shared account system; the full product plan is in
|
||||
|
|
@ -137,7 +138,7 @@ server. Full details: [`docs/irc.md`](docs/irc.md).
|
|||
- **Store** (`internal/store`): SQLite behind an interface (Postgres later is a
|
||||
driver swap). Users, sessions, scores, pod subscriptions.
|
||||
- **Payments** (`internal/payments`): CoinPay REST API (coinpayportal.com) for
|
||||
the $10 lifetime membership + HMAC payment references; manual grant for ops.
|
||||
the $99 Founding Lifetime membership + HMAC payment references; manual grant for ops.
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// ssh bbs@host the BBS hub, guests welcome (play@/guest@ are aliases)
|
||||
// ssh <name>@host the hub as a member/agent (SSH key required)
|
||||
// ssh join@host onboarding: registers your key, confirms your email with an
|
||||
// emailed code, then offers $10 lifetime Premium (CoinPay)
|
||||
// emailed code, then offers $99 Founding Lifetime (CoinPay)
|
||||
// ssh pod@host your personal Linux pod — free for verified members
|
||||
// ssh domain@host point your own domain at your homepage (Premium; add/rm/list)
|
||||
// ssh admin@host the operator admin console ($AGENTBBS_ADMINS only)
|
||||
|
|
@ -372,7 +372,7 @@ func readLine(s ssh.Session, in *bufio.Reader) (string, error) {
|
|||
|
||||
// handleJoin runs onboarding interactively in one SSH session: register the
|
||||
// visitor's key, confirm their email with a code we email them, then offer the
|
||||
// $10 lifetime Premium membership (CoinPay). It then disconnects.
|
||||
// $99 Founding Lifetime membership (CoinPay). It then disconnects.
|
||||
func (a *app) handleJoin(s ssh.Session) {
|
||||
fp := auth.Fingerprint(s.PublicKey())
|
||||
if fp == "" {
|
||||
|
|
@ -432,7 +432,7 @@ func (a *app) handleJoin(s ssh.Session) {
|
|||
" homepage https://" + a.host + "/~" + u.Name,
|
||||
}, "\n"))
|
||||
|
||||
// 2) Premium ($10 lifetime): personal @host email + custom domains.
|
||||
// 2) Founding Lifetime ($99 one-time): personal @host email + custom domains.
|
||||
a.offerPremium(s, &u)
|
||||
_ = s.Exit(0)
|
||||
}
|
||||
|
|
@ -577,7 +577,7 @@ func (a *app) ensurePremium(u *store.User) bool {
|
|||
func (a *app) showPremiumWelcome(s ssh.Session, u store.User) {
|
||||
lines := []string{
|
||||
"",
|
||||
" ★ Premium — thanks! Your perks:",
|
||||
" ★ Founding Lifetime Member — thanks! Your perks:",
|
||||
"",
|
||||
" email " + a.fe.Address(u.Name),
|
||||
" forwards " + u.Email,
|
||||
|
|
@ -592,7 +592,7 @@ func (a *app) showPremiumWelcome(s ssh.Session, u store.User) {
|
|||
wish.Println(s, strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
// offerPremium pitches the $10 lifetime membership — a personal @host email and
|
||||
// offerPremium pitches the $99 Founding Lifetime membership — a personal @host email and
|
||||
// custom domains. When CoinPay can mint a charge in-session it shows the exact
|
||||
// amount and deposit address; otherwise it falls back to a pay command.
|
||||
// Non-blocking: the member pays out of band and perks unlock on their next
|
||||
|
|
@ -607,9 +607,15 @@ func (a *app) offerPremium(s ssh.Session, u *store.User) {
|
|||
|
||||
lines := []string{
|
||||
"",
|
||||
" Upgrade to Premium — " + payments.PremiumPriceLabel + ", one-time:",
|
||||
" • your own email " + a.fe.Address(u.Name) + " (forwards to you)",
|
||||
" ★ Founding Lifetime Member — $" + payments.PremiumAmount() + ", one-time",
|
||||
" Only the first " + payments.FoundingCap + " accounts. Pay once, keep it for life.",
|
||||
"",
|
||||
" Everything in your free membership stays free — founding adds these",
|
||||
" bonus features, forever:",
|
||||
" • your own email " + a.fe.Address(u.Name) + " (forwards to you, webmail included)",
|
||||
" • custom domains point yourdomain.com at your homepage",
|
||||
" • Tor access ssh tor@" + a.host + " — fetch URLs & join IRC over Tor",
|
||||
" • locked-in price founding rate is yours for life — never renew, never pay again",
|
||||
"",
|
||||
}
|
||||
if c, ok, err := payments.CreatePremiumCharge(ref); ok && err == nil {
|
||||
|
|
@ -739,7 +745,7 @@ func (a *app) handleDomain(s ssh.Session) {
|
|||
_ = s.Exit(1)
|
||||
return
|
||||
}
|
||||
// Custom domains are a Premium perk ($10 lifetime). ensurePremium also
|
||||
// Custom domains are a Founding Lifetime perk ($99 one-time). ensurePremium also
|
||||
// catches a payment that settled since their last visit.
|
||||
if !a.ensurePremium(&u) {
|
||||
wish.Println(s, strings.Join([]string{
|
||||
|
|
@ -883,7 +889,7 @@ func (a *app) torMember(s ssh.Session, route string) (store.User, bool) {
|
|||
return store.User{}, false
|
||||
}
|
||||
if !a.ensurePremium(&u) {
|
||||
wish.Println(s, " "+route+" is a Premium feature ($10 lifetime). Upgrade: ssh join@"+a.host)
|
||||
wish.Println(s, " "+route+" is a Founding Lifetime Member feature ($99 one-time, lifetime). Upgrade: ssh join@"+a.host)
|
||||
_ = s.Exit(1)
|
||||
return store.User{}, false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Package payments gates the one-time $10 lifetime Premium membership on
|
||||
// Package payments gates the one-time $99 Founding Lifetime membership on
|
||||
// CoinPay (coinpayportal.com). It talks to the CoinPay REST API directly over
|
||||
// HTTP — no `coinpay` CLI needs to be installed on the host.
|
||||
//
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// COINPAY_API_KEY Bearer key for the CoinPay API (cp_live_…)
|
||||
// AGENTBBS_COINPAY_MERCHANT_ID merchant/business id payments are created under
|
||||
// AGENTBBS_COINPAY_API_URL API base (default https://coinpayportal.com/api)
|
||||
// AGENTBBS_PREMIUM_AMOUNT fiat amount (default 10)
|
||||
// AGENTBBS_PREMIUM_AMOUNT fiat amount (default 99)
|
||||
// AGENTBBS_PREMIUM_CURRENCY fiat currency (default USD)
|
||||
// AGENTBBS_PREMIUM_BLOCKCHAIN settlement chain (default eth)
|
||||
//
|
||||
|
|
@ -35,11 +35,15 @@ const PodTerm = 31 * 24 * time.Hour
|
|||
|
||||
// PremiumPriceLabel is the human-readable price for the one-time lifetime
|
||||
// membership offered at join@.
|
||||
const PremiumPriceLabel = "$10 (lifetime)"
|
||||
const PremiumPriceLabel = "$99 (lifetime)"
|
||||
|
||||
// FoundingCap is the marketing cap on Founding Lifetime memberships — the offer
|
||||
// is pitched as available to the first this-many accounts.
|
||||
const FoundingCap = "1,000"
|
||||
|
||||
// Premium charge parameters — overridable via env so the offer can change
|
||||
// without a rebuild.
|
||||
func PremiumAmount() string { return envOr("AGENTBBS_PREMIUM_AMOUNT", "10") }
|
||||
func PremiumAmount() string { return envOr("AGENTBBS_PREMIUM_AMOUNT", "99") }
|
||||
func PremiumCurrency() string { return envOr("AGENTBBS_PREMIUM_CURRENCY", "USD") }
|
||||
func PremiumBlockchain() string { return envOr("AGENTBBS_PREMIUM_BLOCKCHAIN", "eth") }
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ type Store interface {
|
|||
// SetPremiumPayment records the CoinPay payment id of a pending premium
|
||||
// charge so a later visit can verify whether it settled.
|
||||
SetPremiumPayment(userID int64, payID string) error
|
||||
// GrantPremium marks the account as a lifetime premium member (the $10
|
||||
// one-time membership), recording the CoinPay payment reference. Idempotent.
|
||||
// GrantPremium marks the account as a lifetime premium member (the $99
|
||||
// Founding Lifetime membership), recording the CoinPay payment reference. Idempotent.
|
||||
GrantPremium(userID int64, paymentRef string) error
|
||||
|
||||
RecordSession(userID int64, username, remote, route string) (int64, error)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue