diff --git a/README.md b/README.md index 28a60a0..25851e3 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/cmd/agentbbs/main.go b/cmd/agentbbs/main.go index 0deda86..83cbdc2 100644 --- a/cmd/agentbbs/main.go +++ b/cmd/agentbbs/main.go @@ -5,7 +5,7 @@ // ssh bbs@host the BBS hub, guests welcome (play@/guest@ are aliases) // ssh @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 } diff --git a/internal/payments/payments.go b/internal/payments/payments.go index f05bae5..77158cd 100644 --- a/internal/payments/payments.go +++ b/internal/payments/payments.go @@ -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") } diff --git a/internal/store/store.go b/internal/store/store.go index 0e168ef..d4ddcdc 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -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)