feat(admin): module skeleton, config and two database connections

Adds the admin module: env config with fail-fast validation, two MongoDB
connections (its own vantage_admin database plus a narrow path into the
control plane), the boot sequence and the image.

Config refuses to start without a signing key, and both Mongo URIs must
name their database inline -- admin talks to two databases, so a bare
MONGO_DB would be ambiguous about which.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrhid6
2026-07-25 18:58:44 +01:00
co-authored by Claude Opus 5
parent c4f1684304
commit 64eac6dbc7
8 changed files with 332 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
// Package db holds admin's two MongoDB connections.
//
// Admin() is its own database and it owns every collection there. Control() is
// the control plane's database, and admin's access to it is deliberately narrow:
// it reads `instances` and `users`, and writes exactly three licence fields on
// `instances`. Nothing here should ever grow a write path to another collection.
package db
import (
"context"
"fmt"
"time"
"github.com/mrhid6/vantage/admin/internal/config"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
var (
adminDB *mongo.Database
controlDB *mongo.Database
)
func Connect(ctx context.Context, cfg config.Config) error {
ac, err := mongo.Connect(options.Client().ApplyURI(cfg.AdminMongoURI))
if err != nil {
return fmt.Errorf("connect admin mongo: %w", err)
}
if err := ac.Ping(ctx, nil); err != nil {
return fmt.Errorf("ping admin mongo: %w", err)
}
adminDB = ac.Database(cfg.AdminDBName)
cc, err := mongo.Connect(options.Client().ApplyURI(cfg.ControlMongoURI))
if err != nil {
return fmt.Errorf("connect control mongo: %w", err)
}
if err := cc.Ping(ctx, nil); err != nil {
return fmt.Errorf("ping control mongo: %w", err)
}
controlDB = cc.Database(cfg.ControlDBName)
// The control plane must already be deployed and migrated. Without the
// instances collection, injection would silently create it and write
// licence fields into a collection nothing reads.
names, err := controlDB.ListCollectionNames(ctx, map[string]any{"name": "instances"})
if err != nil {
return fmt.Errorf("inspect control database: %w", err)
}
if len(names) == 0 {
return fmt.Errorf("control database %q has no instances collection; deploy and migrate the control plane first", cfg.ControlDBName)
}
return nil
}
func Admin(name string) *mongo.Collection { return adminDB.Collection(name) }
func Control(name string) *mongo.Collection { return controlDB.Collection(name) }
func Ctx() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), 10*time.Second)
}