Skip to content
kazkriskaPublic

About

Plug-and-Play Universal Digital E-Book & Documentation Web Application

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

edoc-pnp

Plug-and-play universal digital e-book & documentation engine.

Point it at any folder of Markdown files and it becomes a searchable, paginated, themeable documentation reader — no config, no frontmatter requirements, no rebuild step for content changes.

License: MIT Node


Table of contents


What it does

Most documentation tools ask you to restructure your content: add frontmatter, maintain a sidebar config, register routes. edoc-pnp asks for nothing. It recursively scans a directory, infers the table of contents from the folder structure and headings, computes continuous e-book page numbers from word density, and builds a full-text index — all at server startup.

Capability Detail
Zero configuration Drop in .md files; the TOC, badges and categories are derived automatically
Continuous pagination Documents get real e-book page ranges (~300 words/page) across the whole corpus
Full-text search FlexSearch index over titles, headings and body text; Ctrl+K palette with keyboard navigation
Mermaid diagrams Fenced ```mermaid blocks render as live diagrams
Syntax highlighting Prism, with bash / json / yaml / python / javascript / typescript / rust bundled
7 themes Obsidian, Midnight OLED, Cyberpunk, Deep Space, Warm Sepia, Aurora Teal, Light Glass
Reader controls 4 font families, 5 reader widths, adjustable font size and line height — persisted to localStorage
Reading progress Live progress bar, per-document outline, prev/next pagination
Frontmatter aware Optional YAML frontmatter (title, phase, category, badge) overrides inferred values

Quick start

Requirements: Node.js 18 or newer (developed on Node 24) and npm.

git clone <your-repo-url> edoc-pnp
cd edoc-pnp
npm install
cp .env.example .env

Put your Markdown somewhere and point DOCS_DIR at it in .env:

DOCS_DIR=./docs
PORT=3000

Then build the frontend and start the server:

npm run build
npm start

Open http://localhost:3000.

Development mode

Two processes, because the API and the Vite dev server run separately:

npm run dev:server   # terminal 1 — Express API on $PORT
npm run dev:vite     # terminal 2 — Vite with HMR on :5173

Visit http://localhost:5173. Vite proxies /api/* to the Express server using the PORT value from your .env, so .env must exist before starting Vite.

npm scripts

Script Purpose
npm run dev:server Start the Express API only (no static serving)
npm run dev:vite Start the Vite dev server with HMR and API proxy
npm run dev Alias for dev:server
npm run build Build the production frontend bundle into ./dist
npm start Serve API and the built ./dist bundle in production mode

Configuration

All configuration is environment variables — see .env.example.

Variable Default Description
DOCS_DIR ./docs Folder to scan for Markdown. Relative paths resolve from the process working directory.
PORT 3000 Port the Express server binds to. Also the proxy target for the Vite dev server.
NODE_ENV — When production, the server also serves the static ./dist build. npm start sets this.

Optional edoc.config.json

Place an edoc.config.json file inside your docs directory to override the title and subtitle that would otherwise be inferred from the docs' root README.md:

{
  "title": "My Product Handbook",
  "subtitle": "Everything you need to operate the platform"
}

Optional frontmatter

Any document may declare frontmatter to override inferred metadata:

---
title: Ticket Model
phase: Phase 1 — Master Specification
badge: PART IV
---

How it works

graph LR
    A[DOCS_DIR] --> B[Recursive scanner]
    B --> C[gray-matter frontmatter parse]
    C --> D[Heading extraction + slugify]
    C --> E[Page calculator ~300 w/page]
    C --> F[FlexSearch index]
    D --> G[JSON REST API]
    E --> G
    F --> G
    G --> H[React reader UI]
Loading

At startup initializeSpecEngine() walks DOCS_DIR, skipping dotfolders, node_modules and dist. Each .md file is parsed for frontmatter and headings, assigned a title (frontmatter → first H1 → filename), a category (frontmatter → formatted folder name), a badge, a word count, a read-time estimate and a continuous page range. Everything is held in memory and exposed over three read-only endpoints.

REST API

Endpoint Description
GET /api/docs/structure Project metadata, total page count, phase groupings, full document index
GET /api/docs/content?path=<rel> Parsed document with headings, page range, and prev/next links
GET /api/search?q=<query> Full-text search results with highlighted excerpts (min. 2 characters)

Full request/response schemas: _docs/03-reference/01-api.md.

Note: the index is built once at startup. Restart the server after adding or editing documents.

Project layout

edoc-pnp/
├── server.js                 # Express API + spec engine (scan, index, paginate)
├── vite.config.js            # Vite config with /api dev proxy
├── index.html                # SPA entry point
├── src/
│   ├── main.jsx              # React root
│   ├── App.jsx               # Layout shell and data fetching
│   ├── index.css             # Theme variables and global styles
│   ├── context/
│   │   └── SettingsContext.jsx   # Theme/typography state + keyboard shortcuts
│   └── components/
│       ├── Header.jsx        # Top bar, search trigger, progress bar
│       ├── LeftSidebar.jsx   # Index and per-document outline tabs
│       ├── IndexPage.jsx     # Landing page with phase-grouped catalogue
│       ├── ReadView.jsx      # Markdown renderer and reading surface
│       ├── CodeBlock.jsx     # Prism highlighting with copy button
│       ├── DiagramBlock.jsx  # Mermaid renderer
│       ├── SearchModal.jsx   # Ctrl+K command palette
│       └── SettingsModal.jsx # Theme, font, width, spacing controls
├── _docs/                    # Documentation for edoc-pnp itself (underscore
│                             #   keeps it out of the default ./docs scan path)
└── tessera-docs/             # Bundled example corpus — illustrative only,
                              #   not a dependency, safe to delete

Deployment

Deployment recipes for Docker, systemd, Nginx, PM2 and PaaS providers live in _docs/04-deployment/. The short version:

npm ci --omit=dev && npm install --include=dev  # build deps needed for vite
npm run build
NODE_ENV=production PORT=3000 DOCS_DIR=/srv/docs node server.js

See the deployment guide for hardening, process supervision and reverse-proxy configuration.

To put a free public demo online, the Render guide deploys the bundled Dockerfile with no code changes.

Documentation

This project's own documentation lives in _docs/. Because it is written in the same zero-config Markdown the engine consumes, you can read it inside the reader itself:

DOCS_DIR=./_docs npm start
Section Contents
Getting started Installation, quickstart, configuration
Architecture Pipeline overview, spec engine, frontend design
Reference REST API, environment variables, keyboard shortcuts, theming
Deployment Production, Docker, reverse proxy, Render
Contributing Development workflow, code style

Note

The folder is deliberately named _docs/ and not docs/. Since ./docs is the application's default DOCS_DIR, a folder by that name would be picked up and rendered automatically — the app would publish its own documentation instead of yours. The leading underscore keeps it out of that default path.

About the bundled tessera-docs/ folder

The repository ships a tessera-docs/ directory containing a 29-document specification. It exists purely as example content — a corpus large enough to demonstrate multi-level categories, continuous pagination, grouping and full-text search against something realistic.

To be explicit:

  • Tessera is not part of this project. It is not a dependency, it is not imported by any source file, and no code in edoc-pnp references it.

  • Nothing breaks if you remove it. Delete the folder and point DOCS_DIR at your own content:

    rm -rf tessera-docs

    Remember to update DOCS_DIR in your .env if it still points there, and the volume mount in docker-compose.yml if you use Compose.

The sample content is sourced from the Tessera project — a filesystem-native resource automation framework — and is included for illustration only: https://github.com/kazkriska/tessera

Contributing

Contributions are welcome. Please read CONTRIBUTING.md and the Code of Conduct before opening a pull request.

License

Released under the MIT License.

About

Plug-and-Play Universal Digital E-Book & Documentation Web Application

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages