GoBlog is a single-user, multi-blog platform written in Go. Single binary, SQLite database, minimal dependencies. Supports IndieWeb protocols (IndieAuth, Micropub, Webmention, Microformats2) and ActivityPub for Fediverse integration.
- Module:
go.goblog.app/app - Go version: 1.26+
- Primary target OS: Linux
- Router:
chi(github.com/go-chi/chi/v5) - Database: SQLite with FTS5 (full-text search)
- UI: Server-side HTML rendering via
pkgs/htmlbuilder(no templates engine, no frontend framework) - Styles: SCSS compiled to CSS (no inline styles — enforced by CSP headers)
# With system SQLite (recommended, faster build)
go build -tags=linux,libsqlite3,sqlite_fts5 -o GoBlog
# With embedded SQLite (no system dependency, slower build)
go build -tags=linux,sqlite_fts5 -o GoBlog# All tests
go test -tags=linux,libsqlite3,sqlite_fts5 -timeout 600s ./...
# Single package/file
go test -tags=linux,libsqlite3,sqlite_fts5 -run TestName ./...The -tags=linux,libsqlite3,sqlite_fts5 flags are required for all build and test commands. Without them, compilation will fail.
golangci-lint runLinter config is in .golangci.yml. Key enabled linters: errcheck, gosimple, govet, staticcheck, gosec, bodyclose, sqlclosecheck.
# Apply modern Go features and automatic code rewrites
go fix ./...Automatically applies code modernizations, removes deprecated patterns, and updates code to use modern Go features. Run this regularly to keep code up-to-date with Go language evolution. Always review changes before committing.
# Rebuild CSS after editing SCSS
./original-assets/build/buildStyles.shRequires Node.js/npx. Source: original-assets/styles/styles.scss → Output: templates/assets/css/styles.css.
# Download pinned versions of Leaflet, MarkerCluster, hls.js
./bundle-assets.shUpdates files in leaflet/, hlsjs/, and version references in templates/assets/js/.
./GoBlog --config ./config/config.ymlAll Go source files live in the root directory (flat layout, no cmd/ or internal/):
├── app.go # Main app struct and initialization
├── main.go # Entry point
├── config.go # Configuration types and loading
├── database.go # SQLite database setup
├── databaseMigrations.go # Schema migrations (uses embedded SQL files)
├── http.go # HTTP server setup
├── httpRouters.go # All route definitions (chi router)
├── httpMiddlewares.go # HTTP middleware stack
├── ui.go # Page rendering functions
├── uiComponents.go # Reusable UI components
├── posts.go / postsDb.go # Post types and database operations
├── editor.go # Web editor
├── activityPub.go # ActivityPub protocol
├── micropub.go # Micropub protocol
├── indieAuth.go # IndieAuth protocol
├── webmention.go # Webmention send/receive
├── comments.go # Comment system
├── feeds.go # RSS/Atom/JSON feeds
├── search.go # Full-text search (FTS5)
├── cache.go # HTTP response caching
├── media.go # Media uploads and serving
├── plugins.go # Plugin system (Yaegi-based)
├── *_test.go # Tests (same directory)
│
├── dbmigrations/ # Embedded SQL migration files (00001.sql - 00038.sql)
├── pkgs/ # Internal reusable packages
│ ├── htmlbuilder/ # HTML generation (used for all UI)
│ ├── activitypub/ # ActivityPub utilities
│ ├── plugintypes/ # Plugin interface definitions
│ ├── plugins/ # Plugin loading (Yaegi)
│ ├── httpcompress/ # HTTP compression middleware
│ ├── bodylimit/ # Request body size limiting
│ ├── cache/ # Caching abstractions
│ ├── minify/ # HTML/CSS/JS minification
│ ├── maprouter/ # URL routing utilities
│ └── ... # Other utilities
│
├── strings/ # i18n translation files (YAML)
│ ├── default.yaml # English (default)
│ ├── de.yaml # German
│ ├── es.yaml # Spanish
│ └── pt-br.yaml # Portuguese (Brazil)
│
├── templates/assets/ # Frontend assets served to browser
│ ├── css/styles.css # Compiled CSS (do not edit directly)
│ └── js/*.js # JavaScript files
│
├── original-assets/ # Source assets
│ ├── styles/styles.scss # SCSS source (edit this)
│ └── build/buildStyles.sh # SCSS build script
│
├── plugins/ # Example/bundled plugins
├── leaflet/ # Leaflet map library (vendored)
├── hlsjs/ # HLS.js video library (vendored)
├── static/ # Static files served at /s/
├── logo/ # Logo assets
├── config/ # Runtime configuration (YAML)
├── data/ # Runtime data directory (DB, media, logs)
└── testdata/ # Test fixtures
Most features follow this pattern:
- Config: Feature toggle and options defined in
config.go - Routes: Endpoints registered in
httpRouters.go - Handler: HTTP handler in its own file (e.g.,
comments.go) - UI: Rendering in
ui.gooruiComponents.go - Database: Queries in a
*Db.gofile or inline
- Opt-in by default: Most features are disabled unless explicitly enabled in config
- Receiver pattern: Nearly all methods use
(a *goBlog)receiver on the main app struct - HTML builder: UI is built programmatically using
pkgs/htmlbuilder— there are no HTML template files - Database migrations: SQL files in
dbmigrations/are embedded and run automatically on startup. New migrations must be numbered sequentially (e.g.,00039.sql) - Plugins: Loaded at runtime via Yaegi (Go interpreter). Plugin interfaces defined in
pkgs/plugintypes/ - i18n: Translation strings in
strings/*.yaml, accessed via template string functions
- Add config fields to
config.go - Register routes in
httpRouters.go - Implement handler in a new or existing file
- Add UI rendering in
ui.go/uiComponents.go - If database changes needed, add a new migration file in
dbmigrations/
Add route definition to httpRouters.go. The router uses chi.
Edit ui.go (page-level rendering) or uiComponents.go (reusable components). All HTML is generated via pkgs/htmlbuilder — never use raw HTML strings or template files.
Edit original-assets/styles/styles.scss, then run ./original-assets/build/buildStyles.sh. Never edit templates/assets/css/styles.css directly. Inline styles in HTML are forbidden (CSP enforced).
Create a new numbered SQL file in dbmigrations/ (next number after 00038.sql). Migrations are embedded via //go:embed and run automatically on startup.
Add keys to strings/default.yaml (English), then add translations to other locale files (de.yaml, es.yaml, pt-br.yaml).
- New code should be covered by tests, preferably integration tests
- Run
go test -tags=linux,libsqlite3,sqlite_fts5 -timeout 600s ./...to verify
- New features must be documented in
README.md, or existing documentation must be updated to reflect changes - New configurable features must be added to
example-config.ymlwith descriptive comments - Translation strings in
strings/*.yamlmust be kept sorted alphabetically by key
- Standard Go formatting (
gofmt) - Use
go fix ./...to keep code modernized with latest Go features - No code comments unless the code is genuinely complex
- Use existing utility functions from
utils.goandpkgs/utils/ - Use
pkgs/htmlbuilderfor all HTML generation - Use
carlmjohnson/requestsfor outgoing HTTP requests (already a dependency) - Error handling: return errors up the call chain; use
a.serveError(w, r, ...)for HTTP error responses - Context: pass
context.Contextthrough where available