AgentSkillsCN

announcable-backend-dev

在 Announcable 中进行后端开发。适用于创建、修改或调试后端代码(Go、Chi 路由器、GORM、模板、CSS/JS)时使用。

SKILL.md
--- frontmatter
name: announcable-backend-dev
description: Backend development in Announcable. Use when creating, modifying, or debugging backend code (Go, Chi router, GORM, templates, CSS/JS).

Backend Development — Announcable

Working Directory

All commands run from backend/:

bash
cd backend

Before You Start

Read the relevant documentation for what you're changing:

bash
# Domain module
cat internal/domain/[module]/SUMMARY.md

# Handler architecture
cat internal/handler/SUMMARY.md

# Domain conventions
cat internal/domain/SUMMARY.md

# CSS architecture
cat assets/css/SUMMARY.md

# JS architecture
cat assets/js/SUMMARY.md

Validation Sequence

Run after every change. Do NOT trust your own assessment — verify through observable behavior.

bash
# Go code changes
go build -o ./tmp/main .          # Must compile
go vet ./...                      # No issues

# CSS/JS changes
npm run build                     # Vite must succeed

# Full check (if dev environment is running)
# Backend should respond at configured PORT

Project Structure

code
backend/
├── main.go                    # Entry point, routes, server setup
├── config/                    # Environment configuration
├── internal/
│   ├── domain/                # Business logic (model, repository, service per module)
│   ├── handler/
│   │   ├── pages/             # HTML-serving handlers
│   │   ├── api/               # JSON API handlers
│   │   └── shared/            # Shared dependencies struct
│   ├── database/              # GORM setup, migrations, base model
│   ├── middleware/             # Auth, RBAC, rate limiting
│   ├── objstore/              # Minio wrapper
│   ├── email/                 # Email sending
│   └── logger/                # Structured logging
├── templates/                 # Go html/template (layouts, pages, partials)
├── assets/                    # Source CSS/JS (Vite input)
│   ├── css/                   # CSS source files
│   └── js/                    # JS source files
└── static/                    # Embedded assets (dist/ is Vite output)

Domain Module Pattern

Every domain module follows the same trio structure:

code
internal/domain/{module}/
├── SUMMARY.md       # ← Read this first
├── model.go         # GORM model (embeds database.BaseModel)
├── repository.go    # Database access via GORM
├── service.go       # Business logic, orchestration
└── common.go        # Helper builders, shared types (optional)

Key conventions:

  • Services are created with NewService(repo)
  • Repositories require NewRepository(db *database.DB)
  • database.BaseModel provides UUID ID and timestamps
  • Use logger.Get() for structured logging
  • Transactions via repo.db.StartTransaction() for multi-aggregate operations

Package naming: Singular, lowercase (user, session, organisation — NOT users, sessions)

Handler Pattern

Handlers are organized by feature under pages/ (HTML) and api/ (JSON):

code
internal/handler/pages/{feature}/
├── page.go                         # Handlers struct, New(), GET handler, template
└── {domain}_{action}_action.go     # One POST/PATCH/DELETE per file

Key conventions:

  • All handlers are methods on *Handlers struct receiving *shared.Dependencies
  • One action per file, named {domain}_{action}_action.go
  • Templates constructed with templates.Construct() helper
  • Use shared.BaseTemplateData for template data

Adding a new page:

  1. Create handler package under pages/
  2. Define Handlers struct with New(deps) constructor
  3. Add template in templates/pages/
  4. Add CSS entry in assets/css/pages/
  5. Register routes in main.go

Template System

Templates use Go's html/template with composition:

code
root.html → layout (appframe/onboard/fullscreen) → page → partials

Blocks defined by root.html: layout-css, page-css, body, layout-js, page-js

go
var myTmpl = templates.Construct(
    "my-page",
    "layouts/root.html",
    "layouts/appframe.html",
    "pages/my-page.html",
)

// In handler:
myTmpl.ExecuteTemplate(w, "root", data)

CSS/JS Changes

Source files are in assets/, built by Vite to static/dist/:

bash
# Development (watch mode)
npm run dev

# Production build
npm run build

CSS: Entry files in assets/css/layouts/ and assets/css/pages/ import from assets/css/components/ and assets/css/base/. All @import must come first.

JS: Vanilla JavaScript (no modules). Alpine.js components, HTMX handlers, global functions. External deps available via window.* from vendor bundle.

Never edit files in static/dist/ — they are auto-generated.

Adding a New Feature (Checklist)

  1. Read relevant SUMMARY.md files
  2. Create/modify domain module (model.go, repository.go, service.go)
  3. Create migration if schema changes needed (see announcable-migrations skill)
  4. Create/modify handler (page.go + action files)
  5. Create/modify templates
  6. Add CSS/JS if needed
  7. Register routes in main.go
  8. go build -o ./tmp/main . compiles
  9. go vet ./... passes
  10. npm run build succeeds (if CSS/JS changed)
  11. Test manually in browser

External Dependencies

LibraryPurposeGlobal
Alpine.jsReactive UI frameworkwindow.Alpine
HTMXAJAX and partial page updateswindow.htmx
SweetAlertModal dialogswindow.swal
ToastifyToast notificationswindow.Toastify
Feather IconsIcon librarywindow.feather

All bundled in /static/dist/vendor.js and /static/dist/vendor.css.

Anti-Patterns

Don'tWhyInstead
Edit static/dist/ filesAuto-generated by ViteEdit source in assets/
Call config.New() in hot pathsCreates new config each timeCache at package level
Import across domain modules directlyCircular dependenciesUse IDs and defined structs
Use plural package names for domainsConvention conflict with handlersSingular: user, session
Put @import after CSS rulesCSS spec violationAll @import at top of file
Skip reading SUMMARY.mdMiss module conventionsAlways read before modifying
Batch multiple logical changesHard to identify breakageOne change → validate