Add a Feature
A feature is a Go service and a UI package, each self-contained. Features never call each other’s services or import each other’s packages.
Add the service
Section titled “Add the service”- Create
internal/services/<feature>.go. The UI calls its exported methods. - Create
internal/services/<feature>_dto.gofor its DTOs and events. DTOs are UI-shaped: durations in milliseconds, artwork as/art/...cache paths. - Add one line to
internal/services/registry.go.
The full contract is in internal/services/doc.go.
Add the UI package
Section titled “Add the UI package”- Create
internal/ui/features/<name>. Its factory takes a*module.Envand returns amodule.Module: its routes, sidebar entries, shortcuts and event handlers. Keep state in one struct and make views methods on it. - Add one line to
internal/ui/app/modules.go. Its order decides the order of routes, handlers, shortcuts and slots.
func New(env *module.Env) module.Module { l := &library{env: env} return module.Module{ ID: "library", Routes: []module.Route{{Pattern: "/library/albums", Title: func(*ui.Route) string { return i18n.T("Albums") }, Build: l.albums}}, Nav: []module.NavItem{{Section: module.NavLibrary, Label: func() string { return i18n.T("Albums") }, Icon: "disc-3", To: "/library/albums", Order: 1}}, Init: l.init, }}Shortcut IDs (<module>.<action>) are stored in users’ settings, so never rename one. See UI Conventions and the full contract in docs/ui-architecture.md.
Add settings
Section titled “Add settings”Add one nested struct to internal/config/settings.go with its defaults and normalized(). Apply changes live through Settings.OnChange.
Finish
Section titled “Finish”- Design the page fresh; Apple’s apps are a functional reference, never a layout to copy.
- Write strings with
i18n.T(see Translations). - Add tests with
ui.Testerand runcheckandtests(Test Your Change). - Update the docs in the same pull request.