222 lines
9.3 KiB
Markdown
222 lines
9.3 KiB
Markdown
# Personal Backlog
|
||
|
||
A minimalist, single-user task manager where **a single Markdown file is your database**.
|
||
|
||
No cloud. No accounts. No vendor lock-in. Your tasks live in a plain `backlog.md` file you can read, edit, and version-control with any tool you already use.
|
||
|
||
## Why Not Just Use...
|
||
|
||
| Concern | Todoist / TickTick / Notion | This App |
|
||
|---------|-----------------------------|----------|
|
||
| Where's my data? | Their servers | A single `.md` file on *your* disk |
|
||
| Online required? | Yes (cloud sync) | Never — even the server is localhost-only |
|
||
| Vendor lock-in? | You need their app to read your data | It's a `.md` file — read it in VS Code, Vim, `cat` |
|
||
| Can I `git commit` my tasks? | No | Yes — it's a text file |
|
||
| Can I sync across devices? | Built-in cloud | Any file sync — Dropbox, rsync, git, USB, anything |
|
||
| Price | $5–6/mo | Free, forever |
|
||
|
||
**If you've ever wanted your task list to be just a file — this is it.**
|
||
|
||
## Quick Start
|
||
|
||
### Option A: Python Server (all browsers)
|
||
|
||
Works with Chrome, Firefox, Safari — any browser. The server is a single Python file with zero dependencies.
|
||
|
||
```bash
|
||
cd personal-backlog
|
||
python3 server/server.py --port 8080
|
||
```
|
||
|
||
Then open **http://localhost:8080** in your browser.
|
||
|
||
The server creates `backlog.md`, `backups/`, and `stats.jsonl` in its own directory by default. To store data elsewhere:
|
||
|
||
```bash
|
||
python3 server/server.py --port 8080 --dir ~/my-backlog
|
||
```
|
||
|
||
### Option B: Standalone HTML (Chrome / Edge only)
|
||
|
||
No Python needed. Just open the HTML file:
|
||
|
||
```bash
|
||
open webapp/index-style-v2.html
|
||
```
|
||
|
||
Or serve it with any static file server:
|
||
|
||
```bash
|
||
cd webapp && python3 -m http.server 3000
|
||
# Then open http://localhost:3000/index-style-v2.html
|
||
```
|
||
|
||
On first launch, the browser will prompt you to **select a folder**. This is required because browsers can't access your filesystem without explicit permission. Create a folder (or pick an existing one) and the app will create `backlog.md`, `backups/`, and `stats.jsonl` inside it.
|
||
|
||
## How It Works
|
||
|
||
### The Markdown File
|
||
|
||
All your tasks live in `backlog.md`, structured as:
|
||
|
||
```markdown
|
||
# Backlog
|
||
|
||
<!-- SECTION: ENTRIES -->
|
||
|
||
- [ ] [P0] Ship landing page *(due: 2025-06-01, priority: P0, progress: 50)*
|
||
- [x] Design mockups *(priority: P0, progress: 100)*
|
||
- [/] Implement frontend *(priority: P1, progress: 30)*
|
||
- [!] [P1] API integration *(priority: P1, reason: waiting for keys)*
|
||
- [>] [P2] Blog post *(priority: P2, due: 2025-07-15)*
|
||
|
||
<!-- SECTION: HISTORY -->
|
||
|
||
| Timestamp | Item ID | Action | Details |
|
||
|-----------|---------|--------|---------|
|
||
| 2025-05-10T14:32:00Z | i-m1 | status_changed | open → done |
|
||
|
||
<!-- SECTION: INTEGRITY -->
|
||
|
||
<!-- saved: 2025-05-10T14:35:12Z | checksum: sha256:abc123... | entries: 3 | history: 1 -->
|
||
```
|
||
|
||
You can edit this file in any text editor. The app detects external changes and reloads automatically.
|
||
|
||
### Features
|
||
|
||
- **4-level nesting** — Area → Project → Task → Sub-task
|
||
- **6 statuses** — open, in-progress (`/`), blocked (`!`), postponed (`>`), done (`x`), cancelled (`-`)
|
||
- **Priorities** — P0 (burning) through P3, with drag-and-drop reordering within each priority
|
||
- **Progress tracking** — 0–100% per task; done auto-sets to 100%
|
||
- **Due dates** — with overdue highlighting
|
||
- **Tags** — free-form labels with autocomplete
|
||
- **Quick search** — instant text search with hierarchical parent visibility
|
||
- **Integrity checks** — SHA-256 checksum on every save; warning-only on mismatch
|
||
- **Automatic backups** — timestamped on every save, rotating retention
|
||
- **Stats & metrics** — items created/completed, avg time in-progress, most active project — all from real history data
|
||
- **Import/Export** — Markdown or JSON, with checksum validation
|
||
- **Admin page** — health monitoring, backup browser, stats overview, manual actions
|
||
|
||
## Two Storage Modes
|
||
|
||
The app detects which mode to use automatically:
|
||
|
||
| | API Server | Direct File Access |
|
||
|---|---|---|
|
||
| **How to start** | Run `python3 server/server.py` | Open `webapp/index-style-v2.html` in Chrome/Edge |
|
||
| **Works in** | Any browser | Chrome, Edge only |
|
||
| **File access via** | HTTP REST API | File System Access API |
|
||
| **Folder picker** | Not needed | Required on first launch |
|
||
| **LAN access** | Yes (phone, tablet) | No (local browser only) |
|
||
| **Admin shows paths** | Yes (full path) | Folder name only |
|
||
|
||
### Why the Folder Picker? (Direct Mode)
|
||
|
||
When you open the HTML file directly, the browser has no access to your filesystem. The **File System Access API** (`showDirectoryPicker()`) is the only way to read and write local files from a web page. You grant permission once; the handle is stored in IndexedDB so it persists across reloads.
|
||
|
||
**To reset the folder** (pick a different one or clear saved permissions):
|
||
|
||
1. Open DevTools → Application → IndexedDB → delete the `pb-storage-v2` database
|
||
2. Reload the page — you'll be prompted to pick a folder again
|
||
|
||
## Coherency Between Python and Standalone Versions
|
||
|
||
Both versions read and write the **exact same `backlog.md` format**. The Parser and Serializer are identical in logic. This means you can:
|
||
|
||
1. **Start with the Python server** — add tasks, create structure
|
||
2. **Shut down the server** — open the same `backlog.md` location via the standalone HTML
|
||
3. **Switch freely** — edits in one mode are visible in the other
|
||
|
||
### How to Switch Modes
|
||
|
||
**From API server to standalone:**
|
||
|
||
1. Stop the server (`Ctrl+C`)
|
||
2. Open `webapp/index-style-v2.html` in Chrome/Edge
|
||
3. When prompted, select the folder that contains your `backlog.md` (e.g. the `server/` directory or wherever `--dir` pointed)
|
||
|
||
**From standalone to API server:**
|
||
|
||
1. Note which folder your `backlog.md` lives in
|
||
2. Start the server pointing to that folder:
|
||
```bash
|
||
python3 server/server.py --dir /path/to/your/folder
|
||
```
|
||
3. Open `http://localhost:8080`
|
||
|
||
### Important Notes
|
||
|
||
- **Don't run both modes simultaneously** against the same `backlog.md` — the last writer wins and you may lose edits.
|
||
- **External edits** (Vim, VS Code, etc.) are detected automatically via checksum polling every 5 seconds. If you have unsaved changes in the app, you'll get a conflict resolution dialog.
|
||
- The **checksum is a save indicator**, not a gate. If it mismatches (e.g. you edited the file by hand), the app still loads it — just with a yellow warning banner. The next save recalculates a correct checksum.
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
personal-backlog/
|
||
├── README.md
|
||
├── doc/
|
||
│ ├── requirements/requirements.md # Functional & non-functional requirements
|
||
│ └── architecture/
|
||
│ ├── architecture.md # High-level architecture
|
||
│ └── tdd.md # Technical Design Document
|
||
├── server/
|
||
│ ├── server.py # Python REST API server (~420 LoC, stdlib only)
|
||
│ ├── backlog.md # Master data file (created on first run)
|
||
│ ├── backups/ # Automatic timestamped backups
|
||
│ └── stats.jsonl # Append-only analytics log
|
||
├── web/ # V2 source code (React 18 + JSX) + build tooling
|
||
│ ├── index.html # Dev entry point (React + Babel from CDN)
|
||
│ ├── styles.css # All CSS
|
||
│ ├── storage.jsx # Parser, ApiBackend, DirectBackend, SyncPoller
|
||
│ ├── helpers.jsx # Utility functions, event handling
|
||
│ ├── app.jsx # Root App component, state, save/load lifecycle
|
||
│ ├── tree.jsx # Task tree rendering
|
||
│ ├── dialogs.jsx # Modal dialogs
|
||
│ ├── admin.jsx # Admin dashboard
|
||
│ ├── filter-panel.jsx # Filter sidebar
|
||
│ ├── tweaks-panel.jsx # Settings panel
|
||
│ ├── data.jsx # Seed data (test-only, not loaded by default)
|
||
│ ├── bundle.js # Build tool: multi-file JSX → single HTML
|
||
│ ├── package.json # @babel/core + @babel/preset-react
|
||
│ └── node_modules/
|
||
├── webapp/ # Built output — ready to open or deploy
|
||
│ └── index-style-v2.html # Self-contained single-file SPA (~348 KB)
|
||
└── design/
|
||
├── design-v1/ # V1 source (archived, vanilla JS)
|
||
└── archive/ # Earlier prototypes
|
||
```
|
||
|
||
## Development
|
||
|
||
### Running the Dev Server (in-browser Babel)
|
||
|
||
```bash
|
||
cd web
|
||
python3 -m http.server 9000
|
||
# Open http://localhost:9000 — React + Babel load from CDN, no build step needed
|
||
```
|
||
|
||
### Building the Production Bundle
|
||
|
||
```bash
|
||
cd web
|
||
npm install # once, to install @babel/core + @babel/preset-react
|
||
node bundle.js index.html ../webapp/index-style-v2.html
|
||
```
|
||
|
||
The bundler pre-compiles all JSX, swaps React dev CDN builds for production minified builds, removes Babel entirely, and writes a single self-contained HTML file to `webapp/`.
|
||
|
||
See [`doc/architecture/tdd.md`](doc/architecture/tdd.md) for full technical details.
|
||
|
||
### Requirements
|
||
|
||
- **Runtime**: Python 3.8+ (server), any modern browser
|
||
- **Development**: Node.js 18+ (for the bundler only)
|
||
- **Bundler deps**: `cd web && npm install`
|
||
|
||
## License
|
||
|
||
Personal use. Do whatever you want with it.
|