Add Technical Kiwi website with Go, templ, and HTMX.

Single-page site with gallery by album and event, contact form over SMTP,
Docker dev/prod setup, and on-server image derivatives. Gallery photos stay
local (app/images/ is gitignored).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-25 23:57:59 +12:00
parent c21be097b0
commit 509e7ccb43
33 changed files with 2635 additions and 1 deletions

View File

@@ -0,0 +1,71 @@
package mail
import (
"fmt"
"os"
"strconv"
)
// Config holds SMTP relay settings from the environment.
type Config struct {
Host string
Port int
User string
Password string
From string
To string
// TLS: "auto" (STARTTLS on 587, plain on 25), "tls" (implicit TLS, e.g. 465), "plain"
TLS string
}
// Load reads SMTP settings from environment variables.
//
// Required: SMTP_HOST, SMTP_FROM, SMTP_TO
// Optional: SMTP_PORT (587), SMTP_USER, SMTP_PASSWORD, SMTP_TLS (auto)
func Load() (Config, error) {
host := os.Getenv("SMTP_HOST")
if host == "" {
return Config{}, fmt.Errorf("SMTP_HOST is required")
}
from := os.Getenv("SMTP_FROM")
if from == "" {
return Config{}, fmt.Errorf("SMTP_FROM is required")
}
to := os.Getenv("SMTP_TO")
if to == "" {
return Config{}, fmt.Errorf("SMTP_TO is required")
}
port := 587
if p := os.Getenv("SMTP_PORT"); p != "" {
n, err := strconv.Atoi(p)
if err != nil {
return Config{}, fmt.Errorf("SMTP_PORT: %w", err)
}
port = n
}
tls := os.Getenv("SMTP_TLS")
if tls == "" {
tls = "auto"
}
return Config{
Host: host,
Port: port,
User: os.Getenv("SMTP_USER"),
Password: os.Getenv("SMTP_PASSWORD"),
From: from,
To: to,
TLS: tls,
}, nil
}
// Enabled reports whether relay settings are present.
func Enabled() bool {
return os.Getenv("SMTP_HOST") != "" &&
os.Getenv("SMTP_FROM") != "" &&
os.Getenv("SMTP_TO") != ""
}