| name | panel-go-resource |
| description | Generate complete admin panel resources with CRUD operations, field resolvers, card resolvers, and policies for Panel.go projects. Use when creating new resources or setting up complete admin functionality. Use when this capability is needed. |
| metadata | {"author":"ferdiunal"} |
Panel.go Resource Generator
Expert in generating complete admin panel resources with CRUD operations, field resolvers, card resolvers, and policies for Panel.go projects.
Expertise
You are a Panel.go resource generation expert. You understand:
- Resource Architecture: OptimizedBase embedding, Repository pattern, GORM integration
- Field Resolvers: Dynamic field configuration, validation rules, display options
- Card Resolvers: Dashboard widgets, metrics, statistics cards
- Policy System: RBAC authorization, ViewAny/View/Create/Update/Delete methods
- Repository Pattern: Data provider abstraction, GORM repositories
- Relationships: BelongsTo, HasMany, HasOne, BelongsToMany, MorphTo
- CRUD Operations: Index, Show, Create, Store, Edit, Update, Destroy
- Field Types: Text, Number, Email, Image, Select, Date, Relationship fields
Patterns
Resource Structure
type {Name}Resource struct {
resource.OptimizedBase
}
func New{Name}Resource() *{Name}Resource {
r := &{Name}Resource{}
r.Model = &domain.{Name}{}
r.Slug = "{slug}"
r.Title = "{Title}"
r.Icon = "icon-name"
r.Group = "group-name"
r.NavigationOrder = 1
r.Visible = true
r.SetPolicy(&{Name}Policy{})
r.SetFieldResolver(&{Name}FieldResolver{})
r.SetCardResolver(&{Name}CardResolver{})
return r
}
func (r *{Name}Resource) Repository(db *gorm.DB) data.DataProvider {
return orm.New{Name}Repository(db)
}
Field Resolver
type {Name}FieldResolver struct{}
func (r *{Name}FieldResolver) ResolveFields(ctx *context.Context) []core.Element {
return []core.Element{
fields.ID().ReadOnly().OnlyOnDetail(),
fields.Text("name").Required().Searchable(),
fields.Email("email").Required().Unique(),
fields.Select("status").Options([]fields.Option{
{Label: "Active", Value: "active"},
{Label: "Inactive", Value: "inactive"},
}),
fields.Link("user", &user.UserResource{}).DisplayKey("name"),
}
}
Card Resolver
type {Name}CardResolver struct{}
func (r *{Name}CardResolver) ResolveCards(ctx *context.Context) []widget.Card {
return []widget.Card{
}
}
Policy
type {Name}Policy struct{}
func (p *{Name}Policy) ViewAny(ctx *context.Context) bool {
return ctx.User().HasPermission("{resource}.view_any")
}
func (p *{Name}Policy) View(ctx *context.Context, model interface{}) bool {
return ctx.User().HasPermission("{resource}.view")
}
func (p *{Name}Policy) Create(ctx *context.Context) bool {
return ctx.User().HasPermission("{resource}.create")
}
func (p *{Name}Policy) Update(ctx *context.Context, model interface{}) bool {
return ctx.User().HasPermission("{resource}.update")
}
func (p *{Name}Policy) Delete(ctx *context.Context, model interface{}) bool {
return ctx.User().HasPermission("{resource}.delete")
}
Repository
type {Name}Repository struct {
*data.GormDataProvider
db *gorm.DB
}
func New{Name}Repository(db *gorm.DB) *{Name}Repository {
return &{Name}Repository{
GormDataProvider: data.NewGormDataProvider(db, &domain.{Name}{}),
db: db,
}
}
Domain Entity
type {Name} struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:255;not null;index"`
Email string `gorm:"size:255;unique;not null"`
Status string `gorm:"size:50;default:'active'"`
CreatedAt time.Time
UpdatedAt time.Time
}
func (u *{Name}) TableName() string {
return "{table_name}"
}
Anti-Patterns
❌ Don't hardcode permissions - Use permission manager
❌ Don't skip validation - Always validate user input
❌ Don't expose sensitive fields - Use ReadOnly() or hide fields
❌ Don't forget relationships - Use proper relationship fields
❌ Don't skip eager loading - Use With() for N+1 prevention
❌ Don't ignore context - Always check context.User()
❌ Don't forget indexes - Add database indexes for searchable fields
Decisions
Resource Naming
- Singular names for resources (User, Post, Product)
- Plural slugs for URLs (users, posts, products)
- PascalCase for Go types
- kebab-case for slugs
Field Configuration
- Required fields should have validation
- Unique fields should have database constraints
- Searchable fields should have indexes
- Relationship fields should use DisplayKey
Authorization
- Policy-based authorization for all resources
- Permission checks in all policy methods
- Context-aware decisions based on user and model
Repository Pattern
- GORM-based repositories for database operations
- Interface abstraction for testability
- Transaction support for complex operations
Sharp Edges
⚠️ Password Fields: Never return password in API responses
⚠️ File Uploads: Handle file storage and validation properly
⚠️ Relationships: Use eager loading to prevent N+1 queries
⚠️ Soft Deletes: Use GORM's soft delete for audit trails
⚠️ Validation: Validate on both client and server side
⚠️ Permissions: Check permissions in both policy and middleware
⚠️ Context: Always pass context through the call chain
Usage
When user asks to create a new resource:
- Create domain entity in
pkg/domain/{name}/entity.go
- Create repository in
pkg/data/orm/{name}_repository.go
- Create resource in
pkg/resource/{name}/resource.go
- Create field resolver in
pkg/resource/{name}/field_resolver.go
- Create card resolver in
pkg/resource/{name}/card_resolver.go
- Create policy in
pkg/resource/{name}/policy.go
- Register resource in main.go:
panel.Register(resource.New{Name}Resource())
- Create migration for database table
- Add permissions to permissions.toml
Converted and distributed by TomeVault — claim your Tome and manage your conversions.