Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
node_modules/
coverage/
/data/
__pycache__/
*.pyc
.venv/
venv/
_site/
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## SQLite persistence (2026-06-15)

### Added
- `server.py` - Flask app on port 8090 serving `index.html` and `/api/board`
- `db.py` - SQLite storage in `data/taskboard.db`
- `seed_data.py` - default team/tasks seeded on first run
- `requirements.txt` - Flask dependency
- `src/lib/board-sync.js` - background load/save (500ms debounce after edits)

### Changed
- `src/app/main.js` - restored main-branch UI boot (sync `renderAll()`), persistence loads in background
- `src/lib/board-sync.js` - thin save/load layer; only replaces data when server has a real board
- Removed `board-store.js` / `sample-tasks.js` split that broke the initial render

### Reasoning
- Single JSON blob in SQLite keeps v1 simple and matches the in-memory tree model
- Debounced PUT after `snap()` covers all task mutations without touching every handler
- Python fits the existing port-8090 hosting setup

### Fixed
- `seed_data.py` nested `make()` was re-processing already-built child nodes, stripping due/size/children
- `board-sync.js` now rejects corrupt server boards so inline sample data is kept

## Testing infrastructure (2026-06-15)

### Added
Expand Down
42 changes: 37 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
# Task Management Tool

TaskBoard prototype: a single-page task planner with gantt timeline, balance-scale dashboard, voice capture, and transcript extraction.
TaskBoard prototype: a single-page task planner with gantt timeline, balance-scale dashboard, voice capture, and transcript extraction. SQLite-backed persistence when served via `server.py`.

AI-perc:47%

## Run locally
## Run locally (with persistence)

Open `index.html` in a browser, or serve the repo root:
```bash
pip install -r requirements.txt
python server.py
```

Open http://localhost:8090

Data is stored in `data/taskboard.db` (created on first run).

## Run locally (static only, no persistence)

```bash
npx --yes serve .
```

Edits will not survive refresh without the Python server.

## Development

Install dependencies and run tests:
Expand All @@ -27,16 +38,35 @@ Watch mode:
npm run test:watch
```

## API (Python server)

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/board` | Load people, tasks, and config |
| PUT | `/api/board` | Save full board state |
| GET | `/api/health` | Health check |

## Project layout

| Path | Purpose |
|------|---------|
| `index.html` | UI markup and styles |
| `src/app/main.js` | Application logic (DOM, rendering, interactions) |
| `src/data/constants.js` | Team roster, clients, sizes, colors |
| `src/lib/` | Testable pure functions (domain, tree, dates, capture) |
| `src/lib/board-sync.js` | Server load/save (non-blocking) |
| `server.py` | Flask app + SQLite API |
| `tests/` | Vitest unit tests |

## Deploy on your server

1. Pull/copy this repo to the server
2. `pip install -r requirements.txt`
3. Run `python server.py --host 0.0.0.0 --port 8090`
4. Ensure `data/` is writable and backed up
5. Use a process manager (systemd) so the server survives reboots

Optional: set `OPENAI_API_KEY` in the environment when you add `/extract` later.

## Before opening a PR

1. Run `npm run ci` and confirm all checks pass.
Expand Down Expand Up @@ -67,10 +97,12 @@ After checks pass, a bot comment on the PR includes a link like:

`https://summon-rnd.github.io/task-manager/`

Note: GitHub Pages serves static files only. Persistence requires the Python server on your remote host.

### Local preview

```bash
gh pr checkout <PR_NUMBER>
npm install
npx --yes serve .
python server.py
```
75 changes: 75 additions & 0 deletions db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import json
import sqlite3
from datetime import datetime, timezone
from pathlib import Path

from seed_data import default_board

DB_PATH = Path(__file__).resolve().parent / "data" / "taskboard.db"


def connect():
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn


def init_db():
with connect() as conn:
conn.execute(
"""
CREATE TABLE IF NOT EXISTS board_state (
id INTEGER PRIMARY KEY CHECK (id = 1),
data TEXT NOT NULL,
updated_at TEXT NOT NULL
)
"""
)
row = conn.execute("SELECT data FROM board_state WHERE id = 1").fetchone()
if row is None:
save_board(conn, default_board())
else:
board = json.loads(row["data"])
if not board.get("tasks") or not board.get("people"):
save_board(conn, default_board())


def get_board(conn=None):
own = conn is None
if own:
conn = connect()
try:
row = conn.execute("SELECT data, updated_at FROM board_state WHERE id = 1").fetchone()
if row is None:
board = default_board()
save_board(conn, board)
return board, datetime.now(timezone.utc).isoformat()
board = json.loads(row["data"])
if not board.get("tasks") or not board.get("people"):
board = default_board()
save_board(conn, board)
return board, row["updated_at"]
finally:
if own:
conn.close()


def save_board(conn, board):
now = datetime.now(timezone.utc).isoformat()
payload = json.dumps(board, ensure_ascii=False)
conn.execute(
"""
INSERT INTO board_state (id, data, updated_at)
VALUES (1, ?, ?)
ON CONFLICT(id) DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at
""",
(payload, now),
)
conn.commit()
return now


def put_board(board):
with connect() as conn:
return save_board(conn, board)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flask>=3.0,<4
Loading
Loading