| 1 |
// Package app is the self-hosted, Postgres-backed side of Spread: subscribers,
|
| 2 |
// users, sessions, the admin CMS, and the customer dashboard. It is imported
|
| 3 |
// only by the standalone binary (main.go), never by the Vercel function, so
|
| 4 |
// the public demo stays dependency-light.
|
| 5 |
package app
|
| 6 |
|
| 7 |
import (
|
| 8 |
"context"
|
| 9 |
_ "embed"
|
| 10 |
"fmt"
|
| 11 |
|
| 12 |
"github.com/jackc/pgx/v5/pgxpool"
|
| 13 |
)
|
| 14 |
|
| 15 |
//go:embed schema.sql
|
| 16 |
var schemaSQL string
|
| 17 |
|
| 18 |
// App holds the database pool and shared configuration for all handlers.
|
| 19 |
type App struct {
|
| 20 |
pool *pgxpool.Pool
|
| 21 |
secureCookie bool
|
| 22 |
baseURL string
|
| 23 |
mailer Mailer
|
| 24 |
}
|
| 25 |
|
| 26 |
// Config configures the application. Only DSN is required; the rest have sane
|
| 27 |
// defaults so the CLI helpers can open with a bare Config.
|
| 28 |
type Config struct {
|
| 29 |
DSN string
|
| 30 |
SecureCookie bool
|
| 31 |
BaseURL string
|
| 32 |
Mailer Mailer
|
| 33 |
}
|
| 34 |
|
| 35 |
// Open connects to Postgres, verifies the connection, and applies the schema.
|
| 36 |
func Open(ctx context.Context, cfg Config) (*App, error) {
|
| 37 |
pool, err := pgxpool.New(ctx, cfg.DSN)
|
| 38 |
if err != nil {
|
| 39 |
return nil, fmt.Errorf("connect: %w", err)
|
| 40 |
}
|
| 41 |
if err := pool.Ping(ctx); err != nil {
|
| 42 |
pool.Close()
|
| 43 |
return nil, fmt.Errorf("ping: %w", err)
|
| 44 |
}
|
| 45 |
if _, err := pool.Exec(ctx, schemaSQL); err != nil {
|
| 46 |
pool.Close()
|
| 47 |
return nil, fmt.Errorf("apply schema: %w", err)
|
| 48 |
}
|
| 49 |
if cfg.Mailer == nil {
|
| 50 |
cfg.Mailer = LogMailer{}
|
| 51 |
}
|
| 52 |
if cfg.BaseURL == "" {
|
| 53 |
cfg.BaseURL = "http://localhost:8137"
|
| 54 |
}
|
| 55 |
return &App{pool: pool, secureCookie: cfg.SecureCookie, baseURL: cfg.BaseURL, mailer: cfg.Mailer}, nil
|
| 56 |
}
|
| 57 |
|
| 58 |
func (a *App) Close() {
|
| 59 |
if a.pool != nil {
|
| 60 |
a.pool.Close()
|
| 61 |
}
|
| 62 |
}
|