A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
atcr.io
docker
container
atproto
go
1package billing
2
3// Config holds appview billing/Stripe configuration.
4// Parsed from the appview config YAML's billing section.
5type Config struct {
6 // Stripe secret key (sk_test_... or sk_live_...).
7 // Can also be set via STRIPE_SECRET_KEY env var (takes precedence over config).
8 // Billing is enabled automatically when this key is set (requires -tags billing build).
9 StripeSecretKey string `yaml:"stripe_secret_key" comment:"Stripe secret key. Can also be set via STRIPE_SECRET_KEY env var (takes precedence). Billing is enabled automatically when set."`
10
11 // Stripe webhook signing secret (whsec_...).
12 // Can also be set via STRIPE_WEBHOOK_SECRET env var (takes precedence over config).
13 WebhookSecret string `yaml:"webhook_secret" comment:"Stripe webhook signing secret. Can also be set via STRIPE_WEBHOOK_SECRET env var (takes precedence)."`
14
15 // Currency code for Stripe checkout (e.g. "usd").
16 Currency string `yaml:"currency" comment:"ISO 4217 currency code (e.g. \"usd\")."`
17
18 // URL to redirect after successful checkout. {base_url} is replaced at runtime.
19 SuccessURL string `yaml:"success_url" comment:"Redirect URL after successful checkout. Use {base_url} placeholder."`
20
21 // URL to redirect after cancelled checkout. {base_url} is replaced at runtime.
22 CancelURL string `yaml:"cancel_url" comment:"Redirect URL after cancelled checkout. Use {base_url} placeholder."`
23
24 // Subscription tiers with Stripe price IDs.
25 Tiers []BillingTierConfig `yaml:"tiers" comment:"Subscription tiers ordered by rank (lowest to highest)."`
26
27 // Whether hold owners get a supporter badge on their profile.
28 OwnerBadge bool `yaml:"owner_badge" comment:"Show supporter badge on hold owner profiles."`
29}
30
31// BillingTierConfig represents a single tier with optional Stripe pricing.
32type BillingTierConfig struct {
33 // Tier name (matches hold quota tier names for rank mapping).
34 Name string `yaml:"name" comment:"Tier name. Position in list determines rank (0-based)."`
35
36 // Short description shown on the plan card.
37 Description string `yaml:"description,omitempty" comment:"Short description shown on the plan card."`
38
39 // List of features included in this tier (rendered as bullet points).
40 Features []string `yaml:"features,omitempty" comment:"List of features included in this tier."`
41
42 // Stripe price ID for monthly billing. Empty = free tier.
43 StripePriceMonthly string `yaml:"stripe_price_monthly,omitempty" comment:"Stripe price ID for monthly billing. Empty = free tier."`
44
45 // Stripe price ID for yearly billing.
46 StripePriceYearly string `yaml:"stripe_price_yearly,omitempty" comment:"Stripe price ID for yearly billing."`
47
48 // Maximum number of webhooks for this tier (-1 = unlimited).
49 MaxWebhooks int `yaml:"max_webhooks" comment:"Maximum webhooks for this tier (-1 = unlimited)."`
50
51 // Whether all webhook trigger types are available (not just first-scan).
52 WebhookAllTriggers bool `yaml:"webhook_all_triggers" comment:"Allow all webhook trigger types (not just first-scan)."`
53
54 // Whether AI Image Advisor is available for this tier.
55 AIAdvisor bool `yaml:"ai_advisor" comment:"Enable AI Image Advisor for this tier."`
56
57 // Whether this tier earns a supporter badge on user profiles.
58 SupporterBadge bool `yaml:"supporter_badge" comment:"Show supporter badge on user profiles for subscribers at this tier."`
59}
60
61// GetTierByPriceID finds the tier that contains the given Stripe price ID.
62// Returns the tier name and rank, or empty string and -1 if not found.
63func (c *Config) GetTierByPriceID(priceID string) (string, int) {
64 if c == nil || priceID == "" {
65 return "", -1
66 }
67 for i, tier := range c.Tiers {
68 if tier.StripePriceMonthly == priceID || tier.StripePriceYearly == priceID {
69 return tier.Name, i
70 }
71 }
72 return "", -1
73}
74
75// TierRank returns the 0-based rank of a tier by name, or -1 if not found.
76func (c *Config) TierRank(name string) int {
77 if c == nil {
78 return -1
79 }
80 for i, tier := range c.Tiers {
81 if tier.Name == name {
82 return i
83 }
84 }
85 return -1
86}