package pact import ( "context" "io/fs" "net/http" "git.golem15.com/golem15/summercms/bonfire" "github.com/go-gormigrate/gormigrate/v2" "gorm.io/gorm" ) // HasCommands is implemented by plugins that register console commands. type HasCommands interface { Commands() []bonfire.Command } // HasConfig is implemented by plugins that ship default YAML configuration. // ConfigFS should contain files such as config/config.yaml, merged later at // the plugin ID path. type HasConfig interface { ConfigFS() fs.FS } // HasMigrations is implemented by plugins that ship an ordered gormigrate // set. The kernel runs each set in party.Activate order with a separate // history table per plugin ID. type HasMigrations interface { Migrations() []*gormigrate.Migration } // Middleware is a named HTTP wrapper registered by a plugin. type Middleware func(http.Handler) http.Handler // HasMiddleware is implemented by plugins that register named middleware. type HasMiddleware interface { Middlewares() map[string]Middleware } // HasMiddlewareFactories is implemented by plugins that register // parameterized middleware ("name:param"), resolved at wrap time. type HasMiddlewareFactories interface { MiddlewareFactories() map[string]func(param string) Middleware } // HasHouseMiddleware is implemented by plugins that register middleware // tagged as house-envelope/error handling -- refused inside a raw group // (D-16). This is the ONLY way a plugin declares a house-tagged name: // plugins never call a Router.Register* method directly (there is no such // call site anywhere in this codebase -- RegisterMiddleware/ // RegisterMiddlewareFactory/RegisterHouseMiddleware are all called // exclusively from surf.Assemble/BuildRouter's plugin loop, the same way // HasMiddleware's Middlewares() map is today). A name present in both // Middlewares() and HouseMiddlewares() (from the same or a different // plugin) fails boot with the existing duplicate-name error, since both are // registered into the same underlying name table. type HasHouseMiddleware interface { HouseMiddlewares() map[string]Middleware } // Router is the Laravel-like group builder implemented by surf. type Router interface { Group(prefix string, middleware []string, fn func(Router)) GroupRaw(prefix string, middleware []string, fn func(Router)) Get(path string, handler http.HandlerFunc, middleware ...string) Post(path string, handler http.HandlerFunc, middleware ...string) Put(path string, handler http.HandlerFunc, middleware ...string) Patch(path string, handler http.HandlerFunc, middleware ...string) Delete(path string, handler http.HandlerFunc, middleware ...string) Where(param, pattern string) WhereIn(param string, values ...string) } // HasRoutes is implemented by plugins that declare HTTP routes. type HasRoutes interface { Routes(Router) error } // HasModels is implemented by plugins that expose GORM models. type HasModels interface { Models() []any } // JobArgs is the typed payload a job worker receives. Kind identifies the // job so a worker can reject unexpected argument types. type JobArgs interface { Kind() string } // Job is a unit of background work. Phase 11 adapts this onto River; the // interface itself must not import River. type Job interface { Work(ctx context.Context, args JobArgs) error } // HasJobs is implemented by plugins that register background jobs. type HasJobs interface { Jobs() []Job } // AdminController is the compile-time admin controller contract. Phase 9 // grows the schema pipeline; ID, model name and YAML config directory are // enough for generated stubs to compile. type AdminController interface { ID() string ModelName() string ConfigDir() string } // HasAdminControllers is implemented by plugins that register admin controllers. type HasAdminControllers interface { AdminControllers() []AdminController } // AdminAssets is the plugin-owned embedded tree of Winter admin YAML. // Paths are relative to the plugin root (controllers/..., models/...). type AdminAssets interface { AdminFS() fs.FS } // AdminPermissioned is the D-03 permission list enforced before schema or SQL. type AdminPermissioned interface { RequiredPermissions() []string } // AdminRecordSource supplies the GORM model the generic admin handlers query. // NewRecord returns a pointer to the model struct. type AdminRecordSource interface { NewRecord() any } // Permission is one registerPermissions() entry. type Permission struct { Code string Tab string Label string Roles []string } // HasPermissions is implemented by plugins that declare backend permissions. type HasPermissions interface { Permissions() []Permission } // NavigationItem is one registerNavigation() entry. Controller is the admin // controller ID; the SPA derives its route from that ID. type NavigationItem struct { Code string Label string Icon string Permissions []string Order int Controller string SideMenu []NavigationItem } // HasNavigation is implemented by plugins that declare backend navigation. type HasNavigation interface { Navigation() []NavigationItem } // SettingsItem is one registerSettings() entry. type SettingsItem struct { Code string Label string Description string Category string Icon string Model string Order int Keywords []string Permissions []string Form string `json:"-"` NewModel func() any `json:"-"` } // HasSettings is implemented by plugins that declare settings screens. type HasSettings interface { Settings() []SettingsItem } // Option is one dropdown choice. Label may be a phrase key until request time. type Option struct { Value string `json:"value"` Label string `json:"label"` } // DropdownOptionsProvider serves method-backed dropdown options. type DropdownOptionsProvider interface { DropdownOptions(field string) []Option } // ListExtendQuery optionally narrows the admin list query. type ListExtendQuery interface { ListExtendQuery(ctx context.Context, db *gorm.DB) *gorm.DB } // ListRelationColumnMapper maps a source-schema relation column onto the // physical column exposed by the related Go model. It supports legacy admin // schemas whose public field names no longer match the database schema. type ListRelationColumnMapper interface { ListRelationColumn(relation, column string) (string, bool) } // FormExtendQuery optionally narrows admin form record lookup. type FormExtendQuery interface { FormExtendQuery(ctx context.Context, db *gorm.DB) *gorm.DB } // FormBeforeCreate optionally rejects or stamps a record before insert. type FormBeforeCreate interface { FormBeforeCreate(ctx context.Context, model any) error } // FormBeforeUpdate optionally rejects or stamps a record before update. type FormBeforeUpdate interface { FormBeforeUpdate(ctx context.Context, model any) error } // FormAfterCreate optionally runs after insert, inside the same transaction. type FormAfterCreate interface { FormAfterCreate(ctx context.Context, model any) error } // FormAfterUpdate optionally runs after update, inside the same transaction. type FormAfterUpdate interface { FormAfterUpdate(ctx context.Context, model any) error } // FormBeforeDelete optionally rejects a record before delete. type FormBeforeDelete interface { FormBeforeDelete(ctx context.Context, model any) error } // FormAfterDelete optionally runs after delete, inside the same transaction. type FormAfterDelete interface { FormAfterDelete(ctx context.Context, model any) error } // RelationExtendManageQuery optionally narrows relation-manager candidates. type RelationExtendManageQuery interface { RelationExtendManageQuery(ctx context.Context, relation string, db *gorm.DB) *gorm.DB } // RelationBeforeLink optionally stamps pivot columns before a link insert. type RelationBeforeLink interface { RelationBeforeLink(ctx context.Context, relation string, parent, related any, pivot map[string]any) error } // FilterScope is the model capability a config_filter scope name may call. // FilterScopes is the exact, case-sensitive set of names; request text never // selects a method outside that set. type FilterScope interface { FilterScopes() []string FilterScope(name string, db *gorm.DB, value any) *gorm.DB } // HasLang is implemented by plugins that ship embedded translation YAML // under lang//.yaml. type HasLang interface { LangFS() fs.FS } // HasMailTemplates is implemented by plugins that ship Winter-shaped mail // templates and layout aliases. MailTemplatesFS contains views/mail assets; // MailTemplates lists dotted template names; MailLayouts maps a short layout // name to the full dotted layout name. type HasMailTemplates interface { MailTemplatesFS() fs.FS MailTemplates() []string MailLayouts() map[string]string } // OptionalMessage is a service an optional plugin may publish so other // plugins can integrate without importing that plugin's package. type OptionalMessage interface { Message() string } // Future capability families are type-asserted when their first consumer // packages exist: // // HasListeners // HasSchedule // // The kernel type-asserts HasConfig (party, before Register), HasCommands // (generated app main, after Boot), HasMigrations (lagoon migrate), and // HasMiddleware/HasMiddlewareFactories/HasHouseMiddleware/HasRoutes // (surf assemble). surf.BucketProvider is type-asserted in Assemble/ // BuildRouter (not a pact interface: pact cannot import surf without a cycle).