| backend | ||
| dev | ||
| docker | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .envrc.example | ||
| .gitignore | ||
| Caddyfile | ||
| docker-compose.yml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| LICENSE | ||
| main.py | ||
| pyproject.toml | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| uv.lock | ||
Knowledge Hub
A self-hosted content platform built with FastAPI and PostgreSQL — a blog, bookmark manager, writeups collection, and a small community layer, wrapped in a hardened, security-first HTTP stack. It powers a personal technology workshop: a place to publish long-form writing, curate links, and let readers comment.
This repository is a public, portfolio snapshot of the application. It is a real, running codebase, trimmed of deployment-specific infrastructure so it stands on its own.
What it does
- Blog — full CRUD, tags, server-rendered pages with client-side Markdown
rendering (
marked.js+DOMPurifyfor safe HTML). - Bookmarks — categorized, tagged link collection.
- Writeups — long-form technical notes with the same tag model.
- Library — books organized into shelves with per-chapter reading.
- Community — polymorphic comments (on posts, writeups, and chapters), comment upvotes, in-app notifications, and public profile pages. All writes are moderated; admins can remove content.
- Accounts — approval-gated registration, login, and profiles. Optional single-sign-on via any standard OIDC provider (feature-flagged, off by default).
- Feedback — an anonymous contact form.
- Privacy — a proxy layer for an external privacy-scanner service, plus an opt-in, first-party, aggregate-only page-hit counter (no per-user tracking, no third-party analytics; disabled by default).
Architecture
backend/
core/
app.py # FastAPI application + middleware wiring
routes/ # one router module per feature area
analytics.py # first-party aggregate hit counter (opt-in)
db/
models.py # SQLAlchemy models (UUID primary keys throughout)
db.py # engine / session management
migrations/ # Alembic migrations
security/
auth.py # JWT-cookie auth, role checks, CSRF verification
deps.py # FastAPI dependencies
static/ # Bootstrap 5 + vanilla-JS ES-module frontend
utils/ # helpers, constants
dev/ # local dev tooling (TUI runner, dev browser)
tests/ # pytest suite (Python) + Node test for the JS URL guard
Security model
- Auth: JWT stored in an HTTP-only cookie (
access_token). - CSRF: double-submit — a
csrf_tokencookie must match anX-CSRF-Tokenheader on every state-changing request. - Authorization: admin-only writes gated by a
requires_role("admin")dependency. - Rate limiting:
slowapion sensitive endpoints. - Headers: a middleware sets CSP, HSTS,
X-Frame-Options,X-Content-Type-Options,Referrer-Policy, andPermissions-Policy. - Output safety: all user-supplied content is escaped before DOM insertion;
outbound link targets are normalized and validated against open-redirect and
javascript:payloads. - Data model: UUID primary keys everywhere (no enumerable integer IDs).
Tech stack
| Layer | Choice |
|---|---|
| Backend | FastAPI, Starlette, Uvicorn |
| ORM / DB | SQLAlchemy 2, PostgreSQL 17, Alembic migrations |
| Auth | PyJWT, bcrypt, CSRF double-submit |
| Frontend | Bootstrap 5.3, vanilla-JS ES modules, marked.js, DOMPurify (no build step) |
| Rate limit | slowapi |
| Runtime | Docker (non-root container via gosu) |
Running it
The app is containerized. A stranger can bring it up with Docker Compose:
cp .env.example .env # then fill in the blanks (see below)
docker compose up -d --build
This starts three services: the FastAPI app, a PostgreSQL 17 database, and an
optional privacy-scanner sidecar. The app listens on port 6969 inside the
container; put a reverse proxy in front of it (a minimal Caddyfile is included).
Migrations run automatically on container start (alembic upgrade head via the
entrypoint).
Configuration
Copy .env.example and set at minimum:
SECRET_KEY— JWT signing key. Generate withpython -c "import secrets; print(secrets.token_urlsafe(64))".POSTGRES_*— database name, user, and password.
SSO/OIDC is off unless explicitly enabled and configured; the app runs fully with local accounts only.
Tests
pip install -r requirements.txt -r requirements-dev.txt
python -m pytest
Tests run against an in-memory SQLite database — no Docker or Postgres needed.
The frontend URL-safety guard has its own Node test under tests/js/.
License
Released under the GNU Affero General Public License v3.0 (AGPL-3.0-only) —
see LICENSE. AGPL is the network-copyleft choice: anyone who runs a
modified version of this app as a hosted service must offer their users the
corresponding source.
Bundled fonts (Inter, JetBrains Mono) are distributed under the SIL Open Font License; the color theme and favicon are original to the project.
License
AGPL-3.0-only — see LICENSE for the full text.
A commercial license is available for use outside the AGPL-3.0 terms — contact Info@Seglamater.com. (Formal commercial-license terms are being finalized.)
Versions previously published under GPL-3.0 remain available under GPL-3.0.