How-to: a blog

The blog is what septic is for: posts live in a database, and septic build turns the published ones into a static site via poops. One config; drafts never ship.

The backend half. You end with posts in a database and a built site. Writing them from an admin page served beside that site is laxative's version of this how-to.

1. The posts resource

{
  "septic": {
    "db": "data/blog.db",
    "auth": { "seed": { "email": "you@example.com", "password": "changeme", "role": "admin" } },
    "resources": {
      "posts": {
        "methods": ["GET", "POST", "PUT", "DELETE"],
        "access": { "read": "public", "write": "admin" },
        "fields": {
          "title":        "string required",
          "slug":         "slug required unique",
          "body":         "text required",
          "excerpt":      "text",
          "status":       "enum(draft,published) = draft",
          "published_at": "datetime",
          "created":      "datetime = now",
          "updated":      "datetime = now!"
        }
      }
    }
  }
}

2. Wire the bridge โ€” published only

"build": {
  "resources": {
    "posts": {
      "into": "src/markup/posts",
      "slug": "slug",
      "body": "body",
      "layout": "post.html",
      "where": { "status": "published" }
    }
  }
}

where is the important bit: septic build emits only published rows, so drafts stay out of the static site. Each post becomes src/markup/posts/<slug>.md โ€” YAML front matter (title, excerpt, published_at, โ€ฆ) + the body โ€” kept in step each build (only changed files rewritten, deleted rows swept), then poops compiles the site.

3. Write a post

npx septic serve
# log in
curl -c jar -X POST localhost:3000/api/_auth/login \
  -H 'content-type: application/json' -d '{"email":"you@example.com","password":"changeme"}'
# publish one
curl -b jar -X POST localhost:3000/api/posts -H 'content-type: application/json' \
  -d '{"title":"Hello","slug":"hello","body":"# Hi\n\nFirst post.","status":"published","published_at":"2026-08-05 12:00:00"}'

4. Build the static site

npx septic build      # published posts โ†’ src/markup/posts/*.md โ†’ poops โ†’ dist/

A post.html layout renders each post; a posts/index.html lists the collection โ€” that part is poops, the static-site generator. A minimal layout:

<!-- post.html -->
<article>
  <h1>{{ page.title }}</h1>
  <time>{{ page.published_at }}</time>
  {{ content }}
</article>

5. Author from a form (optional)

Add build.forms for a write/edit form:

"build": { "forms": { "posts": { "into": "src/markup/_partials", "submitLabel": "Publish" } } }

GET /api/posts/:id as an admin wanting HTML returns a prefilled edit form (PUT). See Forms.

What you got

Posts in a database โ†’ a static blog, drafts excluded, from one config. For the full app โ€” an admin page to write posts, served next to the site โ€” see the same how-to in laxative.