aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorgrm <grm@eyesin.space>2026-09-12 11:43:14 +0300
committergrm <grm@eyesin.space>2026-09-12 11:43:14 +0300
commitf0eaf46755e04b806e2df07a2fabd4060a72d54c (patch)
treef6d8f9fda0bb6e2fa7ae6304d4ad0c12217f3233 /cmd
parent3eb04b1a2bdf9e53231fe862cfd76327371a9741 (diff)
downloadblogspace-f0eaf46755e04b806e2df07a2fabd4060a72d54c.tar.gz
blogspace-f0eaf46755e04b806e2df07a2fabd4060a72d54c.tar.bz2
blogspace-f0eaf46755e04b806e2df07a2fabd4060a72d54c.zip
Serve the superadmin's blog on the root domain
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
Diffstat (limited to 'cmd')
-rw-r--r--cmd/blogspace/main.go23
-rw-r--r--cmd/blogspace/seed.go16
2 files changed, 39 insertions, 0 deletions
diff --git a/cmd/blogspace/main.go b/cmd/blogspace/main.go
index 3a60bd4..cf240a8 100644
--- a/cmd/blogspace/main.go
+++ b/cmd/blogspace/main.go
@@ -65,6 +65,9 @@ func run(ctx context.Context, cfg *config.Config, cmd string) error {
if err := bootstrapSuperadmin(ctx, cfg, st); err != nil {
return err
}
+ if err := ensureRootBlog(ctx, cfg, st); err != nil {
+ return err
+ }
return serve(ctx, cfg, st)
default:
return fmt.Errorf("unknown command %q (serve|seed|migrate)", cmd)
@@ -119,6 +122,26 @@ func bootstrapSuperadmin(ctx context.Context, cfg *config.Config, st *store.Stor
return nil
}
+// ensureRootBlog makes sure the blog served on the base domain exists; it is owned by the first superadmin.
+func ensureRootBlog(ctx context.Context, cfg *config.Config, st *store.Store) error {
+ _, err := st.BlogBySubdomain(ctx, config.RootSubdomain)
+ if err == nil {
+ return nil
+ }
+ if !errors.Is(err, store.ErrNotFound) {
+ return err
+ }
+ admin, err := st.FirstSuperadmin(ctx)
+ if err != nil {
+ return fmt.Errorf("root blog needs a superadmin: %w", err)
+ }
+ if _, err := st.CreateBlog(ctx, admin.ID, config.RootSubdomain, cfg.BaseDomain); err != nil {
+ return fmt.Errorf("create root blog: %w", err)
+ }
+ log.Printf("created root blog %s owned by %q", cfg.BaseDomain, admin.Username)
+ return nil
+}
+
func serve(ctx context.Context, cfg *config.Config, st *store.Store) error {
srv := &http.Server{
Addr: cfg.Addr,
diff --git a/cmd/blogspace/seed.go b/cmd/blogspace/seed.go
index 847324c..010eff5 100644
--- a/cmd/blogspace/seed.go
+++ b/cmd/blogspace/seed.go
@@ -24,6 +24,9 @@ func seed(ctx context.Context, cfg *config.Config, st *store.Store) error {
if err := bootstrapSuperadmin(ctx, cfg, st); err != nil {
return err
}
+ if err := ensureRootBlog(ctx, cfg, st); err != nil {
+ return err
+ }
if _, err := st.UserByUsername(ctx, "alice"); err == nil {
log.Println("seed: alice already exists, nothing to do")
return nil
@@ -103,6 +106,19 @@ func seed(ctx context.Context, cfg *config.Config, st *store.Store) error {
return err
}
}
+ // a welcome post on the root blog (the superadmin's own blog on the base domain)
+ root, err := st.BlogBySubdomain(ctx, config.RootSubdomain)
+ if err != nil {
+ return err
+ }
+ rootHome, err := st.HomePage(ctx, root.ID)
+ if err != nil {
+ return err
+ }
+ welcome := "This is the blog on the **root domain**, owned by the superadmin. It works like every other blog.\n\nOther blogs live on subdomains, for example [alice](" + cfg.BlogURL("alice") + ")."
+ if _, err := st.CreatePost(ctx, &store.Post{PageID: rootHome.ID, Title: "Welcome to Blogspace", Slug: "welcome", BodyMD: welcome, BodyHTML: markdown.Render(welcome), Published: true}); err != nil {
+ return err
+ }
log.Printf("seed: superadmin %q (password %q in dev), blogger alice / alicealice at %s", cfg.SuperadminUsername, "admin", cfg.BlogURL("alice"))
return nil
}