admin

package
v0.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 36 Imported by: 0

Documentation

Overview

Package admin is Gombit's runtime generic admin (ADMIN-1 through ADMIN-3 / ADR-013).

Feature packages register models explicitly:

admin.Register(app, Product{}, admin.Options{Slug: "products", ...})

framework.New mounts the Huma introspection and data-plane routes, and the /admin/ SPA, only when cookie session auth is on (cfg.Auth.Mode == cookie). JWT-only apps do not get admin routes. Admin requests enforce the registered permission keys; auth.User.IsSuperuser bypasses those checks.

Options is the source of truth. After Register returns, handlers read stored values and GORM constructors — they do not reflect over arbitrary Go types. FieldsFrom and the empty-Fields default may use reflect only inside Register; both are registration-time conveniences.

Index

Constants

View Source
const (
	RelBelongsTo  = string(field.RelBelongsTo)
	RelHasMany    = string(field.RelHasMany)
	RelManyToMany = string(field.RelManyToMany)
	RelOneToOne   = string(field.RelOneToOne)
)

Relation kinds for v1. Defined in package field.

View Source
const (
	ImplicitCreatedAt = "created_at"
	ImplicitUpdatedAt = "updated_at"
)

Implicit timestamp names allowed in List and Ordering even when omitted from Fields. They are GORM's default created_at / updated_at columns.

Variables

This section is empty.

Functions

func Mount

func Mount(host Host) error

Mount registers the admin Huma routes on host.API() when cookie auth is on. The catalog is empty until Register is called. framework.New calls Mount automatically in cookie mode; JWT-only apps must not call it.

func Register

func Register[T any](host Host, model T, opts Options) error

Register adds model T to the host's admin registry.

host is typically *framework.App. Missing or duplicate Slug is an error. Cookie auth must already be on (framework.New mounts the empty admin routes in that mode). After Register returns, the registry holds concrete Options values plus constructors for T; request handlers do not walk arbitrary Go types.

Types

type Actions

type Actions struct {
	List   bool `json:"list"`
	Detail bool `json:"detail"`
	Create bool `json:"create"`
	Update bool `json:"update"`
	Delete bool `json:"delete"`
}

Actions names which data-plane operations are enabled for a model.

type AuthMeta

type AuthMeta struct {
	Mode      string `json:"mode"`
	Bootstrap string `json:"bootstrap"`
}

AuthMeta tells the SPA which authorization rule guards the catalog.

type Capabilities

type Capabilities struct {
	View   bool `json:"view"`
	Create bool `json:"create"`
	Update bool `json:"update"`
	Delete bool `json:"delete"`
}

Capabilities are the current user's enabled actions for one model.

type Catalog

type Catalog struct {
	Models []ModelMeta `json:"models"`
}

Catalog is the GET /admin/meta success data object.

type CatalogAux

type CatalogAux struct {
	Auth *AuthMeta `json:"auth,omitempty"`
}

CatalogAux is optional envelope meta on the catalog.

type Choice added in v0.3.0

type Choice struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

Choice is one enum entry: the stored value and the label the admin shows.

type Field

type Field struct {
	Name     string    `json:"name"`
	Type     FieldType `json:"type"`
	Required bool      `json:"required"`
	ReadOnly bool      `json:"readonly"`
	Related  *Relation `json:"related,omitempty"`
	// Constraints copied from the model's validate tag when the registrar
	// leaves them empty. Strings so a decimal bound survives JSON.
	Minimum   string `json:"minimum,omitempty"`
	Maximum   string `json:"maximum,omitempty"`
	MaxLength int    `json:"max_length,omitempty"`
	Pattern   string `json:"pattern,omitempty"`
	// TagPattern is the pattern struct tag, kept apart from a validate
	// regex. make resource writes the slug alphabet here. A user regex
	// does not change the catalog kind.
	TagPattern string `json:"-"`
	Default    string `json:"default,omitempty"`
	// Format is the OpenAPI format from the model tag (email, uri, ip, time,
	// duration). The admin wire for email stays string; time and duration
	// have their own wires. Writes reject a value that fails the format.
	Format string `json:"format,omitempty"`
	// Choices are the stored value and display label of an enum. Empty
	// when the column is not an enum.
	Choices []Choice `json:"choices,omitempty"`
	// Column is the GORM/SQL column name. Empty means Name == JSON key ==
	// column (the v1 default). When set, it alone picks the model field the
	// admin reads and writes (Name is then only the JSON key); a column the
	// model does not have is a registration error. Not emitted in meta.
	Column string `json:"-"`
	// WriteOnly matches a public create field that is omitted from the
	// response (`gombit:"write"`). Row payloads leave it out. An update
	// applies it only when the body contains a new value.
	WriteOnly bool `json:"writeonly,omitempty"`
	// Accept and MaxBytes are a file or image field's upload policy (the
	// model's storage tag): the media types it accepts and its largest
	// file. Set at registration; the admin form uses them as hints, and
	// the server enforces them.
	Accept   []string `json:"accept,omitempty"`
	MaxBytes int64    `json:"max_bytes,omitempty"`
	// contains filtered or unexported fields
}

Field describes one registered admin field.

Name is the JSON object key used in meta and in data-plane row payloads. For v1, Name is also the GORM/SQL column unless Column is set (when the Go exported name or GORM column differs from the JSON key).

func FieldsFrom

func FieldsFrom(model any) ([]Field, error)

FieldsFrom derives a default []Field from model at registration time. It may use reflect on this one type. Do not call it from request handlers.

Name comes from the json tag when present, otherwise the GORM column / snake_case of the exported field name. Type is inferred from the Go type. Read, write, and hidden follow resourcepolicy — the same gombit tag the generated API uses — so a column cannot be secret on the public contract and editable here. An auto-increment primary key and GORM timestamps stay read-only. A manual primary key stays in the create request and is required; update rejects a different key. GORM created_at / updated_at are included when the policy leaves them on the response.

type FieldMeta

type FieldMeta struct {
	Name     string    `json:"name"`
	Type     FieldType `json:"type"`
	Required bool      `json:"required"`
	ReadOnly bool      `json:"readonly"`
	// WriteOnly is a create field the response omits (`gombit:"write"`).
	// The edit form leaves the key out until the operator sets a value.
	WriteOnly bool      `json:"writeonly,omitempty"`
	Related   *Relation `json:"related,omitempty"`
	Minimum   string    `json:"minimum,omitempty"`
	Maximum   string    `json:"maximum,omitempty"`
	MaxLength int       `json:"max_length,omitempty"`
	Pattern   string    `json:"pattern,omitempty"`
	Default   string    `json:"default,omitempty"`
	Format    string    `json:"format,omitempty"`
	Choices   []Choice  `json:"choices,omitempty"`
	// Accept and MaxBytes: a file or image field's upload policy, as hints
	// for the form (the server enforces them).
	Accept   []string `json:"accept,omitempty"`
	MaxBytes int64    `json:"max_bytes,omitempty"`
}

FieldMeta is the introspection shape of a field (no Column).

type FieldType

type FieldType string

FieldType is a closed admin field type string.

const (
	TypeString   FieldType = FieldType(field.String)
	TypeText     FieldType = FieldType(field.Text)
	TypeInteger  FieldType = FieldType(field.Integer)
	TypeFloat    FieldType = FieldType(field.Float)
	TypeDecimal  FieldType = FieldType(field.Decimal)
	TypeBoolean  FieldType = FieldType(field.Boolean)
	TypeDateTime FieldType = FieldType(field.DateTime)
	TypeDate     FieldType = FieldType(field.Date)
	TypeTime     FieldType = FieldType(field.TimeOfDay)
	TypeDuration FieldType = FieldType(field.Duration)
	TypeUUID     FieldType = FieldType(field.UUID)
	TypeJSON     FieldType = FieldType(field.JSON)
	TypeRelation FieldType = FieldType(field.Relation)
	// TypeFile and TypeImage are storage-backed: the column holds an object
	// key; rows carry a file object; writes take the key of an upload
	// granted by the admin's upload endpoint.
	TypeFile  FieldType = FieldType(field.File)
	TypeImage FieldType = FieldType(field.Image)
)

Admin meta type strings. These are the admin projection of field.Kind (see docs/fields.md). Do not add a wire string that package field does not already list.

type Host

type Host interface {
	API() huma.API
	DB() *gorm.DB
	Config() config.Config
}

Host is satisfied by *framework.App. It is defined here so this package does not import framework (framework.New calls Mount).

type ModelMeta

type ModelMeta struct {
	Slug        string       `json:"slug"`
	Singular    string       `json:"singular"`
	Plural      string       `json:"plural"`
	PK          string       `json:"pk"`
	Fields      []FieldMeta  `json:"fields"`
	List        []string     `json:"list"`
	Search      []string     `json:"search"`
	Filter      []string     `json:"filter"`
	Ordering    []string     `json:"ordering"`
	Actions     Actions      `json:"actions"`
	Permissions Permissions  `json:"permissions"`
	Can         Capabilities `json:"can"`
}

ModelMeta is one registered model in the introspection API.

type Options

type Options struct {
	// Slug is the URL key (products). Required, lowercase, unique per app.
	Slug string
	// Singular and Plural are UI labels. Empty values are derived at Register
	// from the Go type name and slug.
	Singular string
	Plural   string
	// PK is the JSON/field name of the primary key. Empty means derive the
	// GORM primary key at Register and store it.
	PK string
	// Fields is the concrete field list handlers read. Empty means derive a
	// default from the struct once, inside Register (see FieldsFrom).
	Fields []Field
	// List is the list-view column order.
	List []string
	// Search is the list of field names the search query param applies to.
	Search []string
	// Filter is the list of field names that may appear as list query keys.
	Filter []string
	// Ordering is the list of field names the ordering query param may use.
	// created_at and updated_at may appear here even if omitted from Fields.
	Ordering []string
	// Actions enables list / detail / create / update / delete. The zero
	// value (all false) defaults to all enabled.
	Actions Actions
	// Permissions are authorization keys enforced by the admin handlers.
	// Empty values default to admin.{slug}.{action}.
	Permissions Permissions
}

Options is the source of truth for one registered admin model.

type Permissions

type Permissions struct {
	View   string `json:"view"`
	Create string `json:"create"`
	Update string `json:"update"`
	Delete string `json:"delete"`
}

Permissions holds the keys enforced for each admin operation.

type Relation

type Relation struct {
	Slug       string `json:"slug"`
	Kind       string `json:"kind"`
	LabelField string `json:"label_field"`
}

Relation describes a belongs_to, has_many, or many_to_many field (#223).

  • belongs_to is stored as the foreign key on create/update.
  • has_many is read-only. When the field maps to a real GORM has_many association (the usual case, and what auto-derivation emits), list/detail preload it and the data plane returns the related children's primary keys; a has_many field declared without a matching association is meta-only and reads empty. Writes to a has_many field are always rejected.
  • many_to_many reads the related primary keys and, on write, syncs the join table to the submitted id list.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL