fix(finance): seed admin account in finance_users on startup (#37)

SeedAdmin now creates the finance_users account from ADMIN_EMAIL /
ADMIN_PASSWORD env vars if it doesn't exist, so a fresh cluster
bootstraps a working login without manual registration.

Wires ADMIN_EMAIL and ADMIN_PASSWORD into the deployment from the
finance-api-secrets k8s secret (optional — pod still starts without it).

Also gitignores /main build artifact and *.test binaries.

Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gonçalo Rodrigues 2026-06-26 17:43:59 +01:00 committed by GitHub
parent dcb573ed8a
commit 292b2f46f0
3 changed files with 47 additions and 3 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@
# node
node_modules
# go build artifacts
/main
*.test

View File

@ -33,6 +33,18 @@ spec:
value: "jaeger.monitoring.svc:4317"
- name: BASE_URL
value: "https://finance.homelab.local"
- name: ADMIN_EMAIL
valueFrom:
secretKeyRef:
name: finance-api-secrets
key: ADMIN_EMAIL
optional: true
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: finance-api-secrets
key: ADMIN_PASSWORD
optional: true
envFrom:
- secretRef:
name: mongodb-shared-config

View File

@ -8,17 +8,45 @@ import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
"golang.org/x/crypto/bcrypt"
)
// SeedAdmin looks up the admin user by email directly in the shared MongoDB
// (both services use the same DB) and seeds demo data if the account has no
// existing transactions.
// SeedAdmin ensures an admin account exists in finance_users, then seeds demo
// data if the account has no existing transactions.
func SeedAdmin(ctx context.Context, store *Store) {
email := os.Getenv("SEED_USER_EMAIL")
if email == "" {
email = "admin@homelab.local"
}
if _, err := store.findAuthUserByEmail(ctx, email); err != nil {
password := os.Getenv("ADMIN_PASSWORD")
if password == "" {
slog.Warn("seed: no finance_users account and ADMIN_PASSWORD not set, skipping", "email", email)
} else {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
if err != nil {
slog.Error("seed: bcrypt failed", "err", err)
return
}
name := os.Getenv("ADMIN_NAME")
if name == "" {
name = "Admin"
}
u := &AuthUser{
Email: email,
Name: name,
PasswordHash: string(hash),
CreatedAt: time.Now(),
}
if err := store.createAuthUser(ctx, u); err != nil {
slog.Error("seed: create admin user failed", "err", err)
return
}
slog.Info("seed: created admin user", "email", email)
}
}
userID, err := lookupUserByEmailMongo(ctx, store, email)
if err != nil {
slog.Warn("seed: could not resolve admin user, skipping", "email", email, "err", err)