Update README to reflect current state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
91
README.md
91
README.md
@@ -1,15 +1,18 @@
|
||||
# task-inventory
|
||||
|
||||
Personal task management. Organise tasks, thoughts, and ideas as a hierarchy. Designed to grow into project management over time.
|
||||
Personal inventory for tasks, ideas, notes, and anything else. Entries are organised in a hierarchy, with configurable entry types. Designed to grow into project management over time.
|
||||
|
||||
## Features
|
||||
|
||||
- Hierarchical tasks with unlimited nesting — create subtasks, reparent tasks, or promote subtasks to roots
|
||||
- Tree view (roots only, expandable) and flat view (all tasks)
|
||||
- Filters by status, priority, and tag; free-text search across title and body
|
||||
- Markdown rendering via a local Gitea instance — preview tab in the editor, rendered inline in the task list
|
||||
- Sequential integer IDs
|
||||
- Flat NDJSON key-value store — single file, no database required
|
||||
- **Configurable entry types** — default types are task, idea, note; create your own
|
||||
- **Hierarchical entries** — unlimited nesting, any type can be a child of any other
|
||||
- **Tree view** (roots only, expandable — children always shown unfiltered) and **flat view**
|
||||
- **Filters** by status, priority, and tag; free-text search across title and body; clickable tag chips
|
||||
- **Entry detail view** — full rendered markdown, metadata, children list; URL-addressable (`#4`)
|
||||
- **URL routing** — `#all`, `#type/<id>`, `#<entry-id>`, `#manage-types`; back/forward works
|
||||
- **Markdown rendering** via a local Gitea instance — edit/preview tabs in the editor
|
||||
- **Sequential integer IDs** — global across all entry types
|
||||
- **Flat NDJSON key-value store** — single file, no database required
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -32,7 +35,7 @@ gitea:
|
||||
token: your_token_here # needs read:misc scope minimum
|
||||
```
|
||||
|
||||
If Gitea is not configured, task titles and bodies are shown as plain text.
|
||||
If Gitea is not configured, titles and bodies are shown as plain text.
|
||||
|
||||
Environment overrides:
|
||||
|
||||
@@ -43,73 +46,84 @@ Environment overrides:
|
||||
|
||||
## Data model
|
||||
|
||||
Tasks are stored in `data/tasks.ndjson`. Sequential IDs are tracked in `data/ids.ndjson`.
|
||||
All data is stored in `data/tasks.ndjson` as a flat NDJSON key-value store.
|
||||
|
||||
```
|
||||
Task {
|
||||
id integer sequential, auto-assigned
|
||||
Entry {
|
||||
id integer sequential, global across all types
|
||||
type string entry type id (e.g. "task", "idea", "note")
|
||||
title string markdown
|
||||
body string markdown, optional
|
||||
status open | deferred | done | cancelled
|
||||
priority high | normal | low
|
||||
tags string[]
|
||||
parent_id integer | null null = root task
|
||||
parent_id integer | null null = root entry
|
||||
created_at ms timestamp
|
||||
updated_at ms timestamp
|
||||
}
|
||||
|
||||
Entry_Type {
|
||||
id string lowercase alphanumeric/underscore, e.g. "bug_report"
|
||||
title string display name
|
||||
description string
|
||||
created_at ms timestamp
|
||||
updated_at ms timestamp
|
||||
}
|
||||
```
|
||||
|
||||
On first run, three default entry types are seeded: task, idea, note. Existing data from older flat-key format (`task:1`, `task:2`, …) is migrated automatically.
|
||||
|
||||
## API
|
||||
|
||||
All responses: `{ ok: true, ...data }` or `{ ok: false, error: string }`.
|
||||
|
||||
```
|
||||
GET /api/tasks
|
||||
POST /api/tasks body: { title, body?, status?, priority?, tags?, parent_id? }
|
||||
GET /api/tasks/:id
|
||||
PUT /api/tasks/:id body: any subset of task fields
|
||||
DELETE /api/tasks/:id blocked if task has subtasks
|
||||
GET /api/entry-types
|
||||
POST /api/entry-types body: { id, title, description? }
|
||||
PUT /api/entry-types/:id body: { title?, description? }
|
||||
DELETE /api/entry-types/:id blocked if type still has entries
|
||||
|
||||
POST /api/render-markdown body: { text, mode? } → { html }
|
||||
GET /api/entries ?type=<id> to filter by type
|
||||
POST /api/entries body: { type, title, body?, status?, priority?, tags?, parent_id? }
|
||||
GET /api/entries/:id
|
||||
PUT /api/entries/:id body: any subset of entry fields
|
||||
DELETE /api/entries/:id blocked if entry has children
|
||||
|
||||
POST /api/render-markdown body: { text, mode? } → { html }
|
||||
```
|
||||
|
||||
## Running as a system service
|
||||
|
||||
`deployment/task-inventory.service` targets `/srv/task-inventory` with a dedicated `task-inventory` user.
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
# Create service user
|
||||
# First time: create service user and config
|
||||
sudo useradd -r task-inventory
|
||||
|
||||
# Deploy files
|
||||
sudo cp -r . /srv/task-inventory
|
||||
sudo chown -R task-inventory:task-inventory /srv/task-inventory
|
||||
|
||||
# Install dependencies as service user
|
||||
sudo -u task-inventory npm ci --prefix /srv/task-inventory
|
||||
|
||||
# Copy and configure config.yaml
|
||||
sudo mkdir -p /srv/task-inventory
|
||||
sudo cp config.yaml.example /srv/task-inventory/config.yaml
|
||||
sudo chown task-inventory:task-inventory /srv/task-inventory/config.yaml
|
||||
# edit /srv/task-inventory/config.yaml
|
||||
|
||||
# Enable and start
|
||||
# Deploy (and on every update)
|
||||
make deploy DEST=/srv/task-inventory
|
||||
|
||||
# Enable service (first time only)
|
||||
sudo systemctl enable --now "$(realpath deployment/task-inventory.service)"
|
||||
```
|
||||
|
||||
Packaging (Arch, Debian, etc.) is not set up yet.
|
||||
`make deploy` runs rsync (excluding `data/`, `config.yaml`, `node_modules/`), fixes ownership, and runs `npm ci` as the service user. `make sync` does the rsync+chown only, skipping `npm ci`.
|
||||
|
||||
To bind to all interfaces instead of localhost, uncomment `Environment=BIND_ADDRESS=0.0.0.0` in `deployment/task-inventory.service`.
|
||||
|
||||
## File map
|
||||
|
||||
```
|
||||
server.mjs Entry point — Express 5, all routes
|
||||
Makefile deploy / sync targets
|
||||
lib/
|
||||
config.mjs Loads config.yaml (ENOENT-safe)
|
||||
ids.mjs Sequential integer ID generator per namespace
|
||||
kv-store.mjs Flat NDJSON key-value store (auto-load, debounced flush)
|
||||
storage.mjs Task CRUD wrappers
|
||||
storage.mjs Entry types + entries CRUD, ID generation, migration
|
||||
public/
|
||||
app.mjs SPA — state, rendering, dialogs
|
||||
app.mjs SPA — state, routing, rendering, dialogs
|
||||
index.html Shell
|
||||
style.css All styles
|
||||
templates.html HTML templates (injected at init)
|
||||
@@ -118,6 +132,7 @@ public/
|
||||
api.mjs fetch wrappers for all API endpoints
|
||||
dom.mjs qs(), clone(), set_text(), show(), hide()
|
||||
data/ Created at runtime, not committed
|
||||
tasks.ndjson All task records
|
||||
ids.ndjson Sequence counters
|
||||
tasks.ndjson All entry records and entry type definitions
|
||||
deployment/
|
||||
task-inventory.service systemd unit file
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user