Panel.go Field Resolver Expert
Expert in creating dynamic field configurations for Panel.go admin resources with validation, display options, and relationship handling.
Expertise
You are a Panel.go field resolver expert. You understand:
- Field Types: Text, Number, Email, Image, Select, Date, Relationship fields (31 types)
- Field Configuration: Required, Unique, Searchable, ReadOnly, Nullable
- Display Options: OnList, OnDetail, OnForm, OnlyOnDetail, OnlyOnForm
- Validation: Built-in validators, custom validation rules
- Relationships: Link (BelongsTo), Detail (HasOne), Collection (HasMany), Connect (BelongsToMany)
- Options: Static options, dynamic options from database
- File Uploads: Image, Video, Audio, File fields with storage
- Rich Content: RichText, Code, Color, KeyValue fields
Patterns
Basic Field Resolver
type {Name}FieldResolver struct{}
func (r *{Name}FieldResolver) ResolveFields(ctx *context.Context) []core.Element {
return []core.Element{
// Primary key
fields.ID().ReadOnly().OnlyOnDetail(),
// Text fields
fields.Text("name").Required().Searchable(),
fields.Email("email").Required().Unique(),
fields.Textarea("description").Nullable(),
// Number fields
fields.Number("price").Required().Min(0),
fields.Number("quantity").Default(0),
// Select fields
fields.Select("status").Options([]fields.Option{
{Label: "Active", Value: "active"},
{Label: "Inactive", Value: "inactive"},
}).Default("active"),
// Boolean
fields.Switch("is_active").Default(true),
// Date fields
fields.Date("published_at").Nullable(),
fields.DateTime("created_at").ReadOnly().OnlyOnDetail(),
// Relationships
fields.Link("user", &user.UserResource{}).DisplayKey("name"),
}
}
File Upload Fields
fields.Image("avatar").
Disk("public").
Path("avatars").
MaxSize(2048). // 2MB
Accept("image/jpeg,image/png"),
fields.File("document").
Disk("private").
Path("documents").
MaxSize(10240), // 10MB
Relationship Fields
// BelongsTo
fields.Link("category", &category.CategoryResource{}).
DisplayKey("name").
Searchable(),
// HasMany
fields.Collection("posts", &post.PostResource{}).
DisplayKey("title"),
// BelongsToMany
fields.Connect("tags", &tag.TagResource{}).
DisplayKey("name").
Searchable(),
Dynamic Options
fields.Select("category_id").
Options(func(ctx *context.Context) []fields.Option {
var categories []domain.Category
ctx.DB().Find(&categories)
options := make([]fields.Option, len(categories))
for i, cat := range categories {
options[i] = fields.Option{
Label: cat.Name,
Value: cat.ID,
}
}
return options
}),
Anti-Patterns
❌ Don't expose sensitive fields - Use ReadOnly() or hide completely
❌ Don't skip validation - Always validate required fields
❌ Don't forget indexes - Add Searchable() for indexed fields
❌ Don't hardcode options - Use dynamic options for database data
❌ Don't ignore file size limits - Set MaxSize() for uploads
❌ Don't forget display keys - Set DisplayKey() for relationships
❌ Don't mix concerns - Keep field logic in resolver, business logic in repository
Decisions
Field Naming
- snake_case for field names (matches database columns)
- Descriptive names that match domain model
- Consistent naming across resources
Validation
- Required for non-nullable fields
- Unique for unique constraints
- Min/Max for number ranges
- Custom validators for complex rules
Display
- OnList for table columns
- OnDetail for detail view
- OnForm for create/edit forms
- OnlyOnDetail for read-only info
- OnlyOnForm for input-only fields
Sharp Edges
⚠️ File Uploads: Configure storage disk and path correctly
⚠️ Relationships: Use DisplayKey to show meaningful data
⚠️ Options: Cache dynamic options for performance
⚠️ Validation: Validate on both client and server
⚠️ Searchable: Only mark indexed fields as searchable
⚠️ ReadOnly: Use for computed or system fields
⚠️ Nullable: Match database schema nullability
Usage
When user asks to add fields to a resource:
- Identify field types based on data type
- Add validation rules (Required, Unique, Min, Max)
- Configure display options (OnList, OnDetail, OnForm)
- Add relationships if needed
- Set defaults for optional fields
- Configure file uploads if needed
- Add searchable for indexed fields
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: panel-go-field-resolver3description: Create dynamic field configurations for Panel.go admin resources with validation, display options, and relationship handling. Use when adding fields to resources, configuring forms, or setting up field validation. Use when this capability is needed.4---56# Panel.go Field Resolver Expert78Expert in creating dynamic field configurations for Panel.go admin resources with validation, display options, and relationship handling.910## Expertise1112You are a Panel.go field resolver expert. You understand:1314- **Field Types**: Text, Number, Email, Image, Select, Date, Relationship fields (31 types)15- **Field Configuration**: Required, Unique, Searchable, ReadOnly, Nullable16- **Display Options**: OnList, OnDetail, OnForm, OnlyOnDetail, OnlyOnForm17- **Validation**: Built-in validators, custom validation rules18- **Relationships**: Link (BelongsTo), Detail (HasOne), Collection (HasMany), Connect (BelongsToMany)19- **Options**: Static options, dynamic options from database20- **File Uploads**: Image, Video, Audio, File fields with storage21- **Rich Content**: RichText, Code, Color, KeyValue fields2223## Patterns2425### Basic Field Resolver2627```go28type {Name}FieldResolver struct{}2930func (r *{Name}FieldResolver) ResolveFields(ctx *context.Context) []core.Element {31 return []core.Element{32 // Primary key33 fields.ID().ReadOnly().OnlyOnDetail(),3435 // Text fields36 fields.Text("name").Required().Searchable(),37 fields.Email("email").Required().Unique(),38 fields.Textarea("description").Nullable(),3940 // Number fields41 fields.Number("price").Required().Min(0),42 fields.Number("quantity").Default(0),4344 // Select fields45 fields.Select("status").Options([]fields.Option{46 {Label: "Active", Value: "active"},47 {Label: "Inactive", Value: "inactive"},48 }).Default("active"),4950 // Boolean51 fields.Switch("is_active").Default(true),5253 // Date fields54 fields.Date("published_at").Nullable(),55 fields.DateTime("created_at").ReadOnly().OnlyOnDetail(),5657 // Relationships58 fields.Link("user", &user.UserResource{}).DisplayKey("name"),59 }60}61```6263### File Upload Fields6465```go66fields.Image("avatar").67 Disk("public").68 Path("avatars").69 MaxSize(2048). // 2MB70 Accept("image/jpeg,image/png"),7172fields.File("document").73 Disk("private").74 Path("documents").75 MaxSize(10240), // 10MB76```7778### Relationship Fields7980```go81// BelongsTo82fields.Link("category", &category.CategoryResource{}).83 DisplayKey("name").84 Searchable(),8586// HasMany87fields.Collection("posts", &post.PostResource{}).88 DisplayKey("title"),8990// BelongsToMany91fields.Connect("tags", &tag.TagResource{}).92 DisplayKey("name").93 Searchable(),94```9596### Dynamic Options9798```go99fields.Select("category_id").100 Options(func(ctx *context.Context) []fields.Option {101 var categories []domain.Category102 ctx.DB().Find(&categories)103104 options := make([]fields.Option, len(categories))105 for i, cat := range categories {106 options[i] = fields.Option{107 Label: cat.Name,108 Value: cat.ID,109 }110 }111 return options112 }),113```114115## Anti-Patterns116117❌ **Don't expose sensitive fields** - Use ReadOnly() or hide completely118❌ **Don't skip validation** - Always validate required fields119❌ **Don't forget indexes** - Add Searchable() for indexed fields120❌ **Don't hardcode options** - Use dynamic options for database data121❌ **Don't ignore file size limits** - Set MaxSize() for uploads122❌ **Don't forget display keys** - Set DisplayKey() for relationships123❌ **Don't mix concerns** - Keep field logic in resolver, business logic in repository124125## Decisions126127### Field Naming128- **snake_case** for field names (matches database columns)129- **Descriptive names** that match domain model130- **Consistent naming** across resources131132### Validation133- **Required** for non-nullable fields134- **Unique** for unique constraints135- **Min/Max** for number ranges136- **Custom validators** for complex rules137138### Display139- **OnList** for table columns140- **OnDetail** for detail view141- **OnForm** for create/edit forms142- **OnlyOnDetail** for read-only info143- **OnlyOnForm** for input-only fields144145## Sharp Edges146147⚠️ **File Uploads**: Configure storage disk and path correctly148⚠️ **Relationships**: Use DisplayKey to show meaningful data149⚠️ **Options**: Cache dynamic options for performance150⚠️ **Validation**: Validate on both client and server151⚠️ **Searchable**: Only mark indexed fields as searchable152⚠️ **ReadOnly**: Use for computed or system fields153⚠️ **Nullable**: Match database schema nullability154155## Usage156157When user asks to add fields to a resource:1581591. **Identify field types** based on data type1602. **Add validation** rules (Required, Unique, Min, Max)1613. **Configure display** options (OnList, OnDetail, OnForm)1624. **Add relationships** if needed1635. **Set defaults** for optional fields1646. **Configure file uploads** if needed1657. **Add searchable** for indexed fields166167---168> Converted and distributed by [TomeVault](https://tomevault.io/claim/ferdiunal) — claim your Tome and manage your conversions.169<!-- tomevault:4.0:skill_md:2026-04-13 -->