diff --git a/.gitignore b/.gitignore index 57fcae0..b454b24 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ OpenReader-Test-Cert.cer Thumbs.db .vscode/ .idea/ +.wrangler diff --git a/AGENTS.md b/AGENTS.md index f8edd8a..7bd29ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,7 @@ This repository is a local-first desktop PDF utility. Keep maintenance changes b - Tag releases with `vMAJOR.MINOR.PATCH`. - Packaged builds must inject the tag version into `main.py` via `scripts/inject_version.py`. - Source builds may remain `-dev`. -- Update `RELEASE.md` if release mechanics change. +- Update `docs/RELEASE.md` if release mechanics change. ## Build and Test diff --git a/CLAUDE.md b/CLAUDE.md index 9cf37b9..f42b840 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,7 +62,7 @@ python -m pytest tests/ -v - Tag releases with `vMAJOR.MINOR.PATCH`. - Version injected from tag via `scripts/inject_version.py`. - Source builds remain `-dev`. -- Update `RELEASE.md` if release mechanics change. +- Update `docs/RELEASE.md` if release mechanics change. ## Workflow @@ -75,8 +75,8 @@ python -m pytest tests/ -v ## Documentation Rules - README should describe shipped behavior only. -- ARCHITECTURE.md is the canonical architecture reference. -- VERSIONING.md documents the versioning scheme. +- docs/Architecture.md is the canonical architecture reference. +- docs/VERSIONING.md documents the versioning scheme. - Keep CHANGELOG.md updated per Keep a Changelog format. - Keep Mac caveats visible for experimental platform status. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7846871..b445e99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,45 +2,6 @@ Thanks for your interest in improving OpenReader. -This project is free software. Contributions are accepted under the same [GNU AGPLv3](LICENSE) used by the project. +This project is free software under the [GNU AGPLv3](LICENSE). -## Local Setup - -```powershell -python -m venv .venv -.\.venv\Scripts\Activate.ps1 -python -m pip install -r requirements.txt -python main.py -``` - -## Build on Windows - -```powershell -.\scripts\build_windows.ps1 -``` - -The executable is created at: - -```text -dist\OpenReader.exe -``` - -## Build on macOS - -```bash -chmod +x scripts/build_macos.sh -./scripts/build_macos.sh -``` - -The app bundle is created at: - -```text -dist/OpenReader.app -``` - -## Pull Requests - -- Keep the UI simple and native-looking. -- Avoid network services; PDFs should stay local. -- Test opening PDFs directly through command-line arguments. -- Test search, text selection, merge, split, and compress behavior when changing document logic. +For the full contributor guide — setup, workflow, PR process, and design playbooks — see [docs/Contributing.md](docs/Contributing.md). diff --git a/README.md b/README.md index b204dd4..48a63b2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- OpenReader + OpenReader

@@ -10,20 +10,24 @@ Private PDF tools for your computer. No uploads. No accounts. No cloud.

+
+

- OpenReader reading a PDF + OpenReader reading a PDF

Built for Windows 10 & 11 · 100% Offline · Open Source · AI-ready

+
+

⭐ Get OpenReader

- Microsoft Store + Microsoft Store (Recommended)   Portable Release   @@ -34,6 +38,18 @@ --- +## Gallery + +| Dark Mode | PDF Tools | +|---|---| +| ![Dark Mode](assets/screenshots/dark-mode.png) | ![PDF Tools: merge, split, compress](assets/screenshots/merge-split.png) | + +| About & Keyboard Shortcuts | Sample Document | +|---|---| +| ![About dialog with keyboard shortcuts](assets/screenshots/about.png) | ![Sample PDF loaded in OpenReader](assets/screenshots/sample-pdf.png) | + +--- + ## Why OpenReader | | | @@ -49,24 +65,12 @@ | | | |---|---| -| **📖 Read** — Open PDFs, one-page or continuous scroll, fit-width zoom, page jump. | **📝 Annotate** — Highlight, underline, strikethrough, and sticky notes. Saved as native PDF annotations. | -| **🔍 Search** — Full-document keyword search with match count and navigation. | **📚 Library search** — Index entire folders with SQLite FTS5 for cross-document BM25-ranked search. | -| **🧠 Semantic search** — TF-IDF cosine similarity — meaning-based matching, no external ML. | **📊 Compare** — Side-by-side diff with color-coded changes and structured summary. | -| **📑 Multi-tab** — Open several documents in one window with movable tabs. | **🌙 Dark mode** — System-aware theme with Auto/Light/Dark toggle. | -| **🔧 PDF tools** — Merge, split, extract page ranges, compress. | **👁️ OCR fallback** — Automatic OCR on scanned/image-based pages when Tesseract is available. | -| **💾 Session restore** — Remembers open documents and page positions across restarts. | **🤖 AI agent integration** — Built-in MCP server with 14 tools for automated PDF workflows. | - ---- - -## Screenshots - -| Dark Mode | PDF Tools | -|---|---| -| ![Dark Mode](assets/screenshots/dark-mode.png) | ![PDF Tools: merge, split, compress](assets/screenshots/merge-split.png) | - -| About & Keyboard Shortcuts | Sample Document | -|---|---| -| ![About dialog with keyboard shortcuts](assets/screenshots/about.png) | ![Sample PDF loaded in OpenReader](assets/screenshots/sample-pdf.png) | +| **Read** — Open PDFs, one-page or continuous scroll, fit-width zoom, page jump. | **Annotate** — Highlight, underline, strikethrough, and sticky notes. Saved as native PDF annotations. | +| **Search** — Full-document keyword search with match count and navigation. | **Library search** — Index entire folders with SQLite FTS5 for cross-document BM25-ranked search. | +| **Semantic search** — TF-IDF cosine similarity — meaning-based matching, no external ML. | **Compare** — Side-by-side diff with color-coded changes and structured summary. | +| **Multi-tab** — Open several documents in one window with movable tabs. | **Dark mode** — System-aware theme with Auto/Light/Dark toggle. | +| **PDF tools** — Merge, split, extract page ranges, compress. | **OCR fallback** — Automatic OCR on scanned/image-based pages when Tesseract is available. | +| **Session restore** — Remembers open documents and page positions across restarts. | **AI agent integration** — Built-in MCP server with 14 tools for automated PDF workflows. | --- @@ -94,7 +98,16 @@ The focus is on reading and working with documents, not fighting the interface. ## Built With -🐍 Python   ·   🪟 Qt 6   ·   📄 MuPDF   ·   🔍 SQLite   ·   👁️ Tesseract   ·   🤖 MCP   ·   📦 PyInstaller   ·   🏪 MSIX +

+ Python     + Qt 6     + MuPDF     + SQLite     + Tesseract     + MCP     + PyInstaller     + MSIX +

--- @@ -132,4 +145,22 @@ Copyright © 2026 Sparsh Sam. --- +## Part of the Open Collection + +Open\* is a family of privacy-first, open-source applications. Every app is local-first, respects your data, and is built with care. + +| | App | Description | Links | +|---|---|---|---| +| | **OpenReader** | Private PDF tools for your computer. | [Repo](https://github.com/sparshsam/openreader) · [Web](https://reader.kovina.org) | +| | **OpenLedger** | Local-first personal finance ledger. No noise. | [Repo](https://github.com/sparshsam/openledger) · [Web](https://ledger.kovina.org) | +| | **OpenProof** | Privacy-first proof-of-existence for files, onchain. | [Repo](https://github.com/sparshsam/openproof) · [Web](https://proof.kovina.org) | +| | **OpenSend** | Free, ad-free, open-source file sharing between devices. | [Repo](https://github.com/sparshsam/opensend) | +| | **OpenSnap** | Minimal always-on-top screenshot widget for Windows. | [Repo](https://github.com/sparshsam/opensnap) | +| | **OpenJournal** | Privacy-first local activity journal for Windows. | [Repo](https://github.com/sparshsam/openjournal) | +| | **OpenPalette** | Local-first color studio — harmonies, tokens, accessibility. | [Repo](https://github.com/sparshsam/openpalette) | +| | **OpenScrabble** | Multiplayer Scrabble with chat and shared boards. | [Repo](https://github.com/sparshsam/openscrabble) | +| | **OpenSprout** | Privacy-minded plant care dashboard and watering logs. | [Repo](https://github.com/sparshsam/opensprout) | + +--- + *Last updated: June 2026* diff --git a/assets/AppIcon.iconset/icon_128x128.png b/assets/branding/AppIcon.iconset/icon_128x128.png similarity index 100% rename from assets/AppIcon.iconset/icon_128x128.png rename to assets/branding/AppIcon.iconset/icon_128x128.png diff --git a/assets/AppIcon.iconset/icon_128x128@2x.png b/assets/branding/AppIcon.iconset/icon_128x128@2x.png similarity index 100% rename from assets/AppIcon.iconset/icon_128x128@2x.png rename to assets/branding/AppIcon.iconset/icon_128x128@2x.png diff --git a/assets/AppIcon.iconset/icon_16x16.png b/assets/branding/AppIcon.iconset/icon_16x16.png similarity index 100% rename from assets/AppIcon.iconset/icon_16x16.png rename to assets/branding/AppIcon.iconset/icon_16x16.png diff --git a/assets/AppIcon.iconset/icon_16x16@2x.png b/assets/branding/AppIcon.iconset/icon_16x16@2x.png similarity index 100% rename from assets/AppIcon.iconset/icon_16x16@2x.png rename to assets/branding/AppIcon.iconset/icon_16x16@2x.png diff --git a/assets/AppIcon.iconset/icon_256x256.png b/assets/branding/AppIcon.iconset/icon_256x256.png similarity index 100% rename from assets/AppIcon.iconset/icon_256x256.png rename to assets/branding/AppIcon.iconset/icon_256x256.png diff --git a/assets/AppIcon.iconset/icon_256x256@2x.png b/assets/branding/AppIcon.iconset/icon_256x256@2x.png similarity index 100% rename from assets/AppIcon.iconset/icon_256x256@2x.png rename to assets/branding/AppIcon.iconset/icon_256x256@2x.png diff --git a/assets/AppIcon.iconset/icon_32x32.png b/assets/branding/AppIcon.iconset/icon_32x32.png similarity index 100% rename from assets/AppIcon.iconset/icon_32x32.png rename to assets/branding/AppIcon.iconset/icon_32x32.png diff --git a/assets/AppIcon.iconset/icon_32x32@2x.png b/assets/branding/AppIcon.iconset/icon_32x32@2x.png similarity index 100% rename from assets/AppIcon.iconset/icon_32x32@2x.png rename to assets/branding/AppIcon.iconset/icon_32x32@2x.png diff --git a/assets/AppIcon.iconset/icon_512x512.png b/assets/branding/AppIcon.iconset/icon_512x512.png similarity index 100% rename from assets/AppIcon.iconset/icon_512x512.png rename to assets/branding/AppIcon.iconset/icon_512x512.png diff --git a/assets/AppIcon.iconset/icon_512x512@2x.png b/assets/branding/AppIcon.iconset/icon_512x512@2x.png similarity index 100% rename from assets/AppIcon.iconset/icon_512x512@2x.png rename to assets/branding/AppIcon.iconset/icon_512x512@2x.png diff --git a/assets/app-icon-source.png b/assets/branding/app-icon-source.png similarity index 100% rename from assets/app-icon-source.png rename to assets/branding/app-icon-source.png diff --git a/assets/icon-150x150.png b/assets/branding/icon-150x150.png similarity index 100% rename from assets/icon-150x150.png rename to assets/branding/icon-150x150.png diff --git a/assets/icon-310x150.png b/assets/branding/icon-310x150.png similarity index 100% rename from assets/icon-310x150.png rename to assets/branding/icon-310x150.png diff --git a/assets/icon-44x44.png b/assets/branding/icon-44x44.png similarity index 100% rename from assets/icon-44x44.png rename to assets/branding/icon-44x44.png diff --git a/assets/icon-620x300.png b/assets/branding/icon-620x300.png similarity index 100% rename from assets/icon-620x300.png rename to assets/branding/icon-620x300.png diff --git a/assets/icon-71x71.png b/assets/branding/icon-71x71.png similarity index 100% rename from assets/icon-71x71.png rename to assets/branding/icon-71x71.png diff --git a/assets/pdfreader_by_sparsh.ico b/assets/branding/pdfreader_by_sparsh.ico similarity index 100% rename from assets/pdfreader_by_sparsh.ico rename to assets/branding/pdfreader_by_sparsh.ico diff --git a/assets/screenshots/reader-main.png b/assets/hero/reader-main.png similarity index 100% rename from assets/screenshots/reader-main.png rename to assets/hero/reader-main.png diff --git a/assets/icons/feature-ai.svg b/assets/icons/feature-ai.svg new file mode 100644 index 0000000..d3b3ac4 --- /dev/null +++ b/assets/icons/feature-ai.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-annotate.svg b/assets/icons/feature-annotate.svg new file mode 100644 index 0000000..c25479f --- /dev/null +++ b/assets/icons/feature-annotate.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-compare.svg b/assets/icons/feature-compare.svg new file mode 100644 index 0000000..116a0b5 --- /dev/null +++ b/assets/icons/feature-compare.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-darkmode.svg b/assets/icons/feature-darkmode.svg new file mode 100644 index 0000000..741c274 --- /dev/null +++ b/assets/icons/feature-darkmode.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-ocr.svg b/assets/icons/feature-ocr.svg new file mode 100644 index 0000000..4e74b06 --- /dev/null +++ b/assets/icons/feature-ocr.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-offline.svg b/assets/icons/feature-offline.svg new file mode 100644 index 0000000..5a6e84a --- /dev/null +++ b/assets/icons/feature-offline.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-platform.svg b/assets/icons/feature-platform.svg new file mode 100644 index 0000000..f7ea193 --- /dev/null +++ b/assets/icons/feature-platform.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-read.svg b/assets/icons/feature-read.svg new file mode 100644 index 0000000..3774c33 --- /dev/null +++ b/assets/icons/feature-read.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-search.svg b/assets/icons/feature-search.svg new file mode 100644 index 0000000..f344a39 --- /dev/null +++ b/assets/icons/feature-search.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-session.svg b/assets/icons/feature-session.svg new file mode 100644 index 0000000..769b201 --- /dev/null +++ b/assets/icons/feature-session.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-tabs.svg b/assets/icons/feature-tabs.svg new file mode 100644 index 0000000..c3058a8 --- /dev/null +++ b/assets/icons/feature-tabs.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/feature-tools.svg b/assets/icons/feature-tools.svg new file mode 100644 index 0000000..8f830f8 --- /dev/null +++ b/assets/icons/feature-tools.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/openreader.svg b/assets/icons/openreader.svg new file mode 100755 index 0000000..e3cb704 --- /dev/null +++ b/assets/icons/openreader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/tab_close.svg b/assets/icons/tab_close.svg similarity index 100% rename from assets/tab_close.svg rename to assets/icons/tab_close.svg diff --git a/assets/icons/tech-mcp.svg b/assets/icons/tech-mcp.svg new file mode 100644 index 0000000..7a33d56 --- /dev/null +++ b/assets/icons/tech-mcp.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-msix.svg b/assets/icons/tech-msix.svg new file mode 100644 index 0000000..02eab70 --- /dev/null +++ b/assets/icons/tech-msix.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-mupdf.svg b/assets/icons/tech-mupdf.svg new file mode 100644 index 0000000..b86c657 --- /dev/null +++ b/assets/icons/tech-mupdf.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-pyinstaller.svg b/assets/icons/tech-pyinstaller.svg new file mode 100644 index 0000000..1501400 --- /dev/null +++ b/assets/icons/tech-pyinstaller.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-python.svg b/assets/icons/tech-python.svg new file mode 100644 index 0000000..c57e672 --- /dev/null +++ b/assets/icons/tech-python.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-qt.svg b/assets/icons/tech-qt.svg new file mode 100644 index 0000000..cf8e0f4 --- /dev/null +++ b/assets/icons/tech-qt.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-sqlite.svg b/assets/icons/tech-sqlite.svg new file mode 100644 index 0000000..d597fe4 --- /dev/null +++ b/assets/icons/tech-sqlite.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/tech-tesseract.svg b/assets/icons/tech-tesseract.svg new file mode 100644 index 0000000..1d854a1 --- /dev/null +++ b/assets/icons/tech-tesseract.svg @@ -0,0 +1 @@ + diff --git a/docs/Architecture.md b/docs/Architecture.md new file mode 100644 index 0000000..f362aba --- /dev/null +++ b/docs/Architecture.md @@ -0,0 +1,64 @@ +# Architecture + +> System architecture and design decisions for OpenReader. + +For the full design and product architecture playbook, see [Design Playbook](playbooks/DESIGN_PLAYBOOK.md) and [Product Architecture Playbook](playbooks/PRODUCT_ARCHITECTURE_PLAYBOOK.md). + +--- + +## Overview + +OpenReader is a local-first desktop PDF utility built with Python and PySide6 (Qt 6). Every operation — reading, searching, annotating, comparing, merging, splitting — runs on the user's machine. No cloud, no accounts, no telemetry. + +``` +┌─────────────────────────────────────────┐ +│ main.py │ +│ PySide6 (Qt 6) UI │ +│ ┌─────────────────────────────────┐ │ +│ │ pdfreader_lib/ │ │ +│ │ ├── search_index.py │ │ +│ │ ├── comparison.py │ │ +│ │ └── mcp_server.py │ │ +│ └─────────────────────────────────┘ │ +│ ┌─────────────────────────────────┐ │ +│ │ PyMuPDF (MuPDF) — PDF engine │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────┘ + │ + ▼ + Local filesystem only + (PDFs, SQLite indexes, OCR cache) +``` + +## Core Components + +| Component | Module | Purpose | +|-----------|--------|---------| +| GUI | `main.py` | PySide6 application window, menus, controls bar, PDF viewer | +| PDF Engine | — | PyMuPDF (MuPDF bindings) for rendering, text extraction, annotation | +| Search | `pdfreader_lib/search_index.py` | SQLite FTS5 keyword index + TF-IDF semantic search | +| Comparison | `pdfreader_lib/comparison.py` | Page-by-page text diff with color-coded output | +| MCP Server | `pdfreader_lib/mcp_server.py` | Model Context Protocol server for AI agent integration (14 tools) | + +## Key Architecture Decisions + +1. **Local-first.** No network calls beyond the optional GitHub release update check. PDFs are never uploaded or transmitted. +2. **Single-process.** The GUI and all operations run in a single process. Heavy operations (search, compare, compress) show progress feedback. +3. **SQLite for indexing.** Library search uses SQLite FTS5 (keyword) and scikit-learn TF-IDF (semantic). Both are local, zero-configuration, and fast. +4. **MCP server as library.** The MCP server is built into `pdfreader_lib/` and can be used standalone or alongside the GUI. It shares the same underlying search and comparison modules. +5. **No self-update.** The app detects updates via GitHub API but never downloads or runs installers. MSIX updates are handled by Windows App Installer. + +## Security Model + +- PDF validation before parsing (header check, size limits) +- Render pixel caps to prevent OOM from malformed PDFs +- Bandit + pip-audit in CI +- No secrets or credentials stored (no accounts) + +## Distribution + +- **Primary:** Microsoft Store (automatic updates via Store) +- **Secondary:** GitHub Releases (MSIX for sideloading) +- **Legacy:** Setup.exe and portable ZIP + +See [Deployment](Deployment.md) for CI/CD and release details. diff --git a/docs/Contributing.md b/docs/Contributing.md new file mode 100644 index 0000000..5507ca9 --- /dev/null +++ b/docs/Contributing.md @@ -0,0 +1,52 @@ +# Contributing + +> Guide for contributors to OpenReader. + +--- + +## Before You Start + +Please read these documents before opening issues or pull requests: + +- [Code of Conduct](../CODE_OF_CONDUCT.md) +- [Security Policy](../SECURITY.md) + +## Areas We Welcome Contributions + +- Bug fixes and reliability improvements +- UI polish and accessibility +- PDF parsing edge cases and format support +- MCP server tool improvements +- Documentation and translation +- Platform compatibility (especially macOS) + +## Areas We Don't Accept Contributions + +- Cloud features, accounts, sync, or telemetry +- Plugin systems or extension APIs +- AI features that upload documents to third parties +- Breaking the local-first or privacy-by-design model + +## Pull Request Process + +1. Branch from `main`. Use prefixes: `fix/`, `feat/`, `docs/`, `refactor/`. +2. One logical change per PR. +3. Run lint and tests before creating the PR. +4. All CI checks must pass before merge. +5. No direct pushes to `main` — PRs only. + +## Development Setup + +See [Development](Development.md) for build and run instructions. + +## Architecture + +See [Architecture](Architecture.md) for the system design overview. + +## Design Playbooks + +Design and architectural decisions should reference: + +- [Product Architecture Playbook](playbooks/PRODUCT_ARCHITECTURE_PLAYBOOK.md) +- [Design Playbook](playbooks/DESIGN_PLAYBOOK.md) +- [Kovina Repository Standard](playbooks/KOVINA_REPOSITORY_STANDARD.md) diff --git a/docs/Deployment.md b/docs/Deployment.md new file mode 100644 index 0000000..0ee85ca --- /dev/null +++ b/docs/Deployment.md @@ -0,0 +1,90 @@ +# Deployment + +> CI/CD, release workflow, and distribution channels for OpenReader. + +--- + +## Distribution Channels + +| Channel | Status | Updates | +|---------|--------|---------| +| **Microsoft Store** | Live (`9MXDVW2645LL`) | Automatic through Store | +| **GitHub Releases** (MSIX) | Active | Manual (Help → Check for Updates) | +| **GitHub Releases** (Setup.exe) | Legacy | Manual recovery only | +| **GitHub Releases** (Portable ZIP) | Active | Manual download | +| **Winget** | Future | `SparshSam.OpenReader` | + +--- + +## Release Workflow + +Tagging triggers the [release workflow](.github/workflows/release.yml): + +```bash +git tag vMAJOR.MINOR.PATCH +git push origin vMAJOR.MINOR.PATCH +``` + +The CI pipeline: + +1. Runs full test suite and security audit +2. Builds Python package with PyInstaller (`--onedir` mode) +3. Creates MSIX package with Windows App Installer support +4. Builds Inno Setup installer +5. Packages macOS builds (experimental) +6. Uploads all assets to a GitHub Release +7. Injects version from tag via `scripts/inject_version.py` + +### Release Assets + +| Asset | Format | Platform | +|-------|--------|----------| +| `OpenReader.msix` | MSIX | Windows 10/11 | +| `OpenReader-Setup.exe` | Inno Setup | Windows (legacy) | +| `OpenReader-Windows.zip` | Portable ZIP | Windows | +| `OpenReader-macOS-Apple-Silicon.zip` | DMG/ZIP | macOS | +| `OpenReader-macOS-Intel.zip` | DMG/ZIP | macOS | + +### MSIX Version Mapping + +| Tag Format | MSIX Version | +|-----------|--------------| +| `v1.2.3` | `1.2.3.0` | +| `v1.2.3-beta.1` | `1.2.3.0` | +| `v1.0.0-rc.1` | `1.0.0.0` | + +--- + +## CI Pipelines + +| Workflow | Trigger | Purpose | +|----------|---------|---------| +| `ci.yml` | PR + push to `main` | Tests, linting, security scan | +| `build-windows.yml` | PR + push to `main` | Windows build validation | +| `build-macos.yml` | PR + push to `main` | macOS build validation (experimental) | +| `release.yml` | Tag push | Full release with all assets | +| `security.yml` | Scheduled + push | Bandit, pip-audit, Dependabot | +| `deploy-site.yml` | Push touching `site/` | Deploys landing page to Cloudflare Pages | + +### Required Checks + +Before merging to `main`: + +- All CI workflows must pass +- `Build Windows Release Asset` status check is enforced +- PR approval required (branch protection) + +--- + +## Build Locally + +See [Development](Development.md) for local build instructions. + +## Platform Support + +| Platform | Support Level | Notes | +|----------|--------------|-------| +| Windows 10/11 | Full | Primary target, MSIX + installer | +| macOS Apple Silicon | Experimental | Source build, no signed package | +| macOS Intel | Experimental | Source build, no signed package | +| Linux | Unsupported | Not planned | diff --git a/RELEASE.md b/docs/RELEASE.md similarity index 100% rename from RELEASE.md rename to docs/RELEASE.md diff --git a/SUPPORT.md b/docs/SUPPORT.md similarity index 100% rename from SUPPORT.md rename to docs/SUPPORT.md diff --git a/docs/Testing.md b/docs/Testing.md new file mode 100644 index 0000000..92aac94 --- /dev/null +++ b/docs/Testing.md @@ -0,0 +1,56 @@ +# Testing + +> Test suite, coverage areas, and quality gates for OpenReader. + +--- + +## Running Tests + +```bash +# Full test suite +python -m pytest tests/ -v + +# Specific test file +python -m pytest tests/test_mcp_server.py -v + +# Quick syntax check +python -m py_compile main.py tools/create_icon.py scripts/inject_version.py +``` + +--- + +## Test Coverage + +| Area | File | Tests | +|------|------|-------| +| Reliability & safety | `tests/test_reliability.py` | 20 tests — version format, asset naming, safety limits, shortcut consistency | +| Security | `tests/test_security.py` | 12 tests — file validation, path handling, temp file security, subprocess safety | +| MCP Server | `tests/test_mcp_server.py` | 43 tests — tool registration, validation, output shape, error handling | +| Updater | `tests/test_updater.py` | 31 tests (headless-skipped) — version parsing, asset selection, metadata | +| Asset flow | `tools/test_updater_asset_flow.py` | 16 checks — release asset consistency | + +--- + +## Quality Gates + +Every push and PR must pass: + +| Gate | Check | +|------|-------| +| **Compile** | `python -m py_compile` on all entry points | +| **Tests** | Full pytest suite | +| **Security** | Bandit (production code, 0 issues) | +| **Dependencies** | pip-audit (0 known vulnerabilities) | +| **Build** | Windows MSIX build validation (CI) | + +These are enforced in CI via `.github/workflows/ci.yml` and `.github/workflows/security.yml`. + +--- + +## Security Audit + +The security workflow runs Bandit and pip-audit on every push: + +- Bandit configured in `.bandit` (excludes test directories) +- pip-audit checks all pinned dependencies +- Both must pass before merging diff --git a/VERSIONING.md b/docs/VERSIONING.md similarity index 100% rename from VERSIONING.md rename to docs/VERSIONING.md diff --git a/ARCHITECTURE.md b/docs/archive/ARCHITECTURE.md similarity index 100% rename from ARCHITECTURE.md rename to docs/archive/ARCHITECTURE.md diff --git a/ROADMAP.md b/docs/archive/ROADMAP.md similarity index 100% rename from ROADMAP.md rename to docs/archive/ROADMAP.md diff --git a/docs/playbooks/KOVINA_REPOSITORY_STANDARD.md b/docs/playbooks/KOVINA_REPOSITORY_STANDARD.md new file mode 100644 index 0000000..b7b4f7d --- /dev/null +++ b/docs/playbooks/KOVINA_REPOSITORY_STANDARD.md @@ -0,0 +1,184 @@ +# Kovina Repository Standard + +> A specification for every Kovina repository. Treats GitHub as a software showroom, not a development wiki. + +--- + +## Philosophy + +Every Kovina repository should feel like a premium product landing page. The primary audience is: + +- **End users** — people discovering the software, deciding whether to download +- **Recruiters** — evaluating the quality and polish of the work +- **Designers** — examining visual and interaction patterns +- **Discoverers** — visitors who landed from search, social, or word of mouth + +The repository should encourage **downloading or using the product**, not cloning the repository. + +--- + +## Repository Structure + +``` +. +├── assets/ +│ ├── hero/ # Large hero screenshot(s) — product in action +│ ├── screenshots/ # Feature, workflow, and UI screenshots +│ ├── gallery/ # Curated screenshot gallery (larger, fewer images) +│ ├── icons/ # SVG icons for features, tech, branding +│ └── branding/ # App icon (various sizes), logos, store assets +├── docs/ +│ ├── Architecture.md # System architecture and design decisions +│ ├── Development.md # Build, run, and development setup +│ ├── Deployment.md # Release workflow, CI/CD, distribution +│ ├── Testing.md # Test suite, coverage, quality gates +│ ├── Contributing.md # Contributor guide, code of conduct +│ └── playbooks/ # Product, design, and architecture playbooks +├── .github/ # CI workflows, issue templates, Dependabot +├── CHANGELOG.md # Keep a Changelog format +├── CONTRIBUTING.md # GitHub-discovered contributor guide (root redirect) +├── LICENSE # AGPLv3 or permissive +├── SECURITY.md # Security policy (GitHub-discovered) +└── README.md # Product showcase (see section order below) +``` + +### Root file cleanup + +Only these files live at root: + +| File | Purpose | +|------|---------| +| `README.md` | Product showcase landing page | +| `CHANGELOG.md` | Release history | +| `LICENSE` | Software license | +| `CONTRIBUTING.md` | GitHub-discovered contributor guide (keep minimal, point to `docs/`) | +| `SECURITY.md` | GitHub-discovered security policy | +| `CODE_OF_CONDUCT.md` | GitHub-discovered code of conduct | +| `.env.example` | Environment template (if applicable) | +| `.gitignore` | Standard exclusions | + +Everything else goes into `docs/` or `assets/`. + +--- + +## README Section Order + +Every Kovina README follows this exact 11-section order: + +1. **Hero** — Logo, app name, one-line value proposition, large hero screenshot +2. **Primary Call-to-Action** — Download/install buttons (Store first, then Release, then Source) +3. **Gallery** — Large screenshots of the product in use (dark/light, desktop/mobile) +4. **Why This App** — Short, user-focused value propositions, no marketing fluff +5. **Features** — Clean two-column grid with Kovina SVG icons, short descriptions +6. **Designed For** — Typical users and use cases +7. **Design Philosophy** — Short quote + one concise paragraph on design approach +8. **Built With** — Technology icons/logos, clean and scannable +9. **Version Journey** — Timeline of important releases, link to changelog +10. **License** +11. **Part of the Open Collection** — All Open* apps with icons, descriptions, and links + +--- + +## README Rules + +- **Optimize for the first 30 seconds.** A visitor should understand what the product is, why it's useful, what it looks like, and where to download it within 30 seconds. +- **Large typography.** Headings should be prominent. +- **Large screenshots.** Show the product in action at readable sizes (min 720px wide). +- **Minimal text.** Prefer short phrases over paragraphs. +- **Strong visual hierarchy.** Section headings, spacing, and layout guide the eye. +- **Whitespace over density.** Let the content breathe. +- **No developer documentation.** Everything build/install/test/contribute related goes in `docs/`. +- **Primary CTA is always download/use.** The Microsoft Store, Google Play, or Release asset is the first action. + +### Badge style + +CTA badges use `style=for-the-badge` (large, prominent). Secondary badges (version, license, platform) use `style=flat-square` (subtle, informational). + +--- + +## Open Collection Section + +The final section of every README displays all Open\* applications with: + +- App icon (32px, from `assets/icons/` or external URL) +- App name (bold) +- One-line description +- Repository link +- Website link (where available) + +Order alphabetically by name. Use a table or list format. + +```markdown +## Part of the Open Collection + +Open\* is a family of privacy-first, open-source applications. +Every app is local-first, respects your data, and is built with care. + +| | App | Description | Links | +|---|---|---|---| +| ![icon](assets/icons/openreader.svg) | **OpenReader** | Private PDF tools for your computer | [Repo](…) · [Web](…) | +| … | … | … | … | +``` + +--- + +## Asset Organization + +### `assets/hero/` +- One or two hero images showing the product in its primary use case +- 880px+ wide, landscape orientation +- Used only in the Hero section + +### `assets/screenshots/` +- Feature screenshots, workflow steps, UI components +- 600-880px wide +- Referenced throughout the README + +### `assets/gallery/` +- Curated, large gallery images +- Fewer images, higher quality +- Used in the Gallery section + +### `assets/icons/` +- SVG icons for features, technologies, and branding +- Kovina-style: 48×48 viewBox, 1.5px stroke, `stroke="currentColor"` or accent color +- Each icon is a standalone `.svg` file + +### `assets/branding/` +- App icon in all required sizes (`.ico`, `.icns`, `.iconset/`, PNG) +- Store submission images (44×44, 71×71, 150×150, 310×150, 620×300) +- Logo SVG/PNG +- Store badges and marketing assets + +--- + +## Kovina SVG Icon Guidelines + +Icons follow a consistent visual language: + +- **ViewBox:** `0 0 24 24` +- **Stroke width:** `1.5` +- **Stroke style:** `stroke-linecap="round" stroke-linejoin="round"` +- **Fill:** `none` +- **Color:** `currentColor` or brand accent (default: `#ff255F`) +- **Size:** 48×48 display, 52×52 for feature cards + +Store icons in `assets/icons/` as individual `.svg` files prefixed by their feature area. + +--- + +## Quality Checklist + +Before finalising any repository: + +- [ ] README reads like a software landing page, not a developer README +- [ ] Primary CTA is downloading or using the product +- [ ] Product, value, and next action are clear within 30 seconds +- [ ] Screenshots are high quality, current, and render correctly on GitHub +- [ ] All download links (Store, Release, website) work +- [ ] Open Collection section is accurate and up to date +- [ ] Developer documentation is moved to `docs/` and not in root +- [ ] Repository assets follow the standard structure +- [ ] Markdown renders correctly on GitHub desktop and mobile +- [ ] No stale or broken asset references +- [ ] License and copyright are current diff --git a/PRIVACY.md b/docs/privacy/PRIVACY.md similarity index 100% rename from PRIVACY.md rename to docs/privacy/PRIVACY.md