Skip to content

A self-hosted, GTD-inspired task management system built entirely in Rust.

Notifications You must be signed in to change notification settings

zorya-development/north

Repository files navigation

North

North screenshot

Disclaimer: I started this project to see how far I could get with Claude Code on a stack I've never worked with before. I deliberately chose Rust, Leptos, and Diesel so I'd have less temptation to write the code myself — I lead the architecture and design, and Claude Code writes the implementation, which turns out to be pretty close to a tech lead job. I've been quite impressed with the results, though I've also learned a lot about what AI-assisted development can and can't do. For context, I have 15 years of experience in web development — I know how to write code, design systems, deploy, and maintain things — but this project is an exercise in agentic coding. I do aim to bring it to a stable release, though it's not there yet. Use it at your own risk.

A self-hosted, GTD-inspired task management system built entirely in Rust. North combines a full-stack Rust architecture with practical Getting Things Done workflows — sequential subtask execution, structured review cycles, and a powerful query language for filtering tasks.

Features

  • Inbox & Today views — capture tasks quickly, then focus on what's actionable today
  • Sequential subtasks — configurable N-next visibility so you only see the tasks you should work on now
  • Recurring tasks — flexible recurrence rules (daily, weekly, monthly, yearly) with fixed-schedule or after-completion modes
  • GTD review cycles — per-task review tracking with configurable intervals to keep your system current
  • Projects & tags — organize work with colored projects (list or kanban view) and user-defined tags
  • Filter DSL — JQL-like query language with autocomplete for building saved filters (status = 'ACTIVE' AND tags =~ 'work:*' ORDER BY due_date ASC)
  • Keyboard-driven task management — full keyboard navigation with tree-aware cursor, inline editing, task creation, and reordering (press ? to see all shortcuts)
  • Inline parsing — type #tag or @project directly in task titles to assign tags and projects on the fly
  • Markdown support — full CommonMark rendering in task descriptions
  • Drag and drop — reorder tasks, nest subtasks, and organize with drag-and-drop or keyboard shortcuts
  • Dark & light themes — respects system preference with manual toggle
  • Timezone support — per-user timezone setting for accurate scheduling and recurrence display
  • REST API — full CRUD API for external integrations alongside the web UI
  • Single binary — one Rust binary serves both the server-rendered pages and the WASM-hydrated client

Tech Stack

North is a full-stack Rust application — no JavaScript runtime, no Node.js, no npm.

Layer Technology
Language Rust (stable, edition 2021)
Frontend Leptos 0.7 (SSR + WASM hydration)
Backend Axum
Database PostgreSQL 17 via Diesel (async)
Styling TailwindCSS 4
Auth JWT (httpOnly cookies) with Argon2 password hashing

Quick Start

Prerequisites

  • Docker & Docker Compose

Running with Docker Compose

# Clone the repository
git clone https://github.com/zorya-development/north.git
cd north

# Build and start all services
docker compose up -d

# Run database migrations and seed the admin account
docker compose exec app just migrate
docker compose exec app just seed

The application will be available at http://localhost:5000.

Default admin credentials: admin@north.local / admin

There is no self-registration. The admin account creates all other users.


Deploy with Helm

The included Helm chart deploys North to any Kubernetes cluster with PostgreSQL, automatic migrations, uploads persistence, and optional ingress/TLS.

Prerequisites

  • Kubernetes 1.24+
  • Helm 3.x
  • kubectl configured for your cluster

Install

# From OCI registry (published automatically on chart changes)
helm install north oci://ghcr.io/zorya-development/north/charts/north \
  -n north --create-namespace

# Or from a local clone
helm install north ./chart -n north --create-namespace

The admin account is seeded automatically on first install. Default credentials: admin@north.app / admin. Password change is not yet implemented — do not expose this to the public internet.

Configuration

Custom domain with TLS

helm install north ./chart -n north --create-namespace \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set ingress.hosts[0].host=tasks.example.com \
  --set ingress.hosts[0].paths[0].path=/ \
  --set ingress.hosts[0].paths[0].pathType=Prefix \
  --set ingress.tls[0].hosts[0]=tasks.example.com \
  --set ingress.tls[0].secretName=north-tls

External PostgreSQL

helm install north ./chart -n north --create-namespace \
  --set postgresql.enabled=false \
  --set externalDatabase.host=postgres.example.com \
  --set externalDatabase.password=secret

Pre-created secrets

kubectl create secret generic north-secrets -n north \
  --from-literal=database-url='postgres://user:pass@host:5432/north' \
  --from-literal=jwt-secret='your-secret-here'

helm install north ./chart -n north \
  --set existingSecret.name=north-secrets

Key values

Value Default Description
image.tag Chart appVersion Docker image tag
postgresql.enabled true Deploy in-cluster PostgreSQL (Bitnami)
postgresql.auth.password auto-generated PostgreSQL password
secret.jwtSecret auto-generated JWT signing secret (preserved across upgrades)
secret.databaseUrl Explicit DATABASE_URL (overrides all other DB config)
existingSecret.name Use a pre-created Secret (keys: database-url, jwt-secret)
externalDatabase.host External PostgreSQL host (when postgresql.enabled=false)
ingress.enabled false Create an Ingress resource
ingress.className Ingress class (e.g. nginx, traefik)
persistence.enabled true PVC for uploads (/app/uploads)
persistence.size 5Gi Uploads volume size
migration.enabled true Run Diesel migrations as a pre-install/pre-upgrade hook
autoscaling.enabled false Enable HPA (scales 1–3 replicas on CPU)
resources.requests.memory 128Mi Memory request
resources.limits.memory 512Mi Memory limit

Full values reference: chart/values.yaml


Development

Prerequisites

  • Docker & Docker Compose

Setup

# Build the base and dev images
docker compose build

# Start the database
docker compose up -d db

# Enter the app container
docker compose run --rm -ti --service-ports app bash

# Inside the container:
just migrate          # Apply database migrations
just seed             # Seed admin account
just dev              # Start dev server with hot reload

Commands

All commands run inside the app container via just:

Command Description
just dev Dev server with hot reload (cargo-leptos)
just test Run all tests
just test crate_name Run tests for a specific crate
just fmt Format code
just lint Run clippy
just check fmt + lint + test
just migrate Apply database migrations
just migration name Create a new migration
just migrate-revert Revert last migration
just migrate-redo Revert + reapply last migration
just build Release build
just seed Seed admin account

For CI or non-interactive use: docker compose exec app just <command>

End-to-End Tests

E2E tests use Playwright and run against the full app in Docker. Commands run from the host (not inside the app container):

just playwright              # Start test stack + Playwright UI mode (port 8080)
just playwright-exec         # Run tests headless in already-running containers
just playwright-down         # Tear down test containers and volumes

# Rebuild test containers (needed after migrations, schema changes, or new features)
just playwright-down && docker compose -p north-test -f docker-compose.test.yml up -d --build

Project Structure

North is organized as a Cargo workspace with layered crates:

north/
├── crates/
│   ├── dto/            # Shared data types (no IO) — compiled for server and WASM
│   ├── db/             # Diesel schema, models, connection pool
│   ├── core/           # Business logic, services, filter DSL engine
│   ├── server-fns/     # Leptos #[server] RPC boundary
│   ├── repositories/   # Thin async facade over server functions
│   ├── stores/         # Reactive client state (signals, memos, optimistic updates)
│   ├── ui/             # Generic UI component library (no domain deps)
│   ├── app/            # Leptos pages, containers, components (SSR + WASM)
│   └── server/         # Axum binary, REST API, auth middleware
├── migrations/         # Diesel reversible migrations (up.sql + down.sql)
├── style/              # TailwindCSS entry point
├── public/             # Static assets
├── chart/              # Helm chart for Kubernetes deployment
├── docker/             # Base, dev, and prod Dockerfiles
└── docs/               # Product requirements, design system, and architecture reference

Data flows through the layers in one direction:

Page → Store → Repository → ServerFn ──RPC──→ Service → Diesel → PostgreSQL

Docker Images

Image Path Purpose
base docker/base/Dockerfile Rust toolchain, cargo-leptos, diesel_cli, wasm32 target
dev docker/dev/Dockerfile Extends base — adds just and tailwindcss CLI
prod docker/prod/Dockerfile Runtime-only: debian:bookworm-slim with pre-built binary

Base image version is tracked in docker/base/VERSION. Bump with:

just bump-base patch    # 1.0.0 → 1.0.1
just bump-base minor    # 1.0.0 → 1.1.0
just bump-base major    # 1.0.0 → 2.0.0

CI/CD

  • test.yml — runs on pushes to master and all PRs: format check, clippy, tests. Conditionally rebuilds the base image if docker/base/** changed.
  • release.yml — runs on pushes to master: builds a production Docker image, pushes to ghcr.io, generates a changelog via git-cliff, and creates a GitHub release.

Releasing

  1. Bump version: just bump-version {major,minor,patch}
  2. Push to master (via PR or direct push)
  3. The release workflow automatically builds and publishes the Docker image, changelog, and GitHub release

License

Proprietary — Zorya Development

About

A self-hosted, GTD-inspired task management system built entirely in Rust.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •