refactor(db): replace sqlc with handwritten pgx repos

- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs
- Renumber migrations; add 00012 memberships+manage_token,
  00013 location_type_capacity
- Add tests: admin, auth, bookings customer service
- Remove graphify-out artifacts and stale env files

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-17 20:21:34 +02:00
1 parent 2039669e2c
commit f2f7439050
93 files changed
+6987 -69060

No files matched your search

+3 -50
View File
@@ -24,10 +24,6 @@ type Config struct {
SMTPPort string
SMTPUsername string
SMTPPassword string
PaddleEnvironment string
PaddleAPIKey string
PaddleWebhookKey string
PaddlePriceMatrix map[string]map[string]string
StripeAPIKey string
StripeWebhookKey string
StripePriceMatrix map[string]map[string]string
@@ -58,10 +54,6 @@ func Load() (Config, error) {
SMTPPort: valueOrDefault("BOOKRA_SMTP_PORT", "587"),
SMTPUsername: strings.TrimSpace(os.Getenv("BOOKRA_SMTP_USERNAME")),
SMTPPassword: strings.TrimSpace(os.Getenv("BOOKRA_SMTP_PASSWORD")),
PaddleEnvironment: normalizePaddleEnvironment(os.Getenv("BOOKRA_PADDLE_ENV")),
PaddleAPIKey: strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_API_KEY")),
PaddleWebhookKey: strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_WEBHOOK_SECRET")),
PaddlePriceMatrix: paddlePriceMatrixFromEnv(),
StripeAPIKey: strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_API_KEY")),
StripeWebhookKey: strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_WEBHOOK_SECRET")),
StripePriceMatrix: stripePriceMatrixFromEnv(),
@@ -110,19 +102,6 @@ func (cfg Config) validateRuntimeRequirements() error {
return nil
}
func (cfg Config) PaddleConfigured() bool {
return strings.TrimSpace(cfg.PaddleAPIKey) != ""
}
func (cfg Config) PaddleWebhookConfigured() bool {
return strings.TrimSpace(cfg.PaddleWebhookKey) != ""
}
func (cfg Config) PaddleCheckoutConfigured(planCode string) bool {
planCode = shared.NormalizePlanCode(planCode)
return cfg.PaddleConfigured() && cfg.PaddleWebhookConfigured() && cfg.PaddlePriceMatrix[planCode]["czk"] != "" && cfg.PaddlePriceMatrix[planCode]["usd"] != ""
}
func (cfg Config) StripeConfigured() bool {
return strings.TrimSpace(cfg.StripeAPIKey) != ""
}
@@ -137,18 +116,15 @@ func (cfg Config) StripeCheckoutConfigured(planCode string) bool {
}
func (cfg Config) BillingProvider() string {
if cfg.StripeConfigured() {
return "stripe"
}
return "paddle"
return "stripe"
}
func (cfg Config) BillingConfigured() bool {
return cfg.StripeConfigured() || cfg.PaddleConfigured()
return cfg.StripeConfigured()
}
func (cfg Config) BillingWebhookConfigured() bool {
return cfg.StripeWebhookConfigured() || cfg.PaddleWebhookConfigured()
return cfg.StripeWebhookConfigured()
}
func (cfg Config) SMSConfigured() bool {
@@ -170,20 +146,6 @@ func (cfg Config) StripeSMSPriceID(currency string) string {
return cfg.StripeSMSPriceMatrix["czk"]
}
func paddlePriceMatrixFromEnv() map[string]map[string]string {
matrix := map[string]map[string]string{
"starter": {},
"pro": {},
"business": {},
}
for _, planCode := range []string{"starter", "pro", "business"} {
envPlan := strings.ToUpper(strings.ReplaceAll(planCode, "-", "_"))
matrix[planCode]["czk"] = strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_" + envPlan + "_CZK_PRICE_ID"))
matrix[planCode]["usd"] = strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_" + envPlan + "_USD_PRICE_ID"))
}
return matrix
}
func stripePriceMatrixFromEnv() map[string]map[string]string {
matrix := map[string]map[string]string{
"starter": {},
@@ -210,15 +172,6 @@ func stripePriceMatrixFromEnv() map[string]map[string]string {
return matrix
}
func normalizePaddleEnvironment(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "live", "production":
return "live"
default:
return "sandbox"
}
}
func valueOrDefault(key string, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
+19 -13
View File
@@ -2,31 +2,37 @@ package config
import "testing"
func TestPaddleCheckoutConfigured(t *testing.T) {
func TestStripeCheckoutConfigured(t *testing.T) {
cfg := Config{
PaddleAPIKey: "pdl_sdbx_apikey_123",
PaddleWebhookKey: "pdl_ntf_123",
PaddlePriceMatrix: map[string]map[string]string{
"starter": {"czk": "pri_starter_czk", "usd": "pri_starter_usd"},
"pro": {"czk": "pri_pro_czk", "usd": "pri_pro_usd"},
"business": {"czk": "pri_business_czk", "usd": "pri_business_usd"},
StripeAPIKey: "sk_test_123",
StripeWebhookKey: "whsec_test_123",
StripePriceMatrix: map[string]map[string]string{
"starter": {"czk": "price_starter_czk", "usd": "price_starter_usd"},
"pro": {"czk": "price_pro_czk", "usd": "price_pro_usd"},
"business": {"czk": "price_business_czk", "usd": "price_business_usd"},
},
}
if !cfg.PaddleCheckoutConfigured("pro") {
if !cfg.StripeCheckoutConfigured("pro") {
t.Fatal("expected pro checkout configured")
}
}
func TestPaddleCheckoutConfiguredRequiresWebhook(t *testing.T) {
func TestStripeCheckoutConfiguredRequiresWebhook(t *testing.T) {
cfg := Config{
PaddleAPIKey: "pdl_sdbx_apikey_123",
PaddlePriceMatrix: map[string]map[string]string{
"pro": {"czk": "pri_pro_czk", "usd": "pri_pro_usd"},
StripeAPIKey: "sk_test_123",
StripePriceMatrix: map[string]map[string]string{
"pro": {"czk": "price_pro_czk", "usd": "price_pro_usd"},
},
}
if cfg.PaddleCheckoutConfigured("pro") {
if cfg.StripeCheckoutConfigured("pro") {
t.Fatal("expected checkout disabled without webhook key")
}
}
func TestBillingProviderIsStripe(t *testing.T) {
if (Config{}).BillingProvider() != "stripe" {
t.Fatal("expected stripe billing provider")
}
}