markdown

Editable blog

A Lightweight, Self‑Hosted, Multilingual CMS


1. The Problem

I wanted a personal publishing platform that would let me write a post once, have it automatically translated, share it on LinkedIn, and schedule the publication – all without juggling multiple tools or a heavyweight CMS. The solution had to run on my own Kubernetes node, be fast for visitors, and keep the editorial workflow friction‑less.

2. Core Architecture

ComponentChoice & Rationale
Frontend / renderingSvelteKit with Server‑Side Rendering (SSR). Because most pages are static, SSR delivers sub‑second first‑byte times without a separate build step.
DatabasePostgreSQL – stores markdown content, inline images/PDFs (as BLOBs), version metadata and LinkedIn post settings.
Automation / translationn8n workflows triggered from the UI. A post is sent to n8n, which calls a translation service, stores the localized versions, and queues a LinkedIn payload.
ContainerisationDocker images built per commit; the image includes the SvelteKit app and the n8n runner.
OrchestrationKubernetes with Kustomize overlays for dev / prod environments. The cluster is the same one I already operate for other side‑projects (see my personal cloud platform) .
CI/CDGitHub Actions + release‑it. A push to main runs lint, unit tests, creates a new semantic version, builds the Docker image and updates the Kustomize kustomization.yaml. Argo CD (or a kubectl apply) then rolls the new release to the cluster.
VersioningWithin the app each article has a version field (draft → review → published). The overall app version is bumped automatically by release‑it during the CI run.
SchedulingA cron‑job inside the cluster calls the n8n endpoint every 48 h, publishing any queued LinkedIn posts.
Image/PDF handlingUploaded files are streamed directly into PostgreSQL, avoiding an external object store and keeping the deployment truly self‑hosted.
Trivia / image scanningA small Go service (outside the scope of the blog) watches the uploaded assets and runs a quick scan for prohibited content – a proof‑of‑concept for future moderation.

3. How Automation Reduces Friction

  1. Write → Translate – After saving a draft, the UI calls /api/translate. n8n fetches the markdown, sends it to a translation API, and writes back the localized copies.
  2. Translate → LinkedIn – The same workflow creates a LinkedIn payload (title, excerpt, image URL) and stores it in the DB.
  3. Cron → Publish – Every two days a Kubernetes CronJob triggers the n8n “post to LinkedIn” workflow, pulling any ready payloads and sending them to LinkedIn’s API.

All steps happen with a single button click in the admin UI; no manual copy‑pasting or external script execution is required.

4. Performance & Reliability

  • SSR speed – Because the majority of content is static markdown, the SvelteKit server returns HTML in < 200 ms for typical pages (no client‑side hydration lag).
  • Zero‑downtime deployments – The CI pipeline builds a new image, updates the Kustomize manifest, and Argo CD (or kubectl rollout) performs a rolling update. My existing GitOps workflow on the same cluster cuts deployment time from hours to minutes.
  • Self‑contained storage – Images and PDFs live in PostgreSQL, eliminating network latency to an external bucket and simplifying backups.

5. Challenges & Solutions

ChallengeSolution
Concurrent edits – Two editors could modify the same article.Added an optimistic‑locking version field; the UI warns the user if the DB version changed since they loaded the draft.
Large media uploads – Storing PDFs in PostgreSQL could bloat the DB.Implemented streaming inserts and set a 5 MB size limit per file; larger assets are rejected with a clear UI message.
Translation latency – External translation APIs can be slow.n8n runs the translation asynchronously; the UI displays a “translation in progress” badge and updates automatically when the job finishes.

6. Current Status & Next Steps

  • The prototype is fully functional on my personal Kubernetes cluster (Docker, K8s, Kustomize).
  • No production‑grade metrics yet, but early testing shows the end‑to‑end publish flow completes in under 30 seconds.
  • Future work: add analytics (page‑view counters), implement image‑optimisation pipelines, and expose a public demo for community feedback.

7. Why This Project Matters to Recruiters & Tech Leads

  • End‑to‑end cloud‑native delivery – From source to running pod, whole stack (Docker → Kustomize → CI/CD) is automated, mirroring enterprise GitOps practices  .
  • Multilingual & workflow automation – Shows ability to integrate SaaS APIs (translation, LinkedIn) via n8n, a skill in high demand for modern content pipelines.
  • Performance‑first design – SSR with SvelteKit delivers fast page loads without a separate static site generator, demonstrating practical front‑end optimisation.
  • Self‑hosting mindset – Keeps everything in‑house (PostgreSQL storage, Kubernetes cluster), aligning with security‑first organisations.