<feed xmlns='http://www.w3.org/2005/Atom'>
<title>nebbet.no/internal/db, branch main</title>
<subtitle>[no description]</subtitle>
<id>https://git.ivar.systems/nebbet.no/atom?h=main</id>
<link rel='self' href='https://git.ivar.systems/nebbet.no/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/'/>
<updated>2026-04-04T14:36:18Z</updated>
<entry>
<title>fix: make slug rename and content update atomic via RenameAndUpsertPost</title>
<updated>2026-04-04T14:36:18Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-04T14:36:18Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=0d8f53520a2143b22e2246ab1ec25e0860e90dad'/>
<id>urn:sha1:0d8f53520a2143b22e2246ab1ec25e0860e90dad</id>
<content type='text'>
Previously RenamePost + UpsertPost were two separate DB calls; a failure
between them left the post at the new slug with stale content. The new
RenameAndUpsertPost method does both in a single transaction.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: guard RenamePost against self-rename (noop)</title>
<updated>2026-04-04T14:12:29Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-04T14:12:29Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=8b137242305bb2a39f580d994392ece195aacf3b'/>
<id>urn:sha1:8b137242305bb2a39f580d994392ece195aacf3b</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat: add RenamePost with transactional rename and redirect creation</title>
<updated>2026-04-04T14:10:52Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-04T14:10:52Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=f045a49e6feb6f448faea073821a9661f8b710a3'/>
<id>urn:sha1:f045a49e6feb6f448faea073821a9661f8b710a3</id>
<content type='text'>
Implement RenamePost method that atomically:
1. Fetches the post record by old slug
2. Inserts a new record with the new slug
3. Deletes the old slug post
4. Collapses redirect chains (updates any redirects pointing to oldSlug to point to newSlug)
5. Creates a redirect from oldSlug to newSlug

All operations are transactional (all-or-nothing). Includes two comprehensive tests:
- TestRenamePost: basic rename with redirect creation and old slug deletion
- TestRenamePost_CollapsesChain: verifies redirect chains are collapsed correctly

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: add redirect DB methods (AddRedirect, GetRedirect, CollapseRedirects)</title>
<updated>2026-04-04T14:08:50Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-04T14:08:50Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=d239993644aae8c29d5fc37e8c6209850140807c'/>
<id>urn:sha1:d239993644aae8c29d5fc37e8c6209850140807c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat: add redirects table to meta.db schema</title>
<updated>2026-04-04T14:07:08Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-04T14:07:08Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=3b3ca0ce18ed13fca9a7f81229ba0b05957afab0'/>
<id>urn:sha1:3b3ca0ce18ed13fca9a7f81229ba0b05957afab0</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor: convert admin handlers to Gin context-based signatures</title>
<updated>2026-04-03T12:22:23Z</updated>
<author>
<name>ivar</name>
<email>i@oiee.no</email>
</author>
<published>2026-04-03T12:22:23Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=33310be68544d3381ac6e9899790f4a106e17e8f'/>
<id>urn:sha1:33310be68544d3381ac6e9899790f4a106e17e8f</id>
<content type='text'>
- Remove old ServeHTTP method (no longer needed with Gin routing)
- Update all 6 handler methods to use *gin.Context instead of http.ResponseWriter, *http.Request
- Convert handler signatures: handleList, handleNew, handleNewPost, handleEdit, handleDelete
- Remove render() helper (use c.HTML() directly)
- Update renderError() to accept gin.Context instead of http.ResponseWriter
- Update postFromForm() to extract form data from gin.Context using c.PostForm()
- Update main.go to use adminSrv.NewServer() and adminSrv.Engine()
- All handlers now use Gin methods: c.HTML(), c.PostForm(), c.Param(), c.Redirect()
- Path parameters now extracted via c.Param("slug") instead of function arguments
- HTTP status codes and error handling fully migrated to Gin patterns

Build verified: go build ./cmd/nebbet succeeds

Co-Authored-By: Claude Haiku 4.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add post management admin UI and switch to modernc.org/sqlite</title>
<updated>2026-03-31T10:44:10Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-03-31T10:44:10Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=aa23774abb90c168c9ba2559d6bf381bc9fc55ba'/>
<id>urn:sha1:aa23774abb90c168c9ba2559d6bf381bc9fc55ba</id>
<content type='text'>
- Replace custom CGO sqlite driver with modernc.org/sqlite (registered as
  "sqlite3"); a local compat shim under compat/sqlite/ provides the same
  import path and WAL-mode behaviour using system libsqlite3 while network
  access is unavailable — swapping to the real pure-Go package later only
  requires removing the replace directive and running go get.

- Add internal/admin/server.go: HTTP handler for /admin/ that serves a
  server-side-rendered post management UI (list, new, edit, delete). Posts
  are stored as Markdown files under content/posts/ and rebuilt via the
  existing Builder after every write. Basic auth is checked against the
  .passwords file when it exists.

- Add cmd/nebbet/main.go: unified CLI with build, watch, serve (HTTP server
  with admin + file server + watch), and user subcommands.

- Update builder.BuildAll to skip content/admin/ — admin pages are served
  dynamically and must never appear in the static output directory.

- Mark content/admin/index.md as draft so the old static placeholder is
  not built even if the admin skip logic is bypassed.

- Fix .gitignore: use /nebbet (root-only) so the pattern no longer
  accidentally ignores the cmd/nebbet/ source directory.

https://claude.ai/code/session_01WLuSGxJhNs2cFM2zJzSsTx
</content>
</entry>
<entry>
<title>Add static site builder: SQLite-backed MD→HTML pipeline</title>
<updated>2026-03-31T10:11:18Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-03-31T10:11:18Z</published>
<link rel='alternate' type='text/html' href='https://git.ivar.systems/nebbet.no/commit/?id=3cb7c82cf7c4e050148f69be23590a7fbe587a27'/>
<id>urn:sha1:3cb7c82cf7c4e050148f69be23590a7fbe587a27</id>
<content type='text'>
- cmd/nebbet: CLI with build [--watch] and user add/passwd/delete/list
- internal/builder: markdown→HTML, component injection via HTML comments,
  auto importmap from lib/, fsnotify watch with 150ms debounce
- internal/db: meta.db (page index, tag queries) + search.db (FTS5)
- internal/sqlitedrv: minimal CGO database/sql driver for system libsqlite3
- internal/auth: htpasswd-compatible bcrypt password file management
- templates/base.html + admin.html, styles/main.css + admin.css
- nginx.conf with auth_basic for /admin, clean URLs, gzip
- nebbet.service systemd unit for watch daemon
- Example content/index.md and components/site-greeting.js

https://claude.ai/code/session_01HTc1BCBCiMTEB54XQP1Wz9
</content>
</entry>
</feed>
