Most note-taking apps force a choice between simple Markdown editors and heavyweight platforms like Notion or Confluence. Teams that want self-hosted control, granular permissions, and rich formatting typically end up stitching together multiple tools or accepting a bloated all-in-one. Alexandrie targets that gap: a self-hosted knowledge base with an extended Markdown editor, offline support, and OIDC SSO, deployable with one command.
What This Does
Alexandrie is a full-stack knowledge base. The backend/ is a Go (Gin) API with JWT auth, OIDC/SSO, MySQL persistence, and S3-compatible storage. The frontend/ is a Nuxt 4 (Vue 3) app with TypeScript, Pinia, and a custom CodeMirror 6 editor. Features include extended Markdown (KaTeX, containers), Kanban boards, full-text search, 5-level per-document permissions, and PWA/offline support.
The README claims one-command deployment via docker compose up, with a live demo and documentation in docs/. The project is a fork of Smaug6739/Alexandrie (2373 stars), so it inherits a mature feature set.
How It Is Wired
Execution starts in backend/main.go:18 (main), which reaches 69 functions. It calls InitApp (backend/app/app.go:46), which initializes the app and reaches 46 functions. The shortest traced path to an external effect is main -> InitApp -> MinioConnection, which reads a file via os.ReadFile — so a run touches the filesystem within 3 hops of the entry point. The backend also has 13 functions that read/write the database and 2 that make outbound network calls.
The most-connected modules are the repositories and permission service. backend/repositories/node.repository.go is called from 13 files and defines NewNodeRepository, GetAll, GetShared, and loadPermissionsForNodes. backend/permissions/service.go is called from 9 files and defines WithActor, ActorFromContext, and RequireNodeAction. The call graph shows statusFromAccessError and actorFromRequest are each called from 18 places — changing either ripples widely. processBackup -> updateJobStatus is the most frequent edge (18 calls), so backup logic is tightly coupled to job-status tracking.
The frontend is a separate project (595 files) with its own package config. The module graph shows no circular dependencies, but the i18n locale files (frontend/i18n/locales/en/index) have high instability (0.92), meaning they import much more than they export — a change there affects many consumers.
How To Use It
Setup: Clone the repo and use Docker Compose. The README documents:
git clone https://github.com/moses-y/Alexandrie.git
cd Alexandrie
cp .env.example .env
docker compose up -d
Open http://localhost:8200 and create an account.
Configuration: The root .env.example and backend/.env.example define required environment variables. docker-compose.yml orchestrates 4 services (frontend, backend, MySQL, S3-compatible storage). For dev with HMR, the README shows docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build.
Running it: The Makefile and backend/main.go are the entry points. For manual setup, see CONTRIBUTING.md.
Real-World Use
A small team runs Alexandrie internally for project documentation. They use OIDC via Google for SSO, store notes in extended Markdown with KaTeX for math, and organize work in Kanban boards. The PWA lets field staff read and edit notes offline, syncing when back online. Backups export everything as a ZIP via the one-click backup feature.
Code Health & Issues
Static analysis (not opinion) found 21 issues: 3 high, 16 medium, 2 low. The high-severity findings are:
High/Clarity — Duplicated code blocks: 2999 repeated 6-line blocks across 84 files, including backend/controllers/authentication.controller.go, oidc.controller.go, backup.controller.go, and resources.controller.go. Fix: extract shared helpers.
High/Cognitive load — Oversized files: frontend/app/styles/vendors/katex/contrib/mhchem.js (2741 lines) and two siblings. Fix: split by responsibility.
Medium/Cognitive load — Deep nesting in backend/repositories/node.repository.go (indentation depth 6). Fix: early returns and guard clauses.
Medium/Cognitive load — High branching density in frontend/app/helpers/markdown/cards.ts (19 branch points over 54 lines). Fix: decompose decision-heavy logic.
The code-health audit adds a critical finding: golang.org/x/crypto@0.50.0 has CVE-2026-42508 (critical), and the manifest pins the vulnerable version. Also high: frontend/.env is tracked despite being in .gitignore — the file is committed and likely contains live credentials. Third-party GitHub Actions are pinned to mutable tags (@v1, @v3), which is a supply-chain risk.
The Bottom Line
Alexandrie is a feature-rich, self-hosted knowledge base with a solid architecture — the Go backend is cleanly layered, and the frontend is substantial. The critical dependency vulnerability and committed .env file are blockers for production use. Fix those, and this is a credible alternative to hosted note-taking tools for teams that want control over their data.
What the analyser found
Deployment readiness
6/7
✓Container image
✓CI pipeline
✓Lockfile committed
✓Test suite
✓README
✓License
✗No committed secrets
Composition
735 files
Vue164
TypeScript113
Go74
SCSS33
SQL32
JavaScript12
ReactVueDocker
Module dependencies
The 10 most depended-upon modules of 126, from static import analysis. Red outline marks a module in an import cycle.
Ranked by severity × confidence × production reach. Reach is the honest discriminator across a collection that is mostly other people's code: the same finding matters more in something that ships.
critical1
high4
medium7
low1
Upgrade the pinned dependency carrying a critical advisorycritical27 occurrences
golang.org/x/crypto@0.50.0 CVE-2026-42508 (critical) +26 more
The manifest pins the exact version the advisory covers, so this is not a warning about drift: the vulnerable code is what installs, and a critical rating means it is reachable over the network without credentials or user interaction.
Fix: Upgrade to the fixed version named in the advisory, then commit the lockfile.
Untrack the file your own .gitignore says to ignorehigh
frontend/.env
tracked although .gitignore excludes it
The author already decided this file must never be committed, so its presence is an accident nobody noticed, which means the credentials in it are the ones actually in use.
Fix: git rm --cached the path and rotate; the ignore rule is already correct.
Pin third-party GitHub Actions to a commit SHAhigh4 occurrences
A tag can be moved, so the action running with your token and secrets is whatever its owner last pushed; this is how tj-actions/changed-files leaked secrets from thousands of repos.
Fix: Replace each @vN with the 40-character commit SHA, keep # vN as a comment, and let Dependabot bump the SHAs.
Upgrade the pinned dependency carrying a published advisoryhigh11 occurrences
github.com/quic-go/quic-go@0.59.0 CVE-2026-40898 (medium) +1 more; golang.org/x/net@0.52.0 CVE-2026-25680 (medium) +8 more
The pinned version is the one that installs, so a published advisory against it describes this deployment rather than a hypothetical one, and the advisory is also a public description of how to exploit it.
Fix: Upgrade to the fixed version named in the advisory, then commit the lockfile.
Remove the committed .env and rotate what it holdshigh
frontend/.env
frontend/.env
A tracked .env is the most common route for a working key to reach a public clone, and it is the file the app actually loads, so the value is usually live.
Fix: git rm --cached the file, add it to .gitignore, rotate every credential it names, commit a .env.example with empty values.
Declare least-privilege permissions for GITHUB_TOKENmedium
.github/workflows/deploy_to_prod.yml
1 workflow(s) declare no permissions, 1 of them reference secrets
With no declaration the token inherits the repository default, so any injected step can push commits or mint releases from inside your own CI.
Fix: Add permissions: contents: read at the top of the workflow and widen per job only where needed.
Pin the container base image by digestmedium2 occurrences
An untagged or mutable base means today's build and last month's contain different libc and a different CVE set, with no record of which shipped.
Fix: Use image:tag@sha256:<digest> and enable Dependabot's docker ecosystem.
Gate pull requests on a dependency vulnerability scanmedium
.github/workflows
no dependency scan in CI
This is the one gate that would catch a known-vulnerable package before it reaches a build, and no repository in the sample had it.
Fix: Add dependency-review-action on pull_request, or osv-scanner on push and a schedule.
Add a pre-commit secret gatemedium
a secret-shaped file is tracked and no repo-level gate is visible
Without a gate the same class of leak recurs on the next commit, so a leak finding is the symptom and this is the cause.
Fix: Add a pre-commit hook scanning staged content, and enable push protection.
Set persist-credentials: false on checkoutmedium
.github/workflows/deploy_to_prod.yml
checkout keeps the token, then dependencies are installed
The token stays in .git/config for every later step, so a malicious postinstall script reads a pushable credential without one ever being passed to it.
Fix: Add with: persist-credentials: false, and pass an explicit token only to the step that pushes.
Add a non-root USER to the imagemedium
backend/Dockerfile
CMD or ENTRYPOINT with no USER directive
A process running as root in the container is root against every mounted volume, and it turns any container escape or writable-mount mistake from a contained problem into a host one.
Fix: Create an unprivileged user, chown what it needs, and end the Dockerfile with USER.
Expand the test suite; it cannot cover this codebasemedium5 occurrences
5 test files against 363 source files (ratio 0.014)
A reviewer reads "has tests" and assumes a safety net that covers two files out of eighty-five, which is how untested paths ship behind a green badge.
Fix: Add tests for the highest fan-in modules first.
1 further finding(s) are listed in the full report.
Checked deterministically against the repository tree and a bounded set of its files: committed credentials, unpinned actions and base images, missing lockfiles and update bots, workflows that discard failures, published advisories against the declared dependencies, runtime configuration, licensing and notebook reproducibility. No language model is involved in this section.