diff --git a/Makefile b/Makefile
index 3134371..a733dc4 100755
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all clean norm author author-stop author-restart author-status help
+.PHONY: all clean norm author author-install author-start author-stop author-restart author-status author-logs author-health help
VENV := .venv
PY := $(VENV)/bin/python
@@ -7,11 +7,13 @@ PERM_DIR := /home/zaine/master-folder/projects/scripts/bash-scripts
AUTHOR_PORT := 8765
AUTHOR_URL := http://127.0.0.1:$(AUTHOR_PORT)
-AUTHOR_PID := /home/zaine/logs/authoring-server.pid
-AUTHOR_LOG := /home/zaine/logs/authoring-server.log
AUTHOR_PAGES_CHECK := /tmp/authoring-server-pages.json
+AUTHOR_SERVICE := org-web-authoring.service
+AUTHOR_UNIT_SRC := systemd/user/$(AUTHOR_SERVICE)
+SYSTEMD_USER_DIR := $(HOME)/.config/systemd/user
+AUTHOR_UNIT_DST := $(SYSTEMD_USER_DIR)/$(AUTHOR_SERVICE)
-all: set-perms clean-output build search author-restart clean-venv
+all: set-perms clean-output build search author-restart
build:
@echo "Building project..."
@@ -42,41 +44,37 @@ norm:
@echo "sorting out the backups..."
find . -path ./backups -prune -o -type f -name '*~' -exec mv {} backups/ \;
-author: $(VENV)
- @echo "Starting local authoring UI in foreground..."
- $(PY) authoring_server.py
+author: author-start
+
+author-install: $(VENV)
+ @echo "Installing $(AUTHOR_SERVICE) for the current user..."
+ @mkdir -p "$(SYSTEMD_USER_DIR)"
+ install -m 0644 "$(AUTHOR_UNIT_SRC)" "$(AUTHOR_UNIT_DST)"
+ systemctl --user daemon-reload
+ systemctl --user enable "$(AUTHOR_SERVICE)"
+
+author-start: author-install
+ @echo "Starting authoring UI with systemd..."
+ systemctl --user start "$(AUTHOR_SERVICE)"
+ @$(MAKE) --no-print-directory author-health
author-stop:
- @echo "Stopping existing authoring UI if running..."
- @mkdir -p /home/zaine/logs
- @if [ -f "$(AUTHOR_PID)" ]; then \
- PID=$$(cat "$(AUTHOR_PID)"); \
- if kill -0 $$PID 2>/dev/null; then \
- echo "Stopping PID $$PID"; \
- kill $$PID 2>/dev/null || true; \
- for i in 1 2 3 4 5; do \
- if ! kill -0 $$PID 2>/dev/null; then break; fi; \
- sleep 1; \
- done; \
- if kill -0 $$PID 2>/dev/null; then \
- echo "PID $$PID did not stop cleanly; killing it."; \
- kill -9 $$PID 2>/dev/null || true; \
- fi; \
- fi; \
- rm -f "$(AUTHOR_PID)"; \
- fi
- @fuser -k $(AUTHOR_PORT)/tcp >/dev/null 2>&1 || true
+ @echo "Stopping authoring UI with systemd..."
+ systemctl --user stop "$(AUTHOR_SERVICE)" || true
-author-restart: $(VENV) author-stop
- @echo "Starting authoring UI on port $(AUTHOR_PORT)..."
- @mkdir -p /home/zaine/logs
- @cd "$(CURDIR)" && nohup "$(CURDIR)/$(PY)" -u authoring_server.py > "$(AUTHOR_LOG)" 2>&1 & echo $$! > "$(AUTHOR_PID)"
+author-restart: author-install
+ @echo "Restarting authoring UI with systemd..."
+ systemctl --user restart "$(AUTHOR_SERVICE)"
+ @$(MAKE) --no-print-directory author-health
+
+author-health:
@echo "Waiting for authoring UI and page list to respond..."
@for i in 1 2 3 4 5 6 7 8 9 10; do \
- PID=$$(cat "$(AUTHOR_PID)"); \
- if ! kill -0 $$PID 2>/dev/null; then \
- echo "Authoring UI process exited before becoming healthy. Last logs:"; \
- tail -n 80 "$(AUTHOR_LOG)" || true; \
+ if ! systemctl --user is-active --quiet "$(AUTHOR_SERVICE)"; then \
+ echo "Authoring UI service is not active. Service status:"; \
+ systemctl --user status --no-pager "$(AUTHOR_SERVICE)" || true; \
+ echo "Recent logs:"; \
+ journalctl --user -u "$(AUTHOR_SERVICE)" -n 80 --no-pager || true; \
exit 1; \
fi; \
if curl -fsS "$(AUTHOR_URL)/api/pages" -o "$(AUTHOR_PAGES_CHECK)" && $(PY) -c 'import json,sys; data=json.load(sys.stdin); sys.exit(0 if isinstance(data, list) and data else 1)' < "$(AUTHOR_PAGES_CHECK)"; then \
@@ -85,18 +83,19 @@ author-restart: $(VENV) author-stop
fi; \
sleep 1; \
done; \
- echo "Authoring UI failed to start. Last logs:"; \
- tail -n 80 "$(AUTHOR_LOG)" || true; \
+ echo "Authoring UI failed to respond. Service status:"; \
+ systemctl --user status --no-pager "$(AUTHOR_SERVICE)" || true; \
+ echo "Recent logs:"; \
+ journalctl --user -u "$(AUTHOR_SERVICE)" -n 80 --no-pager || true; \
exit 1
author-status:
- @if [ -f "$(AUTHOR_PID)" ] && kill -0 $$(cat "$(AUTHOR_PID)") 2>/dev/null; then \
- echo "PID: $$(cat "$(AUTHOR_PID)")"; \
- else \
- echo "No live authoring UI PID recorded."; \
- fi
+ @systemctl --user status --no-pager "$(AUTHOR_SERVICE)" || true
@curl -fsS "$(AUTHOR_URL)/api/pages" -o "$(AUTHOR_PAGES_CHECK)" && $(PY) -c 'import json,sys; print(f"Pages: {len(json.load(sys.stdin))}")' < "$(AUTHOR_PAGES_CHECK)" || true
+author-logs:
+ journalctl --user -u "$(AUTHOR_SERVICE)" -n 100 --no-pager
+
help:
@echo "Available targets:"
@echo " make - Full rebuild and restart authoring UI"
@@ -105,9 +104,11 @@ help:
@echo " make clean-output - Remove output directory"
@echo " make clean-venv - Remove venv directory"
@echo " make norm - Move backup files"
- @echo " make author - Start the local authoring UI in foreground"
- @echo " make author-stop - Stop the authoring UI"
- @echo " make author-restart - Restart the authoring UI in background"
- @echo " make author-status - Show authoring UI PID and page count"
+ @echo " make author - Install and start the authoring UI service"
+ @echo " make author-install - Install and enable the authoring UI service"
+ @echo " make author-stop - Stop the authoring UI service"
+ @echo " make author-restart - Restart the authoring UI service"
+ @echo " make author-status - Show authoring UI service status and page count"
+ @echo " make author-logs - Show recent authoring UI service logs"
@echo " make search - Create the search index"
@echo " make help - Show this help message"
diff --git a/README.md b/README.md
index 60ec461..cb5f1b0 100755
--- a/README.md
+++ b/README.md
@@ -6,7 +6,14 @@ The site is written using Emacs and Org-mode, and exported using the `org-publis
## Local authoring UI
-Run `make author` and open `http://127.0.0.1:8765` to create or edit blog and post Org files from a browser. When deployed behind the reverse proxy, use `https://author.zainezq.com`.
+Run `make author` to install and start the user systemd service, then open `http://127.0.0.1:8765` to create or edit blog and post Org files from a browser. When deployed behind the reverse proxy, use `https://author.zainezq.com`.
+
+The service unit is checked in at `systemd/user/org-web-authoring.service` and is installed to `~/.config/systemd/user/` by the Makefile. Useful service commands:
+
+- `make author-restart` restarts the service and waits for the page API to respond
+- `make author-stop` stops the service
+- `make author-status` shows systemd status and the editable page count
+- `make author-logs` shows recent journal logs
The editor writes normal `.org` pages with the metadata used by the publishing pipeline:
diff --git a/posts/posts-list.org b/posts/posts-list.org
index 4319789..073c1b6 100755
--- a/posts/posts-list.org
+++ b/posts/posts-list.org
@@ -4,7 +4,7 @@
See the categories: @@html:Categories@@
* Posts:
-- [[file:career/career-list.org][Career List]] @@html:07-05-2026 16:45@@
+- [[file:career/career-list.org][Career List]] @@html:07-05-2026 23:40@@
- [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:14-04-2026 16:36@@
- [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:11-03-2026 17:18@@ @@html:learning@@ @@html:notes@@
- [[file:career/javascript.org][Understands the Javascript language]] @@html:11-03-2026 16:52@@ @@html:learning@@ @@html:notes@@
diff --git a/sitemap.org b/sitemap.org
index 2789160..0aed73c 100755
--- a/sitemap.org
+++ b/sitemap.org
@@ -12,9 +12,9 @@
- [[file:tags/review.org][Tag: review]]
- [[file:tags/website.org][Tag: website]]
- [[file:tags/update.org][Tag: update]]
+ - [[file:tags/insights.org][Tag: insights]]
- [[file:tags/life.org][Tag: life]]
- [[file:tags/education.org][Tag: education]]
- - [[file:tags/insights.org][Tag: insights]]
- [[file:tags/reading.org][Tag: reading]]
- [[file:tags/emacs.org][Tag: emacs]]
- [[file:tags/maths.org][Tag: maths]]
diff --git a/systemd/user/org-web-authoring.service b/systemd/user/org-web-authoring.service
new file mode 100644
index 0000000..568b3c4
--- /dev/null
+++ b/systemd/user/org-web-authoring.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Org web authoring UI
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/home/zaine/master-folder/org_files/org_web
+Environment=AUTHOR_ROOT=/home/zaine/master-folder/org_files/org_web
+Environment=AUTHOR_PORT=8765
+Environment=PYTHONUNBUFFERED=1
+ExecStart=/home/zaine/master-folder/org_files/org_web/.venv/bin/python -u /home/zaine/master-folder/org_files/org_web/authoring_server.py
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=default.target