Framework

The framework layer, on top of core

framework and framework/ui sit on top of the primitives. Declare an entity and get the database, API, and tools; compose screens from components that already match your theme.

entitiesauthaccess controlmigrationscomponentstheming

Entities

Declare an entity in Go — fields, types, relations. One call gives you the table, REST endpoints, validation, an OpenAPI entry, and MCP tools.

main.go
9 lines
app.Entity("posts", framework.EntityConfig{    Exposure: &framework.ExposureConfig{Public: true},    Fields: []schema.Field{        {Name: "title", Type: schema.String, Required: true},        {Name: "body", Type: schema.Text},        {Name: "status", Type: schema.Enum,            Values: []string{"draft", "published"}, Default: "draft"},    },})
/docs/entity-declarations →

Auth

Login, sessions, OAuth, magic-link, 2FA, password reset. Each is a plugin you add to an auth manager; the middleware puts the signed-in user on the request.

auth.go
10 lines
authMgr := auth.New(auth.AuthConfig{    DevMode:      true, // dev only: mints a per-process JWT secret; set JWTSecret in prod    UserStore:    auth.NewEntityUserStore(db, "auth_users"),    SessionStore: auth.NewEntitySessionStore(db, "auth_sessions"),})authMgr.Use(auth.NewCorePlugin())if err := authMgr.Init(fwApp); err != nil {    log.Fatal(err) // without a JWT secret (or DevMode) Init fails closed}fwApp.Use(auth.SessionMiddleware(authMgr))
/docs/auth →

Access control

Roles and permissions, plus per-user owner scoping. It fails closed: a request with no matching policy is denied, not allowed.

entities.go
9 lines
app.Entity("notes", framework.EntityConfig{    Scope: &framework.ScopeConfig{OwnerField: "user_id"}, // every read and write is scoped to the signed-in user    Exposure: &framework.ExposureConfig{        Access: framework.AccessControl{            Read: "notes:read", Create: "notes:write",            Update: "notes:write", Delete: "notes:admin",        },    },})
/docs/access-control →

Migrations

Versioned, ordered, reversible schema changes. In dev the framework can auto-migrate from the declared entities; in production you run the ordered migrations.

main.go
4 lines
// Derive the schema from the declared entities and apply it.if err := framework.AutoMigrate(db, app.Registry); err != nil {    log.Fatal(err)}
/docs/migrations →

Components

framework/ui composes intent, not tags: PageHeader, DataTable, Form, Card, charts. Each ships its own CSS through the theme, so a page inherits your look for free.

screen.go
6 lines
ui.PageHeader(ui.PageHeaderConfig{    Eyebrow:  "Settings",    Title:    "Workspace settings",    Subtitle: "Tune defaults for everyone on this workspace.",    Actions:  ui.Button(ui.ButtonConfig{Label: "Save changes", Variant: ui.ButtonPrimary}),})
/components — the live gallery →

Theming

One typed theme drives every color, space, and font as CSS variables. Change a token and every component updates — you never edit a component's CSS to reskin an app.

theme.go
6 lines
t := theme.Default(theme.Overrides{    Primary:  "oklch(0.82 0.155 78)", // amber accent    Surface:  "oklch(0.17 0.006 75)",    RadiusMd: 6,})site.WithTheme(t)
/docs/theming →