Stage 10: admin console & dictionary ops (complaint review, hot-reload, broadcasts) (#11)
Tests · Go / test (push) Successful in 7s
Tests · Integration / integration (push) Successful in 13s

This commit was merged in pull request #11.
This commit is contained in:
2026-06-04 07:27:49 +00:00
parent 4c4beace85
commit 3a640a17a4
49 changed files with 2548 additions and 200 deletions
+58
View File
@@ -67,6 +67,16 @@ type Account struct {
UpdatedAt time.Time
}
// Identity is one of an account's platform/email identities, surfaced on the
// admin account-detail view. ExternalID is the platform user id (or the email
// address for an email identity); Confirmed tracks the email confirm-code flow.
type Identity struct {
Kind string
ExternalID string
Confirmed bool
CreatedAt time.Time
}
// Store is the Postgres-backed query surface for accounts and identities.
type Store struct {
db *sql.DB
@@ -187,6 +197,54 @@ func (s *Store) IdentityExternalID(ctx context.Context, accountID uuid.UUID, kin
return row.ExternalID, nil
}
// Identities returns the account's platform/email identities, oldest first, for
// the admin account-detail view.
func (s *Store) Identities(ctx context.Context, accountID uuid.UUID) ([]Identity, error) {
stmt := postgres.SELECT(table.Identities.AllColumns).
FROM(table.Identities).
WHERE(table.Identities.AccountID.EQ(postgres.UUID(accountID))).
ORDER_BY(table.Identities.CreatedAt.ASC())
var rows []model.Identities
if err := stmt.QueryContext(ctx, s.db, &rows); err != nil {
return nil, fmt.Errorf("account: list identities %s: %w", accountID, err)
}
out := make([]Identity, 0, len(rows))
for _, r := range rows {
out = append(out, Identity{Kind: r.Kind, ExternalID: r.ExternalID, Confirmed: r.Confirmed, CreatedAt: r.CreatedAt})
}
return out, nil
}
// ListAccounts returns accounts for the admin user list, newest first, paginated
// by limit and offset.
func (s *Store) ListAccounts(ctx context.Context, limit, offset int) ([]Account, error) {
stmt := postgres.SELECT(table.Accounts.AllColumns).
FROM(table.Accounts).
ORDER_BY(table.Accounts.CreatedAt.DESC()).
LIMIT(int64(limit)).
OFFSET(int64(offset))
var rows []model.Accounts
if err := stmt.QueryContext(ctx, s.db, &rows); err != nil {
return nil, fmt.Errorf("account: list accounts: %w", err)
}
out := make([]Account, 0, len(rows))
for _, r := range rows {
out = append(out, modelToAccount(r))
}
return out, nil
}
// CountAccounts returns the total number of accounts, for admin-list pagination.
func (s *Store) CountAccounts(ctx context.Context) (int, error) {
stmt := postgres.SELECT(postgres.COUNT(table.Accounts.AccountID).AS("count")).
FROM(table.Accounts)
var dest struct{ Count int64 }
if err := stmt.QueryContext(ctx, s.db, &dest); err != nil {
return 0, fmt.Errorf("account: count accounts: %w", err)
}
return int(dest.Count), nil
}
// findByIdentity joins identities to accounts and returns the matching account,
// or ErrNotFound.
func (s *Store) findByIdentity(ctx context.Context, kind, externalID string) (Account, error) {