Skip to content
jshields-caPublic

About

A comprehensive web application for evaluating PDF accessibility and automatically remediating common issues according to WCAG AA and AAA standards.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

36 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Docubil

CI CodeQL License Version Issues Contributors

Docubil brings PDF accessibility to any workspace, community, or use case. It analyzes PDFs against WCAG 2.1 AA/AAA, automatically fixes what can be fixed safely, and clearly flags what still needs a human — so everyone has equal access to data, forms, and PDF-based documents.


Contents


Quick start (Docker)

No clone, no local Node/Python setup — pull and run the published image:

curl -O https://raw.githubusercontent.com/jshields-ca/Docubil/main/docker-compose.release.yml
docker compose -f docker-compose.release.yml pull
docker compose -f docker-compose.release.yml up -d

Then open http://localhost:3000.

Every tagged release (vX.Y.Z) is published as a multi-arch (amd64/arm64) image to GitHub Container Registry. See Releases for version history, or edit the image tag in the compose file to pin a specific version instead of latest.

Want to build from source or contribute code instead? See Development setup below.

Features

  • 🔍 Automated PDF Analysis — real WCAG evaluation via a Python bridge (pikepdf + pdfplumber), not a placeholder checklist
  • ♿ WCAG 2.1 AA & AAA — choose the compliance level per analysis
  • 🔧 Automatic Remediation — fixes what's safe to fix (metadata, tagging, language, form tooltips); honestly flags what needs a human (alt text, reading order, complex tables)
  • 📊 Detailed Reports — HTML, JSON, and CSV export, with real per-issue severity and fix status
  • 🧭 Interactive API Docs — full OpenAPI 3.0 spec browsable at /api/docs
  • 🚀 Modern, Accessible Frontend — React + Vite + Tailwind CSS + Framer Motion, itself tested with jest-axe in CI so the tool practices what it preaches
  • 🔒 Security First — rate limiting, magic-bytes validation, automatic file cleanup, CodeQL + dependency-audit CI gates

Supported Standards

  • WCAG 2.1 AA — standard compliance level required by most accessibility regulations
  • WCAG 2.1 AAA — enhanced accessibility with stricter requirements
  • PDF/UA — PDF Universal Accessibility compatibility

What gets fixed automatically

✅ Automatic fixes

  • Missing document metadata (title, subject, language)
  • Basic document structure and tagging
  • Form field accessibility attributes (tooltips)
  • Document outline/bookmarks

⚠️ Flagged for manual review

  • Alternative text for images (needs human context)
  • Color contrast verification
  • Reading order and complex table structures
  • Context-specific content descriptions

Docubil never silently claims a fix it didn't actually make — see remainingIssuesDetail in the API response.

Development setup

Prerequisites

  • Node.js 24+ and npm (see engines in package.json; the Docker image and CI both run on Node 24)
  • Python 3.11+ (for the PDF analysis/remediation bridge)
  • Git

Setup

git clone https://github.com/jshields-ca/Docubil.git
cd Docubil
npm install
pip install -r requirements.txt
cp .env.example .env   # edit as needed

Run it

Backend:

npm run dev

Frontend, in a second terminal — Vite proxies API calls to the Express server so both run with hot reload:

cd client
npm install
npm run dev

Open the URL Vite prints (typically http://localhost:5173). See client/README.md for frontend-specific details.

Build for production

npm run build

Builds the frontend straight into public/, which Express serves as static files. This runs automatically as part of the Docker image build — you don't need to run it by hand for the Docker path above.

Tests & lint

npm test && npm run lint          # backend
cd client && npm test && npm run lint   # frontend (includes jest-axe accessibility checks)

API

Full interactive documentation (Swagger UI) is served at /api/docs once the server is running, with the raw OpenAPI 3.0 spec at /api/docs.json. Summary of the main endpoints:

Upload and analyze

POST /api/analyze
Content-Type: multipart/form-data

pdf: <file>          # PDF, max 50MB
wcagLevel: "AA"      # or "AAA"

Remediate

POST /api/remediate/:jobId
Content-Type: application/json

{ "autoFix": true }

Download the remediated PDF

GET /api/download/:jobId

Job status

GET /api/status/:jobId

Reports

GET /api/report/:jobId/json
GET /api/report/:jobId/csv

Health check

GET /health

Programmatic example

const formData = new FormData();
formData.append('pdf', pdfFile);
formData.append('wcagLevel', 'AA');

const { jobId } = await fetch('/api/analyze', { method: 'POST', body: formData })
  .then((r) => r.json());

const result = await fetch(`/api/remediate/${jobId}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ autoFix: true }),
}).then((r) => r.json());

Architecture

Docubil/
├── server.js                      # Express server, route wiring
├── src/
│   ├── openapi.js                 # OpenAPI 3.0 spec (served at /api/docs)
│   ├── logger.js                  # pino structured logging
│   ├── db.js                      # file-backed JSON job store
│   ├── services/
│   │   ├── PDFProcessor.js        # metadata/text extraction (pdf-lib + pdf-parse)
│   │   ├── AccessibilityAnalyzer.js  # WCAG analysis orchestration
│   │   ├── PythonBridge.js        # spawns the Python analysis/remediation scripts
│   │   ├── RemediationService.js  # applies safe automatic fixes (pdf-lib + pikepdf)
│   │   └── ReportGenerator.js     # HTML report rendering
│   └── python/
│       ├── analyze_pdf.py         # real WCAG checks via pikepdf + pdfplumber
│       └── remediate_pdf.py       # tagging/metadata/form-tooltip remediation
├── client/                        # Frontend source (React + Vite + Tailwind)
│   └── src/
├── public/                        # Built frontend output (generated, not tracked in git)
├── uploads/ · output/ · reports/  # Temporary storage, auto-cleaned on a schedule
├── package.json                   # Node.js dependencies
└── requirements.txt                # Python dependencies

Analysis and remediation degrade gracefully: if the Python bridge is unavailable, PythonBridge.js returns null rather than throwing, and the pipeline falls back to what pdf-lib/pdf-parse alone can determine.

Configuration

Copy .env.example to .env and adjust as needed — it documents every variable (server port, file size/retention limits, CORS origins, rate limiting, the Python interpreter path, log level). Key defaults:

  • File upload: 50 MB maximum, PDF files only (validated by magic bytes, not just extension)
  • Rate limiting: 100 requests per 15 minutes per IP (configurable)
  • File cleanup: uploaded/output files deleted after 24 hours by a scheduled job
  • CORS: allow-listed origins via ALLOWED_ORIGINS, not wide open by default in production
  • CSP: Helmet-managed Content Security Policy headers

Deployment

Docker (recommended) — see Quick start above for the no-clone path, or build from source for development:

git clone https://github.com/jshields-ca/Docubil.git
cd Docubil
docker compose up -d --build

See RELEASING.md if you're cutting a new release.

Manual Node deployment — if you'd rather not use Docker, run the server directly behind a process manager and reverse proxy:

NODE_ENV=production PORT=80 npm install -g pm2
pm2 start server.js --name docubil

Then configure nginx, Caddy, or similar to proxy requests to the Node process. You are responsible for the Python 3.11+ environment and dependencies in this path — the Docker image handles that for you.

Browser support

Chrome 80+, Firefox 75+, Safari 13+, Edge 80+.

How to contribute

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes, with tests
  4. Run tests and lint (both npm test && npm run lint in the root and in client/)
  5. Commit using Conventional Commits — npx cz will guide you — since PR titles become the changelog entry on merge
  6. Push and open a Pull Request

See CONTRIBUTING.md for the full guide, CODE_OF_CONDUCT.md for community expectations, and PLAN.md for the project roadmap and current phase.

Community & support

License

GNU Affero General Public License v3.0 (AGPL-3.0) — see LICENSE for details.

Docubil is copyleft software: if you run a modified version of Docubil as a network service, you must make your modified source available to its users. See CONTRIBUTING.md for what this means for contributors.


Built with ❤️ for universal accessibility by Jeremy Shields.

About

A comprehensive web application for evaluating PDF accessibility and automatically remediating common issues according to WCAG AA and AAA standards.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages