docs(AGENTS): add Nebula project guidelines document
This commit is contained in:
227
AGENTS.md
Normal file
227
AGENTS.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# AGENTS.md - Nebula Project Guidelines
|
||||
|
||||
## Project Overview
|
||||
|
||||
Nebula is a Go/Templ wallet application with HTMX 4 for server-driven UI and WebAwesome (wa-*) web components.
|
||||
|
||||
**Stack**: Go 1.25+ | templ v0.3.977 | htmx 4.0.0-alpha5 | WebAwesome | SQLite WASM
|
||||
|
||||
## Build & Run Commands
|
||||
|
||||
```bash
|
||||
# Generate Go code from .templ files (REQUIRED after any .templ changes)
|
||||
templ generate
|
||||
|
||||
# Build the project
|
||||
go build ./...
|
||||
|
||||
# Run development server (serves on :8080)
|
||||
go run main.go
|
||||
|
||||
# Watch mode for templ files
|
||||
templ generate --watch
|
||||
|
||||
# Full build + run + open browser
|
||||
make all
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
nebula/
|
||||
├── models/ # Data types (MVC models)
|
||||
├── views/ # Page templates (.templ)
|
||||
├── layouts/ # Base layouts (DashboardLayout, CenteredLayout)
|
||||
├── components/ # Reusable UI components
|
||||
├── handlers/ # HTTP route handlers
|
||||
├── _migrate/ # HTML prototypes to convert
|
||||
├── HTMX.md # htmx 4 patterns documentation
|
||||
└── SQLC.md # Database schema documentation
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### Go Files
|
||||
|
||||
- Standard `gofmt` formatting
|
||||
- Package-level types in `models/` directory
|
||||
- Handlers in `handlers/routes.go` with pattern: `handleX(w http.ResponseWriter, r *http.Request)`
|
||||
- Use `r.Header.Get("HX-Request") == "true"` to detect HTMX requests
|
||||
- Return partials for HTMX, full pages for direct navigation
|
||||
|
||||
### Templ Files (.templ)
|
||||
|
||||
- One main page template per file: `PageName(data ModelType) templ.Component`
|
||||
- Helper functions lowercase: `helperName()`
|
||||
- CSS-in-templ using `templ css` blocks or `<style>` tags
|
||||
- Component parameters use Go types from `models/` package
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
| Type | Convention | Example |
|
||||
|------|------------|---------|
|
||||
| Page template | `XxxPage` | `SettingsPage`, `DashboardPage` |
|
||||
| Partial template | `XxxContent`, `XxxTab` | `DashboardContent`, `ProfileTab` |
|
||||
| OOB update | `XxxWithOOB`, `XxxWithStepper` | `LoginStepWithOOB` |
|
||||
| Model struct | PascalCase | `SettingsData`, `ProfileSettings` |
|
||||
| Handler func | `handleXxx` | `handleSettings`, `handleDashboard` |
|
||||
|
||||
## HTMX 4 Patterns
|
||||
|
||||
### Partial Updates
|
||||
|
||||
```html
|
||||
<div hx-get="/endpoint" hx-target="#target" hx-swap="innerHTML">
|
||||
```
|
||||
|
||||
### Out-of-Band Updates
|
||||
|
||||
```go
|
||||
templ ComponentWithOOB() {
|
||||
@MainContent()
|
||||
<div id="sidebar" hx-swap-oob="true">
|
||||
@UpdatedSidebar()
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
### HTMX Request Detection
|
||||
|
||||
```go
|
||||
if r.Header.Get("HX-Request") == "true" {
|
||||
views.PartialContent(data).Render(r.Context(), w)
|
||||
return
|
||||
}
|
||||
views.FullPage(data).Render(r.Context(), w)
|
||||
```
|
||||
|
||||
## WebAwesome Components
|
||||
|
||||
Use `wa-*` web components for UI:
|
||||
|
||||
```html
|
||||
<wa-button variant="brand">Click me</wa-button>
|
||||
<wa-card>Content</wa-card>
|
||||
<wa-tab-group>
|
||||
<wa-tab panel="one">Tab 1</wa-tab>
|
||||
<wa-tab-panel name="one">Panel 1</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
<wa-icon name="user"></wa-icon>
|
||||
<wa-avatar initials="JD"></wa-avatar>
|
||||
```
|
||||
|
||||
## Route Registration
|
||||
|
||||
All routes in `handlers/routes.go`:
|
||||
|
||||
```go
|
||||
func RegisterRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /path", handlePath)
|
||||
mux.HandleFunc("POST /path/action", handleAction)
|
||||
}
|
||||
```
|
||||
|
||||
Go 1.22+ routing patterns:
|
||||
- `GET /path` - method prefix
|
||||
- `GET /path/{param}` - path parameters via `r.PathValue("param")`
|
||||
- `GET /path/{param...}` - catch-all
|
||||
|
||||
## Model Pattern
|
||||
|
||||
Models in `models/` package with `DefaultXxxData()` factory functions:
|
||||
|
||||
```go
|
||||
// models/example.go
|
||||
package models
|
||||
|
||||
type ExampleData struct {
|
||||
Field1 string
|
||||
Field2 int
|
||||
Items []Item
|
||||
}
|
||||
|
||||
func DefaultExampleData() ExampleData {
|
||||
return ExampleData{
|
||||
Field1: "default",
|
||||
Items: []Item{...},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Pattern (HTML to Templ)
|
||||
|
||||
When converting `_migrate/*.html` files:
|
||||
|
||||
1. Create model types in `models/xxx.go`
|
||||
2. Create view in `views/xxx.templ`
|
||||
3. Add route in `handlers/routes.go`
|
||||
4. Update sidebar active state in `components/sidebar.templ`
|
||||
|
||||
### Templ Syntax Reference
|
||||
|
||||
```go
|
||||
// Conditionals
|
||||
if condition {
|
||||
<div>shown</div>
|
||||
}
|
||||
|
||||
// Loops
|
||||
for _, item := range items {
|
||||
<div>{ item.Name }</div>
|
||||
}
|
||||
|
||||
// Boolean attributes
|
||||
<input disabled?={ isDisabled } />
|
||||
<wa-tab active?={ tab == "profile" }>
|
||||
|
||||
// String interpolation
|
||||
<div class={ "base " + extraClass }>
|
||||
<div data-id={ item.ID }>
|
||||
|
||||
// Raw HTML (use sparingly)
|
||||
@templ.Raw(htmlString)
|
||||
|
||||
// Component composition
|
||||
@ChildComponent(props)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
go test ./...
|
||||
|
||||
# Run with verbose
|
||||
go test -v ./...
|
||||
|
||||
# Run specific package
|
||||
go test ./handlers/...
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Add New Page
|
||||
|
||||
1. Create `models/newpage.go` with data types
|
||||
2. Create `views/newpage.templ` with page template
|
||||
3. Add handler in `handlers/routes.go`
|
||||
4. Add nav item in `components/sidebar.templ` if needed
|
||||
|
||||
### Add New Component
|
||||
|
||||
1. Create in `components/newcomp.templ`
|
||||
2. Import in views: `import "nebula/components"`
|
||||
3. Use: `@components.NewComp(props)`
|
||||
|
||||
### Modify Layout
|
||||
|
||||
Layouts in `layouts/`:
|
||||
- `base.templ` - HTML document wrapper with htmx CDN
|
||||
- `app.templ` - Dashboard app shell with sidebar
|
||||
- `centered.templ` - Centered auth pages
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **templ**: Template engine - `go install github.com/a-h/templ/cmd/templ@latest`
|
||||
- **htmx 4**: Loaded from CDN in `layouts/base.templ`
|
||||
- **WebAwesome**: Loaded from CDN in `layouts/base.templ`
|
||||
Reference in New Issue
Block a user