feat(admin): account roles and the instance_members index
Phase 2 created cloud instances without recording who owns them on this side, because the collection did not exist. The boot backfill reconstructs one member row per instance from the hq-sourced control-plane owner, and marks every existing customer_user an owner — they all created their own account. Backfill lives in models rather than db: db is the connection layer and models already imports it for SeedPlans, so db -> models would cycle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -118,5 +118,25 @@ func EnsureIndexes(ctx context.Context) error {
|
||||
return fmt.Errorf("index %s: %w", idx.coll, err)
|
||||
}
|
||||
}
|
||||
|
||||
// One person holds at most one user in one instance. This is the property
|
||||
// that makes a grant idempotent-by-refusal rather than silently doubling a
|
||||
// projection, and it mirrors users' own (instance_id, email) uniqueness.
|
||||
if _, err := Admin("instance_members").Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
Keys: bson.D{{Key: "instance_id", Value: 1}, {Key: "customer_user_id", Value: 1}},
|
||||
Options: options.Index().SetUnique(true).
|
||||
SetName("instance_customer_user_unique"),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("index instance_members.(instance_id,customer_user_id): %w", err)
|
||||
}
|
||||
for _, keys := range []bson.D{
|
||||
{{Key: "account_id", Value: 1}},
|
||||
{{Key: "customer_user_id", Value: 1}},
|
||||
} {
|
||||
if _, err := Admin("instance_members").Indexes().CreateOne(ctx,
|
||||
mongo.IndexModel{Keys: keys}); err != nil {
|
||||
return fmt.Errorf("index instance_members: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user