| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
|
|
|
| |
Clicking "Blogspace" in the top bar went to the public root blog; from
inside the dashboard it should go back to your blog's overview. /dashboard
already resolves that (own blog, or /admin/ for a superadmin without one),
so the link points there when there is a user and stays / on the login page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A blog is now a database of its own (blog_<sub>) on the same server: one
pg_dump is a complete backup of a blog, one psql restores it, and nothing a
blog's queries do can reach another blog's rows. The control database
(DATABASE_URL) keeps only users and the blog registry (id, owner, subdomain,
db_name); title, tagline and theme move into a one-row settings table next
to the content so the dump really is everything.
db.Cluster holds the control pool plus small, lazily opened per-blog pools.
store.Store (control) hands out a store.BlogStore per blog; every blog_id
parameter and column is gone, the database is the scope. Handlers reach it
through blogStore(r), which resolveBlog puts in the context next to the blog.
Existing data is moved in place by control migration 00006, a Go migration
that runs inside the control transaction: it creates and migrates each blog
database, copies the rows preserving ids, and marks the registry; 00007 then
drops the old tables. Either every blog is moved or the control database is
untouched.
/media/{id} now serves the host's blog only, so dashboard previews on the
root domain use /b/{sub}/media/{id}. Subdomains are capped at 58 chars so
"blog_" + name fits a Postgres identifier. Deleting a user drops their
database. Store.Open resets a blog's pool and retries once so a database
restored under a running app (dropdb --force, createdb, psql) just works.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
| |
With the column grid, a centred max-width box meant the main content did
not fill the page when no side columns were shown. The column
percentages now divide the whole page; a blogger who wants a narrower,
centred main column keeps the columns' space instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A blog page is now header, left column, main content, right column and
footer, each holding an ordered list of modules (blog title, logo, menu,
archive by year/month, recent posts, custom HTML, footer text, RSS link,
site map). Side columns have percentage widths, can be hidden, and can
keep their space when empty; on phones they stack under the posts. The
menu becomes its own ordered list mixing pages and outside links.
Announcements are placed per column at its top or bottom.
Modules and menu items get tables; the migration derives them from each
blog's old theme (nav position, footer text, show-in-nav pages) so
existing blogs look the same. Custom HTML is deliberately stored and
served as-is (owner's decision; see AGENTS.md for why the blast radius
is the blogger's own origin).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Blogs had no icon at all, and browsers probing /favicon.ico ended up
rendering the 404 page. Ship a default paper & ink icon (svg + png) and
let each blog replace it from the Design page; /favicon.ico now serves
the default or redirects to the blog's own image. ICO uploads accepted.
The Design page gains colour schemes, reset to defaults, thumbnail
image pickers, jump links and a sticky save bar, plus new options:
heading font, link underline/hover, content box style and padding,
header image height, post dates and format, footer RSS toggle, menu
alignment/style/hover and sidebar width. The Menu card picks the
position with illustrated tiles and shows only the options that apply
to it, using CSS :checked rules rather than JavaScript.
All new defaults reproduce the previous look, so existing blogs are
unchanged until edited. Theme is jsonb, so no migration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
| |
A blog can have any number of announcements ("sections" in the schema):
a book club's next meeting, this month's pick, a holiday closure. Each
has a placement (above or below the posts, or under the menu when the
menu is a left sidebar), a look (highlighted, warning, plain), an order,
and an on/off switch so recurring notices can be kept around while hidden.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
| |
A shared editor partial adds an "Insert image" file picker plus paste and
drag-and-drop on the textarea; a few lines of inline JS upload the file to
the existing images endpoint (which now answers JSON when asked) and put
the Markdown at the caret. Without JS the same file rides along with the
form and is appended to the text on save, so nothing depends on scripting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Flat colours, 2px rules, hard offset shadows and square corners; mono
headings and labels; the blog nav is a tab strip that scrolls sideways on
phones instead of stacking; list pages get a page header with the primary
action on the right; the Markdown cheat-sheet collapses into a details
element so forms stay calm. Plain CSS only, no variables or flex, so it
still renders on old browsers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
| |
The login URL is less guessable, bloggers can type /webadmin on their own
blog and get bounced to the root login page (and back to their dashboard
after logging in), and the public root blog no longer advertises the
admin entry point in its footer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
| |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
| |
The base domain (and www.) now serves a regular blog owned by the first
superadmin, created automatically on startup, alongside the management
routes. Literal management paths take precedence over the blog's page
wildcards, and the slugs they would shadow are reserved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
|
|
Go + Postgres application serving a management dashboard on the base
domain and one public blog per subdomain. Markdown posts organised in
pages, form-based theme customisation, image uploads stored in Postgres,
JWT cookie sessions with CSRF, superadmin user management, RSS feeds.
Docker/compose deployment and a Makefile-driven dev environment with
seed data.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|