Project Structure
Every file and directory in a Blog-Doc installation, and what each one does.
Understanding the layout before you touch anything saves a lot of confusion later.
blog-doc/
├── index.js # Entry point — app wiring & server start
├── update.js # Runnable script — pull latest app version
├── package.json
├── .env # Optional — PORT override
├── app/
│ ├── content/
│ │ ├── pages/ # Page .md files (slug-as-filename)
│ │ ├── posts/ # Post .md files (slug-as-filename)
│ │ └── images/ # Uploaded images
│ ├── data/
│ │ ├── settings.json # Site-wide settings
│ │ ├── menus.json # Menu definitions
│ │ ├── active-theme.json # Currently active theme ID
│ │ └── search.json # Auto-generated search index
│ └── themes/
│ └── {themeId}/ # One directory per installed theme
│ ├── theme.json # Theme manifest
│ ├── screenshot.* # Required preview image
│ ├── templates/ # STE HTML templates
│ └── assets/ # CSS, JS, fonts, images
├── admin/
│ ├── assets/ # Admin CSS, JS, fonts
│ ├── functions/ # Pure data/business logic (no HTTP)
│ │ ├── admin-bar.js # Dev-only admin bar middleware
│ │ ├── build.js # Static site generator
│ │ ├── data.js # File I/O helpers, PATHS, slug utilities
│ │ ├── frontmatter.js # YAML frontmatter serialization
│ │ ├── search.js # Search index generator
│ │ └── site-data.js # Content assembly for templates
│ ├── routes/ # All route handler modules
│ └── views/ # Admin HTML templates (STE)
└── _site/ # Generated static site (git-ignored)
Key directories
app/content/
This is where your content lives. Files are plain Markdown with YAML frontmatter. The filename (without .md) is the slug — about.md becomes /about.
app/data/
Plain JSON configuration files. You never need to edit these by hand — the admin GUI writes to them — but they're human-readable and easily version-controlled.
app/themes/
Each installed theme is a subfolder here. The active theme is tracked in active-theme.json by its folder name (the theme id).
admin/
The admin application itself. routes/ handles HTTP, functions/ is pure business logic with no HTTP dependencies. The clean separation means you can read and test build.js or site-data.js without spinning up the server.
Module responsibilities
| Module | Location | Responsibility |
|---|---|---|
admin-bar.js |
admin/functions/ | Admin bar injected into live theme responses |
build.js |
admin/functions/ | Static site generator — pure, idempotent function |
data.js |
admin/functions/ | All file I/O, PATHS constants, slug utilities |
frontmatter.js |
admin/functions/ | Serialize form fields back to clean .md files |
search.js |
admin/functions/ | Generate and write search.json |
site-data.js |
admin/functions/ | Assemble template data objects per route |
The adminBarMiddleware wraps res.end on every non-/admin request, checks for text/html content type, and injects the floating admin bar before </body>. The bar is absent from static builds. No changes to themes or templates are required.
_site/
Created on demand by the build engine. Add it to .gitignore. Every build wipes it and starts fresh.
Architecture layers
Route registration order in index.js is intentional and must be preserved:
// 1. Admin GUI routes → /admin/*
registerAdminUIRoutes(app)
// 2. Admin API routes → /admin/api/*
const apiRouter = new LiteNode("__NO_STATIC_DIR__")
// ... register all API routes on apiRouter ...
app.nest("/admin/api", apiRouter)
// 3. Admin bar middleware (dev only — never runs during static build)
app.use(adminBarMiddleware)
// 4. Live theme routes → /* (registered last — catch-all)
registerLiveTheme(app)
The live theme is registered last because its catch-all /:pagename route would swallow every other route if registered first.
The three main layers
| Layer | Base path | Purpose |
|---|---|---|
| Admin GUI | /admin/* |
Browser-based content management |
| Admin API | /admin/api/* |
JSON REST API consumed by the GUI |
| Live theme | /* |
Serves the active theme dynamically |
All three share the same Node.js process and the same filesystem. There is no authentication — Blog-Doc is a local tool.
Updating Blog-Doc
update.js updates Blog-Doc to the latest version by pulling the newest code from the repository and refreshing dependencies.
Run this from your project root to update Blog-Doc whenever a new version is released:
node update.js
or
npm run update
Your content and data are never touched by this script.
The following are gitignored and therefore completely safe:
| Folder | Contents |
|---|---|
app/content/ |
Pages, posts, and uploaded images. |
app/data/ |
Site settings, navigation menus, and the active theme. |
app/themes/ |
Installed themes (excluding the bundled default theme). |