chore: updated skills
54f3285f
1 file(s) · +41 −41
| 1 | 1 | --- |
|
| 2 | 2 | name: Andromeda Stack |
|
| 3 | - | description: Scaffold a Go CRUD web app using net/http + html/template + modernc.org/sqlite + the shared andromeda crates-go packages (auth, web, config, sqlite, darkmatter). Use when the user wants to build a new Go web server with CRUD operations in the andromeda monorepo. |
|
| 3 | + | description: Scaffold a Go CRUD web app using net/http + html/template + modernc.org/sqlite + the shared andromeda pkg packages (auth, web, config, sqlite, darkmatter). Use when the user wants to build a new Go web server with CRUD operations in the andromeda monorepo. |
|
| 4 | 4 | --- |
|
| 5 | 5 | ||
| 6 | 6 | # Go Andromeda Web App |
|
| 9 | 9 | ||
| 10 | 10 | Scaffold and build Go CRUD web apps in the andromeda workspace using the |
|
| 11 | 11 | standard library `net/http` mux, `html/template`, `modernc.org/sqlite` (pure |
|
| 12 | - | Go, no cgo) and the shared `crates-go/*` packages. Each app ships a single Go |
|
| 12 | + | Go, no cgo) and the shared `pkg/*` packages. Each app ships a single Go |
|
| 13 | 13 | binary with HTML pages, a JSON API, optional session or API key auth, embedded |
|
| 14 | 14 | templates + static assets via `embed.FS`, and Docker deployment. |
|
| 15 | 15 | ||
| 16 | 16 | Apps live under `apps/<name>/`. Each app is its own Go module. Shared packages |
|
| 17 | - | live under `crates-go/` and are each their own module, wired in via local |
|
| 17 | + | live under `pkg/` and are each their own module, wired in via local |
|
| 18 | 18 | `replace` directives. |
|
| 19 | 19 | ||
| 20 | 20 | Shared crates: |
|
| 21 | 21 | ||
| 22 | - | - `crates-go/auth` — session `Store`, `RequireSession` / `RequireAPIKey` / |
|
| 22 | + | - `pkg/auth` — session `Store`, `RequireSession` / `RequireAPIKey` / |
|
| 23 | 23 | `RequireBearerOrSession` middleware, `SecureEqual`, `VerifyPassword` |
|
| 24 | 24 | (bcrypt or plaintext), `GenerateSessionToken`, `GenerateShortID`. |
|
| 25 | - | - `crates-go/web` — `Render`, `WriteJSON`, `WriteError`, `DecodeJSON`, |
|
| 25 | + | - `pkg/web` — `Render`, `WriteJSON`, `WriteError`, `DecodeJSON`, |
|
| 26 | 26 | `EmbeddedHandler`, `RedirectWithError`, `RedirectWithSuccess`, `PathInt64`. |
|
| 27 | - | - `crates-go/config` — `LoadDotEnv`, `Getenv`, `GetenvInt`, `GetenvBool`. |
|
| 28 | - | - `crates-go/sqlite` — `Open(path, schema)` opens SQLite with the project |
|
| 27 | + | - `pkg/config` — `LoadDotEnv`, `Getenv`, `GetenvInt`, `GetenvBool`. |
|
| 28 | + | - `pkg/sqlite` — `Open(path, schema)` opens SQLite with the project |
|
| 29 | 29 | defaults (`PRAGMA foreign_keys=ON`, `SetMaxOpenConns(1)`). |
|
| 30 | - | - `crates-go/darkmatter` — embedded shared CSS + fonts plus `Mount(mux, |
|
| 30 | + | - `pkg/darkmatter` — embedded shared CSS + fonts plus `Mount(mux, |
|
| 31 | 31 | "/assets")` to register routes on any `*http.ServeMux`. |
|
| 32 | 32 | ||
| 33 | 33 | ## Project Structure |
|
| 67 | 67 | go 1.25 |
|
| 68 | 68 | ||
| 69 | 69 | require ( |
|
| 70 | - | github.com/stevedylandev/andromeda/crates-go/auth v0.0.0 |
|
| 71 | - | github.com/stevedylandev/andromeda/crates-go/config v0.0.0 |
|
| 72 | - | github.com/stevedylandev/andromeda/crates-go/darkmatter v0.0.0 |
|
| 73 | - | github.com/stevedylandev/andromeda/crates-go/sqlite v0.0.0 |
|
| 74 | - | github.com/stevedylandev/andromeda/crates-go/web v0.0.0 |
|
| 70 | + | github.com/stevedylandev/andromeda/pkg/auth v0.0.0 |
|
| 71 | + | github.com/stevedylandev/andromeda/pkg/config v0.0.0 |
|
| 72 | + | github.com/stevedylandev/andromeda/pkg/darkmatter v0.0.0 |
|
| 73 | + | github.com/stevedylandev/andromeda/pkg/sqlite v0.0.0 |
|
| 74 | + | github.com/stevedylandev/andromeda/pkg/web v0.0.0 |
|
| 75 | 75 | ) |
|
| 76 | 76 | ||
| 77 | 77 | replace ( |
|
| 78 | - | github.com/stevedylandev/andromeda/crates-go/auth => ../../crates-go/auth |
|
| 79 | - | github.com/stevedylandev/andromeda/crates-go/config => ../../crates-go/config |
|
| 80 | - | github.com/stevedylandev/andromeda/crates-go/darkmatter => ../../crates-go/darkmatter |
|
| 81 | - | github.com/stevedylandev/andromeda/crates-go/sqlite => ../../crates-go/sqlite |
|
| 82 | - | github.com/stevedylandev/andromeda/crates-go/web => ../../crates-go/web |
|
| 78 | + | github.com/stevedylandev/andromeda/pkg/auth => ../../pkg/auth |
|
| 79 | + | github.com/stevedylandev/andromeda/pkg/config => ../../pkg/config |
|
| 80 | + | github.com/stevedylandev/andromeda/pkg/darkmatter => ../../pkg/darkmatter |
|
| 81 | + | github.com/stevedylandev/andromeda/pkg/sqlite => ../../pkg/sqlite |
|
| 82 | + | github.com/stevedylandev/andromeda/pkg/web => ../../pkg/web |
|
| 83 | 83 | ) |
|
| 84 | 84 | ``` |
|
| 85 | 85 | ||
| 86 | - | Add `crates-go/tui` only if the app ships a TUI. Add `golang.org/x/crypto`, |
|
| 86 | + | Add `pkg/tui` only if the app ships a TUI. Add `golang.org/x/crypto`, |
|
| 87 | 87 | `yuin/goldmark`, etc. only when the specific app needs them. The Dockerfile |
|
| 88 | - | must copy `crates-go/` into the build context for the replace directives. |
|
| 88 | + | must copy `pkg/` into the build context for the replace directives. |
|
| 89 | 89 | ||
| 90 | 90 | Do NOT add ORMs, web frameworks (gin, echo, chi), connection pools, or HTTP |
|
| 91 | 91 | client libs unless explicitly requested. The stdlib `net/http` mux (with |
|
| 105 | 105 | "net/http" |
|
| 106 | 106 | "os" |
|
| 107 | 107 | ||
| 108 | - | "github.com/stevedylandev/andromeda/crates-go/auth" |
|
| 109 | - | "github.com/stevedylandev/andromeda/crates-go/config" |
|
| 108 | + | "github.com/stevedylandev/andromeda/pkg/auth" |
|
| 109 | + | "github.com/stevedylandev/andromeda/pkg/config" |
|
| 110 | 110 | ) |
|
| 111 | 111 | ||
| 112 | 112 | func main() { |
|
| 176 | 176 | "html/template" |
|
| 177 | 177 | "log/slog" |
|
| 178 | 178 | ||
| 179 | - | "github.com/stevedylandev/andromeda/crates-go/auth" |
|
| 179 | + | "github.com/stevedylandev/andromeda/pkg/auth" |
|
| 180 | 180 | ) |
|
| 181 | 181 | ||
| 182 | 182 | //go:embed templates/*.html static/* |
|
| 215 | 215 | import ( |
|
| 216 | 216 | "net/http" |
|
| 217 | 217 | ||
| 218 | - | "github.com/stevedylandev/andromeda/crates-go/auth" |
|
| 219 | - | "github.com/stevedylandev/andromeda/crates-go/darkmatter" |
|
| 220 | - | "github.com/stevedylandev/andromeda/crates-go/web" |
|
| 218 | + | "github.com/stevedylandev/andromeda/pkg/auth" |
|
| 219 | + | "github.com/stevedylandev/andromeda/pkg/darkmatter" |
|
| 220 | + | "github.com/stevedylandev/andromeda/pkg/web" |
|
| 221 | 221 | ) |
|
| 222 | 222 | ||
| 223 | 223 | func (a *App) routes() *http.ServeMux { |
|
| 263 | 263 | ||
| 264 | 264 | ## db.go (or internal/store) |
|
| 265 | 265 | ||
| 266 | - | Single-file module: schema, model, CRUD. `crates-go/sqlite.Open` handles the |
|
| 266 | + | Single-file module: schema, model, CRUD. `pkg/sqlite.Open` handles the |
|
| 267 | 267 | driver, pragmas, and schema bootstrap. |
|
| 268 | 268 | ||
| 269 | 269 | ```go |
|
| 273 | 273 | "database/sql" |
|
| 274 | 274 | "errors" |
|
| 275 | 275 | ||
| 276 | - | "github.com/stevedylandev/andromeda/crates-go/auth" |
|
| 277 | - | "github.com/stevedylandev/andromeda/crates-go/sqlite" |
|
| 276 | + | "github.com/stevedylandev/andromeda/pkg/auth" |
|
| 277 | + | "github.com/stevedylandev/andromeda/pkg/sqlite" |
|
| 278 | 278 | ) |
|
| 279 | 279 | ||
| 280 | 280 | type Item struct { |
|
| 396 | 396 | "net/http" |
|
| 397 | 397 | "strings" |
|
| 398 | 398 | ||
| 399 | - | "github.com/stevedylandev/andromeda/crates-go/auth" |
|
| 400 | - | "github.com/stevedylandev/andromeda/crates-go/web" |
|
| 399 | + | "github.com/stevedylandev/andromeda/pkg/auth" |
|
| 400 | + | "github.com/stevedylandev/andromeda/pkg/web" |
|
| 401 | 401 | ) |
|
| 402 | 402 | ||
| 403 | 403 | func (a *App) loginGetHandler(w http.ResponseWriter, r *http.Request) { |
|
| 467 | 467 | import ( |
|
| 468 | 468 | "net/http" |
|
| 469 | 469 | ||
| 470 | - | "github.com/stevedylandev/andromeda/crates-go/web" |
|
| 470 | + | "github.com/stevedylandev/andromeda/pkg/web" |
|
| 471 | 471 | ) |
|
| 472 | 472 | ||
| 473 | 473 | func (a *App) apiListItems(w http.ResponseWriter, r *http.Request) { |
|
| 514 | 514 | ||
| 515 | 515 | ## Authentication |
|
| 516 | 516 | ||
| 517 | - | `crates-go/auth` provides three middleware patterns. Pick based on app shape: |
|
| 517 | + | `pkg/auth` provides three middleware patterns. Pick based on app shape: |
|
| 518 | 518 | ||
| 519 | 519 | ### Session/cookie auth (web-facing apps) |
|
| 520 | 520 | ||
| 631 | 631 | ||
| 632 | 632 | ## Dockerfile |
|
| 633 | 633 | ||
| 634 | - | Multi-stage, built from the repo root so `crates-go/` is available for the |
|
| 634 | + | Multi-stage, built from the repo root so `pkg/` is available for the |
|
| 635 | 635 | `replace` directives. Pure Go (`CGO_ENABLED=0`) because the SQLite driver is |
|
| 636 | 636 | `modernc.org/sqlite`. |
|
| 637 | 637 | ||
| 639 | 639 | # Build from repo root: docker build -t APP_NAME -f apps/APP_NAME/Dockerfile . |
|
| 640 | 640 | FROM golang:1.25-bookworm AS builder |
|
| 641 | 641 | WORKDIR /app |
|
| 642 | - | COPY crates-go/ ./crates-go/ |
|
| 642 | + | COPY pkg/ ./pkg/ |
|
| 643 | 643 | COPY apps/APP_NAME/go.mod apps/APP_NAME/go.sum ./apps/APP_NAME/ |
|
| 644 | 644 | WORKDIR /app/apps/APP_NAME |
|
| 645 | 645 | RUN go mod download |
|
| 763 | 763 | make go-app-fmt APP=APP_NAME |
|
| 764 | 764 | ``` |
|
| 765 | 765 | ||
| 766 | - | The shared crates (`crates-go/web`, `crates-go/auth`, `crates-go/config`, |
|
| 767 | - | `crates-go/sqlite`, `crates-go/darkmatter`) are each their own module — run |
|
| 766 | + | The shared crates (`pkg/web`, `pkg/auth`, `pkg/config`, |
|
| 767 | + | `pkg/sqlite`, `pkg/darkmatter`) are each their own module — run |
|
| 768 | 768 | `go build ./...` inside any to check in isolation. |
|
| 769 | 769 | ||
| 770 | 770 | ## Checklist |
|
| 776 | 776 | 3. `main.go` — env load, DB open, sessions bootstrap, `App` build, `ListenAndServe`. |
|
| 777 | 777 | 4. `app.go` — `App` struct, `//go:embed`, page-data structs. |
|
| 778 | 778 | 5. `routes.go` — mux wiring, middleware, `/static/` + `darkmatter.Mount`. |
|
| 779 | - | 6. `db.go` — schema, model, CRUD via `crates-go/sqlite.Open`. |
|
| 779 | + | 6. `db.go` — schema, model, CRUD via `pkg/sqlite.Open`. |
|
| 780 | 780 | 7. `handlers_web.go` — login/logout + HTML CRUD pages. |
|
| 781 | 781 | 8. `handlers_api.go` — JSON CRUD endpoints behind `RequireAPIKey`. |
|
| 782 | 782 | 9. `templates/base.html` + per-page templates using `{{ define }}` blocks. |
|
| 794 | 794 | - No web frameworks (gin, echo, chi, fiber) — stdlib `net/http` mux is enough. |
|
| 795 | 795 | - No ORMs — raw `database/sql` + `?` placeholders. |
|
| 796 | 796 | - No connection pools — `sqlite.Open` sets `MaxOpenConns(1)` on purpose. |
|
| 797 | - | - No cgo SQLite drivers — use `modernc.org/sqlite` via `crates-go/sqlite`. |
|
| 798 | - | - No external CSS frameworks unless specified — use `crates-go/darkmatter`. |
|
| 797 | + | - No cgo SQLite drivers — use `modernc.org/sqlite` via `pkg/sqlite`. |
|
| 798 | + | - No external CSS frameworks unless specified — use `pkg/darkmatter`. |
|
| 799 | 799 | - No JS frontend / build step — `html/template` rendered server-side. |
|
| 800 | 800 | - No CLI / TUI deps (cobra, bubbletea) unless the app actually needs them. |
|
| 801 | - | - No `replace` directives for anything outside `crates-go/`. |
|
| 801 | + | - No `replace` directives for anything outside `pkg/`. |
|