task-inventory

Personal task management. Organise tasks, thoughts, and ideas as a hierarchy. 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

Setup

npm install
cp config.yaml.example config.yaml
# edit config.yaml — add your Gitea URL and token
node server.mjs

Server starts on http://localhost:3025 by default.

Configuration

config.yaml (not committed):

gitea:
  url: https://gitea.example.com
  token: your_token_here   # needs read:misc scope minimum

If Gitea is not configured, task titles and bodies are shown as plain text.

Environment overrides:

Variable Default
PORT 3025
BIND_ADDRESS localhost

Data model

Tasks are stored in data/tasks.ndjson. Sequential IDs are tracked in data/ids.ndjson.

Task {
  id          integer          sequential, auto-assigned
  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
  created_at  ms timestamp
  updated_at  ms timestamp
}

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

POST   /api/render-markdown   body: { text, mode? }   → { html }

Running as a system service

deployment/task-inventory.service is a systemd unit file. To use it:

  1. Fill in WorkingDirectory with the path to the deployed app
  2. Create a dedicated user: useradd -r task-inventory
  3. systemctl enable --now /path/to/deployment/task-inventory.service

Packaging (Arch, Debian, etc.) is not set up yet.

File map

server.mjs              Entry point — Express 5, all routes
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
public/
  app.mjs               SPA — state, rendering, dialogs
  index.html            Shell
  style.css             All styles
  templates.html        HTML templates (injected at init)
  gitea-markup.css      Vendored Gitea markup + chroma CSS for markdown rendering
  lib/
    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
Description
Personal task management
Readme 368 KiB
Languages
JavaScript 76%
CSS 17.6%
HTML 5.4%
Makefile 1%