chore: documentation alignment

This commit is contained in:
2026-02-19 10:11:45 +01:00
parent 5dfe59b4be
commit 3d12cfbc89
2 changed files with 155 additions and 141 deletions

183
README.md
View File

@@ -1,135 +1,136 @@
# Blogging Desktop Server (bDS)
A desktop blogging application with offline-first capabilities.
Desktop-first blogging workspace built with Electron + TypeScript + React + SQLite (Drizzle), with filesystem-based content as source of truth.
## Features
## Current State (February 2026)
- **Offline-First**: All data is stored locally in SQLite, works without internet
- **VS Code-Inspired UI**: Familiar, clean interface with activity bar, sidebar, and editor
- **Markdown Posts**: Write blog posts in Markdown with YAML frontmatter
- **Media Management**: Import and manage images with metadata sidecar files
- **Clean Architecture**: Engine classes handle business logic, UI is purely presentational
Implemented and actively used:
- **Offline-first by default** with full local editing, preview, and git-based workflows; all online features are optional
- **Multi-project workflow** with active project switching and optional custom data paths
- **Post management** (draft/published/archived), pagination, filtering, full-text search, canonical URL handling
- **Media pipeline** with import, metadata sidecars, thumbnails, linked-media references, and cleanup tooling
- **Tag management** including merge/rename/sync from content
- **WordPress WXR import pipeline** (analysis, import definitions, execution/progress)
- **Preview server** with local assets only, Liquid templates, macro processing, archive routes, sitemap generation
- **Git integration** (status, diff, history, fetch/pull/push, init, .gitignore ensure, LFS prune)
- **Metadata diff tooling** for comparing filesystem metadata vs database metadata
- **AI chat persistence layer** (conversations/messages/model metadata) with OpenCode integration support
- **Task system** for progress reporting across long-running operations
## Architecture
```
```text
src/
├── main/ # Electron main process
│ ├── database/ # Drizzle ORM schema and connection
│ ├── engine/ # Business logic engines
│ │ ├── PostEngine # Post CRUD, file operations
│ │ ├── MediaEngine # Media import/management
│ │ ── TaskManager # Async task handling
├── ipc/ # IPC handlers for renderer communication
└── main.ts # App entry point
└── renderer/ # Electron renderer process (React)
├── components/ # UI components (VS Code style)
├── store/ # Zustand state management
── styles/ # Global CSS variables
├── main/
│ ├── database/ # Drizzle schema, migrations, connection
│ ├── engine/ # Core business logic (no UI)
│ │ ├── PostEngine
│ │ ├── MediaEngine
│ │ ── PostMediaEngine
│ ├── ProjectEngine
│ ├── MetaEngine
│ ├── TagEngine
├── PreviewServer
│ │ ├── Import* engines
│ │ ├── GitEngine
│ │ ── MetadataDiffEngine
│ │ ├── ChatEngine / OpenCodeManager
│ │ └── TaskManager
│ ├── ipc/ # IPC handlers; bridges renderer to engines
│ ├── shared/ # Shared contracts/types (Electron API)
│ └── main.ts # Electron app + menu + window lifecycle
└── renderer/
├── components/ # UI (editor, sidebars, panels, modals, views)
├── store/ # Zustand app state
├── macros/ # Macro authoring/runtime support
└── App.tsx # App composition + event wiring
```
## Data Storage
## Data Model & Storage
All user data is stored in the application's user data folder:
- **Primary DB**: `{userData}/bds.db`
- **Projects**: stored in DB with an active project
- **Per-project data**:
- default/internal: `{userData}/projects/{projectId}/`
- optional custom `dataPath` (posts/media/meta/thumbnails live together)
- **Filesystem remains source of truth** for post/media files; DB is query/index/state layer
- **Database**: `{userData}/bds.db` - SQLite database with post/media metadata
- **Posts**: `{userData}/posts/*.md` - Markdown files with YAML frontmatter
- **Media**: `{userData}/media/` - Image files with `.meta` sidecar files
Typical per-project folders:
### Post Format
```markdown
---
id: uuid-here
title: "My Blog Post"
slug: my-blog-post
status: draft
author: John Doe
createdAt: 2024-01-15T10:30:00.000Z
updatedAt: 2024-01-15T10:30:00.000Z
tags: ["javascript", "tutorial"]
categories: ["development"]
---
# My Blog Post
Your markdown content here...
```text
{projectDataDir}/
├── posts/
├── media/
├── meta/
└── thumbnails/
```
### Media Sidecar Format
## Menu / Shortcuts (Cross-Platform)
```yaml
---
id: uuid-here
originalName: "photo.jpg"
mimeType: image/jpeg
size: 102400
width: 1920
height: 1080
alt: "A beautiful sunset"
caption: "Sunset over the mountains"
createdAt: 2024-01-15T10:30:00.000Z
updatedAt: 2024-01-15T10:30:00.000Z
tags: ["nature", "sunset"]
---
```
Key shortcuts (defined as `CmdOrCtrl`):
### Internal Link Formats
Canonical formats for new content:
- Post links: `/YYYY/MM/DD/slug` (example: `/2025/02/16/my-post`)
- Media links: `/media/YYYY/MM/file.ext` (example: `/media/2025/02/photo.jpg`)
Also supported (legacy/alternative input formats):
- Post links: `/posts/slug`, `/posts/YYYY/MM/slug`, `post/slug`, `post/YYYY/MM/slug`
- Media links: `media/YYYY/MM/file.ext`
Preview HTML generation rewrites supported post/media link formats to preview-routable URLs. Markdown source remains unchanged except when inserting new media links from the editor, which now use `/media/...`.
- `CmdOrCtrl+N` New post
- `CmdOrCtrl+I` Import media
- `CmdOrCtrl+S` Save
- `CmdOrCtrl+1` Posts view
- `CmdOrCtrl+2` Media view
- `CmdOrCtrl+B` Toggle sidebar
- `CmdOrCtrl+J` Toggle panel
- `CmdOrCtrl+Shift+P` Publish selected
- `CmdOrCtrl+Shift+V` Preview active post in browser
## Development
### Prerequisites
- Node.js 18+
- npm or yarn
- npm
### Setup
### Install
```bash
# Install dependencies
npm install
```
# Start development mode
### Run (Development)
```bash
# Runs main TypeScript watch, Vite dev server, and Electron together
npm run dev
```
# In another terminal, start Electron
Alternative renderer+Electron flow:
```bash
npm start
```
### Building
### Tests
```bash
# Build for production
npm test
npm run test:watch
npm run test:coverage
```
### Build
```bash
# Generates drizzle artifacts, builds main process and renderer
npm run build
# Package for distribution (uses electron-builder)
# Package distributables
npx electron-builder
```
## Keyboard Shortcuts
### Database Utilities
| Shortcut | Action |
|----------|--------|
| Ctrl+N | New Post |
| Ctrl+S | Save |
| Ctrl+B | Toggle Sidebar |
| Ctrl+J | Toggle Panel |
| Ctrl+1 | View Posts |
| Ctrl+2 | View Media |
| Ctrl+Shift+P | Publish Selected |
```bash
npm run db:generate
npm run db:migrate
npm run db:studio
```
## License

113
VISION.md
View File

@@ -5,30 +5,35 @@ self-contained blogging engine with an integrated webserver and database that
allowed management of blog posts in an easy local way and a sync to a cloud
system for syncing data and also rendering the full blog.
This document remains the long-term vision, but parts of it are already
implemented in bDS (Electron + TypeScript + SQLite/Drizzle, multi-project
support, markdown/media workflows, preview server, importer pipeline,
task/progress UI, and git tooling).
## Main Vision
create a electron app in this folder that uses typescript for all the logic code
and sqlite and a proper database framework around it for local storage of data.
The app is an Electron app in this folder that uses TypeScript for logic code
and SQLite with a proper database framework for local storage of data.
The UI should be aligned with the UI patterns used by vscode. The name of the
application is "blogging Desktop Server" and the shortname is bDS. Startwith
default layout for edit and view menues and things like that. I don't want the
application is "blogging Desktop Server" and the shortname is bDS. Start with
default layout for edit and view menus and things like that. I don't want the
app to use raw SQL, I want some proper layer between those and proper wiring
where all actual functional code is kept in engine classes and the UI realy
just does presentation and reacts to state changes properly, so that
where all actual functional code is kept in engine classes and the UI really
just does presentation and reacts to state changes properly, so that
long-running processes can properly integrate as async tasks.
The main area of the window must be a tabbled view, where multiple tabs can be
The main area of the window must be a tabbed view, where multiple tabs can be
open at the same time and are retained over program runs. The tabs can be
different tabs like media file tabs, post tabs for multiple posts and setting
tabs or whatever will come later.
Blog post metadata should be managed in the SQLite database in the user local
folder, so it persists application runs properly. for blog posts, create a
folder, so it persists application runs properly. For blog posts, create a
subfolder /posts/ there where each post is stored as a markdown file with a
properties segment in the top of the file with YAML like property definitions,
properties segment at the top of the file with YAML-like property definitions,
so all metadata can always be reconstructed from posts. Do the same with images,
keeping them in /media/ under the user local path, in that case storing the
image file sand for each image file a properties sidecar file that uses the same
image files and for each image file a properties sidecar file that uses the same
header structure as for posts.
The application must be offline-first, everything must work in airplane mode
@@ -38,38 +43,38 @@ reflections in the filesystem, so available tags, available categories, all
those things must be automatically reflected to the filesystem in a per-project
way. Use a meta/ folder under the project folder for those files.
The application must be able to support multiple projects (ie web sites), so
The application supports multiple projects (ie web sites), so
there must be a way to create new projects and select current project. The UI is
only showing all data of the current selected project and all tools are only
working against the selected project. I can imagine that projects will be
separate databases and folders for post and media.
working against the selected project. Projects are currently separated by
project-scoped folders and metadata.
I want proper full-text search for posts based on the integrated sqlite
database using fts5, so that I can quickly find posts. So build proper text
I want proper full-text search for posts based on the integrated SQLite
database using FTS5, so that I can quickly find posts. Keep proper text
search index update into the core model right away, so that regardless how posts
come into the system, they are always properly indexed.
Additionally bring in a good markdown library, because all posts will be
formatted in markdown for easy portability to future systems. Media files can be
attached to posts and can be referenced with standard markdown notation with a
post-relative path, so it is easy for the user to include images. The post
editor should support both a wysiwyg editor and raw markdown editor, so the user
post-relative path, so it is easy for the user to include images. The post
editor should support both a WYSIWYG editor and raw markdown editor, so the user
does not have to know markdown, but everything is handled by the editor, but for
complex parts, markdown is available for power users.
Integrate toasts as notification mechanism that will be used whenever anything
has to communicate success/failure to the user.
Integrated images in posts should be shown with a lightbox effect als galleries
Integrated images in posts should be shown with a lightbox effect as galleries
when there are multiple photos, or just as single images with lightbox when
there is only one. The wysiwyg editor should support this at least on a basic
there is only one. The WYSIWYG editor should support this at least on a basic
level.
## Posting life-cycle
New posts start in draft state. Drafts are automatically saved in the
background, but the draft content is not directly part of the publishing
pipeline. A user can discard a draft, which either deltes a new post or reverts
pipeline. A user can discard a draft, which either deletes a new post or reverts
a post that is edited to the last published state.
A user can publish a post, that moves the content from the draft state to the
@@ -81,7 +86,7 @@ published. Editing only happens on the draft state. Undo/Redo is also only
available on the draft state editing session in the text field with standard
mechanisms.
published posts have a delete button that allows deleting a post that exists.
Published posts have a delete button that allows deleting a post that exists.
This will internally switch the post to deleted, and filter it out, but will not
remove it fully from the database, because the publishing pipeline later might
need the fact of the deletion as information source to do its thing (update
@@ -106,6 +111,7 @@ pipeline.
So only posts in state draft have content in the database, but whenever
something goes to state published, the draft content is set to empty. draft
something goes to state published, the draft content is set to empty. Draft
content contains text content as well as metadata content that was changed. So
even if the user changes tags or the category or the title or whatnot, the
actual data is first only kept in the database and only on publish moved to the
@@ -123,7 +129,7 @@ to delete, because that will break the relation.
## UI and UX specifics
The UI and UX should be aligned with modern applications like vscode. I want
iconbar and left sidebar and the big main area with tabbed views. Open views
an icon bar and left sidebar and the big main area with tabbed views. Open views
will be automatically opened again on next start, so the user does not have to
reselect everything.
@@ -147,21 +153,22 @@ via toasts. There is a central notification framework used by everything, so we
are sure that the user is informed about ongoing activities at all times.
There is a bottom status bar in the app that for example shows how many async
tasks are running at any time, so if we run maybe two importer in parallel, the
user will be able to see that there are 2 tasks running and will be abl to click
tasks are running at any time, so if we run maybe two importers in parallel, the
user will be able to see that there are 2 tasks running and will be able to click
on that to see a small popup that lists all active async tasks.
All preferences are always local to the selected project and project settings
are easily reachable via a gear icon in the bottom of the iconbar. Also login
are easily reachable via a gear icon in the bottom of the icon bar. Also login
credentials can be managed via a user icon in the bottom of the icon bar
directly above the gear icon. This is similar to what vscode does, separating
logins and settings.
Tags are something that should be mainly focus on reusing but need easy ways to
Tags are something that should be mainly focused on reusing but need easy ways to
add new tags. This should not be a simple text field, but more a feature like
tags in gitlab, where you can easily select multiple available tags, but also
tags in GitLab, where you can easily select multiple available tags, but also
can quickly create new tags. Tags should have a color and there should be a way
to manage tags in the preferences, too, so that users can create tags upfront to
to manage tags in the preferences, too, so that users can create tags upfront for
posts.
Categories are a simple selection via dropdown and a preferences panel that
@@ -184,17 +191,17 @@ should give a "links to" part in the UI (right sidebar or lower area of left
sidebar like with vscode?) and a "linked to by" part where incoming links are
shown.
Post need to support drag-and-drop image insert, and adding images must
Posts need to support drag-and-drop image insert, and adding images must
automatically create the related media file entry, so that metadata for images
can easily be set in the UI, but users get their posts set up quickly without
lots of hassle. Images that are referenced by posts are also linked in metadata
to the post, so that we have full overview what imags a post references in the
to the post, so that we have full overview of what images a post references in the
actual post data. And that data is also included in the published post file on
the file system.
Linkage data must be recoverable form posts and image links must be discoverable
Linkage data must be recoverable from posts and image links must be discoverable
from post text, too, so that a blog can be repaired if anything goes wrong.
There must be a strong focus on being indestructable for the blog, the most that
There must be a strong focus on being indestructible for the blog, the most that
could get lost can be draft content, but everything published must be fully
recoverable from data on the file system.
@@ -209,7 +216,7 @@ This is a variant of article with less text-focus but usually a strong focus on
attached images. This will show the image in a wide format if it is just one, or
a gallery view, if it is multiple images and will only show thumbnails for
overviews. This means we will need a library to manage image sizes properly for
thumbnails during media storage. those thumbnails must be created automatically.
thumbnails during media storage. Those thumbnails must be created automatically.
### category "aside"
@@ -217,11 +224,13 @@ This is a short-form article that does not need a full-article-page, because it
will just be a link and a short comment that is shown after the link. This is
meant for link collections and should be rendered in a compact form in the
overview pages. More on rendering in the publishing pipelin description.
overview pages. More on rendering in the publishing pipeline description.
### category "page"
This is a post that behaves mostly like an article, but is ignored in overview
pages, because it is just meant to be linked to menues. So menu editing needs to
pages, because it is just meant to be linked to menus. So menu editing needs to
be able to reference posts of category page and overview templates need to
ignore posts of category page. Other than that, they are just like article, so
have long form text, short form summary and title. Pages can be assigned
@@ -233,31 +242,32 @@ A project is not just the collection of posts, media and publish settings, it is
also a base project container with title, author and other elements like that.
So there needs to be project related settings that allow to give the project a
title, set up a main author that can be referenced in metadat and for example
title, set up a main author that can be referenced in metadata and for example
set up header images that can be used when publishing.
## Migrating
Prepare a proper mass-data importer that can read wordpress backup files, so the
user can bring in old wordpress blogs easily. That importer should run
Prepare and continue improving the mass-data importer that reads WordPress backup files, so the
user can bring in old wordpress blogs easily. The importer should run
asynchronously and properly communicate progress to the user while it is running
in the background. The import has to rebuild all metadata properly, so check if
we have all the metadata in our model set up in a similar way as Wordpress
handles it, so that we have a seamless integration. Posts in Wordpress backups
are html, but should be interpreted and transformed into proper markdown in the
handles it, so that we have a seamless integration. Posts in WordPress backups
are HTML, but should be interpreted and transformed into proper markdown in the
import.
In general, HTML elements of the post have to all be transformed into markdown
equivalents, and not use embedded HTML, for as much as possible. We want clean
markdown in the posts after the import, not a mix of markdown and HTML.
For this AI support during import to work, the blog application needs to provide
For AI support during import to work, the blog application needs to provide
post management and media management functionality as proper AI tools to the
OpenCode Zen API, so that it will be able to work on those posts.
The AI importing agent must discover the language of a post and put that in an
attribute. Posts must have the database structure of translations, so that a
post that is discovered as being german can be automatically translated to
english and vice-versa. After import, all posts are available in two languages.
English and vice-versa. After import, all posts are available in two languages.
Another thing the AI importing agent must do is create summaries of posts to put
into a summary attribute on posts in the database, so that those can be used in
@@ -270,7 +280,7 @@ be linked to the same tag of the new import, so that the user can see it was
referenced by multiple imports.
Essentially my main idea for imports is that the importer is classes that can
read websits from different sources (starting with wordprss backup and HTTP URL)
read websites from different sources (starting with WordPress backup and HTTP URL)
and that each discovered element is handed to the AI to convert to markdown and
in the case of the HTTP URL also separate out posts, then use the tools to check
for duplicates and update tags or create new posts based on the process.
@@ -298,15 +308,16 @@ Also the AI should be available to create summaries just with a button click in
the post editor area, so that the summary is filled in based on AI summarization
to help speed up the blogging process. Also the AI can be used to generate a
good slurl that is not just generically from the title and even the title can be
good slug that is not just generically from the title and even the title can be
AI-generated from the text. That way the user can focus on writing the core text
and if all matches, just accept AI summary and title and post it.
## Previewing
There should be an integrated web server that can be opened from the file menu
There is an integrated web server that can be opened from the file menu
in a browser (menu item "open in browser" starts the default browser with the
localhost URL) too look at what the site would look after publishing. The
preview should just run live through what the exporter would do to each page
localhost URL) to look at what the site would look like after publishing. The
preview should run live through what the exporter would do to each page
that is sent to the server. This gives a proper preview of things to come.
Preview should include draft content, so that even before publishing the user
@@ -317,7 +328,7 @@ publish state, if we want that later.
## Publishing
Publishing should target static HTML/CSS/JavaScript situations. There must be a
asnyc exporter, that will render all affected pages based on the structure of
async exporter, that will render all affected pages based on the structure of
the export and auto-update affected files when the posts or media that are used
in the page were changed. This requires a cross-reference table that links posts
and media entries with actual HTML files that are referencing them. This needs
@@ -327,20 +338,21 @@ Essentially the publishing pipeline knows what posts changed since last
publishing (maybe a version number that is pulled from a central place, so that
any change will raise that version and any post and media that has a higher
version number of the last publish run is seen as changed) and will run the
relevant templates to recreate all linkd pages of the publishing (single post
relevant templates to recreate all linked pages of the publishing (single post
pages for the post but also many overview pages) and of course each page is only
updated once in the publishing run, collecting all changed posts for that.
The main driver is a proper blog structure with templates. For this I want
proper templates I can manage and edit in the application itself. Template
editing should provide proper syntax highlighting, so something like monaco is
important. Choose a good solid template engine for node-js based tools that is
especialy targeted to easy template creation.
important. Choose a good solid template engine for Node.js-based tools that is
especially targeted to easy template creation.
For the styling I want the system to be based on css templates, so that the look
can be easily swapped to the wish of the user. There should be a selection of
light and dark themes bundled with the application, so that starting is simple.
New css templates must be easily integrateable into the application, maybe even
New CSS templates must be easily integrable into the application, maybe even
with easy importing from a central repository site or something like that. I
think Pico CSS is a good choice, since it sticks to semantic HTML and
auto-adapts to light/dark mode settings of users. I want to work minimalist, but
@@ -348,7 +360,7 @@ still allow some style influence into the site based on user prefs.
Check the site https://hugo.rfc1437.de/ for its structure, this is the structure
of blog I want to be capable of building with this tooling. So we need templates
for overview pages and ways to manage menues that reference overview pages and
for overview pages and ways to manage menus that reference overview pages and
structure the menu according to site structure. Also support calendar views to
allow users to go to specific months and years of the blog. Build up a sensible
set of templates that come with a new project, so that the user can start right
@@ -357,6 +369,7 @@ website, but keep out website title and images, of course.
Categories and tags must be able to define a template selection for post
templates, so that different types can be represented differently. this is
templates, so that different types can be represented differently. This is
especially important for the standard categories "article", "picture" and
"aside", as they should come right away with templates for their article page
and their use in overviews. Every post can define via category or tag
@@ -364,10 +377,10 @@ and their use in overviews. Every post can define via category or tag
article-specific template selections).
There must be way to open a browser tab in the application that then uses the
applicaiton itself and does dynamic rendering of the content, using the same
templates and everything else, so that the user can do a propoer preview before
application itself and does dynamic rendering of the content, using the same
templates and everything else, so that the user can do a proper preview before
deciding to update the remote static web storage. The browser tab will of course
use the correct styling of the website.
Publishing of files can be configured to be done via FTP or SSH, connection data
must be configureable in preferences for the website.
must be configurable in preferences for the website.