Decision Log
Key architectural and design decisions made during Lamb’s development.
Procedural PHP with namespaces (not MVC)
Decision: Use namespaced procedural PHP rather than an MVC framework.
Rationale: Lamb targets single-author self-hosting with minimal setup. A framework would add complexity, dependencies, and upgrade friction. Namespaced PHP files give logical organisation without the overhead of a class hierarchy or a DI container. The routing model (register_route / call_route) is intentionally trivial.
SQLite via RedBeanPHP (fluid mode)
Decision: Use SQLite with RedBeanPHP ORM in fluid mode (automatic schema evolution).
Rationale: A single-author microblog rarely needs multi-writer concurrency. SQLite is zero-config, ships as a single file, and is easy to back up. Fluid mode means schema migrations happen automatically and there is no migration runner to maintain. The trade-off is that column types are inferred by RedBeanPHP and can change; this is acceptable for a small personal blog.
INI text stored in the database (not config files on disk)
Decision: Store the site configuration as raw INI text in the option table rather than reading a file from disk at runtime.
Rationale: Keeping config in the database avoids file-permission issues on shared hosts and simplifies deployment (no writable config directory needed outside of the database file itself). The INI format is kept because it is human-readable and easy to edit in a <textarea>, with a clear upgrade path if a structured UI is ever added.
No automatic reslugging on title changes
Decision: Once a page slug is created it is not overwritten when the title is edited.
Rationale: “Good URLs don’t change.” Silently resluggling on edit would break external links. If an author deliberately wants a new slug they must set slug: in the front-matter explicitly. When a slug is changed, a 301 redirect is created automatically so old links remain valid.
Soft-delete (trash) instead of hard-delete
Decision: Deleting a post marks it as deleted (deleted = 1) rather than removing the database row.
Rationale: Accidental deletion is a common user error. Soft-delete provides a safety net at minimal cost. The /trash page is admin-only, so deleted posts are not publicly visible.
Themes by file fallback, not inheritance
Decision: Custom themes only need to provide the files they wish to override. Missing files fall back to the default theme automatically.
Rationale: This minimises the amount of boilerplate a theme author must maintain. A theme can be a single CSS file if only the styling differs, which lowers the barrier for customisation.
Feed ingestion saved as drafts by default
Decision: Posts ingested from external feeds are saved as drafts unless feeds_draft = false is set.
Rationale: Lamb is a single-author blog. The author should retain editorial control over cross-posted content; surfacing ingested items as drafts for review respects that. Authors who want automatic publishing can opt in with a config flag.
Micropub via IndieAuth (no bespoke auth)
Decision: The Micropub endpoint delegates authentication entirely to IndieAuth rather than implementing its own token system.
Rationale: Implementing token issuance and revocation correctly is non-trivial. Delegating to IndieAuth (indieauth.com or a self-hosted server) keeps Lamb’s auth surface small and leverages a well-specified open standard.