note taking and reminder generating pwa for zettlekasten
  • Rust 44.6%
  • Svelte 31.6%
  • JavaScript 20.7%
  • Just 1.3%
  • Dockerfile 1.1%
  • Other 0.7%
Find a file
Ed Sweeney ca7f6b128a
All checks were successful
CI / ci (push) Successful in 2m3s
Merge pull request 'Update rust Docker tag to v1.96' (#30) from renovate/rust-1.x into main
Reviewed-on: #30
2026-06-01 12:47:00 +00:00
.forgejo/workflows rev rust to 1.95.x 2026-05-25 06:36:20 -07:00
docs docs 2026-05-25 07:11:20 -07:00
pwa Update dependency svelte to v5.56.0 2026-06-01 08:06:09 +00:00
server Update Rust crate sqlx to 0.9 2026-06-01 09:05:29 +00:00
sync Merge pull request 'Update Rust crate getrandom to 0.4' (#24) from renovate/getrandom-0.x into main 2026-05-28 13:47:27 +00:00
.gitignore toolchain 2026-04-17 15:04:40 -07:00
Cargo.lock Merge pull request 'Update Rust crate sqlx to 0.9' (#29) from renovate/sqlx-0.x into main 2026-06-01 12:46:50 +00:00
Cargo.toml ⏺ All done. Here's a summary of what was created: 2026-01-26 22:23:11 -08:00
Dockerfile Update rust Docker tag to v1.96 2026-06-01 09:05:35 +00:00
Justfile clean 2026-05-25 06:59:01 -07:00
LICENSE Add MIT License to the project 2026-01-30 21:26:15 -08:00
PLAN.md docs 2026-05-25 07:11:20 -07:00
README.md readme 2026-05-25 06:22:27 -07:00
renovate.json renovate 2026-05-21 04:47:46 -07:00
rust-toolchain.toml rev rust to 1.95.x 2026-05-25 06:36:20 -07:00

navinote

A personal note-taking PWA with reminders and markdown sync.

Components

  • pwa/ - Svelte 5 progressive web app
  • server/ - Axum REST API with SQLite
  • sync/ - CLI tool to sync notes to markdown files

Quick Start

# Install dependencies
cd pwa && npm install

# Build everything
just build

# Run locally
just dev-server   # API on :8080
just dev-pwa      # Vite dev server

CLI Sync

Install the sync tool:

just install

First-time login (browser-based, once per workstation):

export NAVINOTE_OIDC_ISSUER="https://auth.navicore.tech/realms/homelab"
export NAVINOTE_OIDC_CLIENT_ID="navinote-sync"
navinote-sync login

Then run sync (cron-friendly — no env needed beyond NAVINOTE_ZET_DIR):

export NAVINOTE_ZET_DIR="$HOME/notes"
# NAVINOTE_URL defaults to https://notes.navicore.tech

navinote-sync

Synced notes are appended to daily markdown files (YYYY-MM-DD.md) with reminders formatted as:

* [ ] #reminder 2026-01-30T14:00:00Z: Call dentist
* [x] #reminder 2026-01-30T09:00:00Z: Morning standup

Features

  • Offline-first with IndexedDB
  • Swipe left to delete, swipe right to mark done
  • Reminder color coding (green=future, orange=overdue, dimmed=done)
  • iOS/Android install prompts

CI

CI is defined in .forgejo/workflows/ci.yml and runs on every PR and push to main. It invokes a single command — just ci — which chains:

  • fmt-checkcargo fmt --all -- --check
  • lintcargo clippy --locked --workspace --all-targets -- -D warnings plus a strict PWA build (SVELTE_STRICT=1)
  • testcargo test --locked --workspace --all-targets
  • build — PWA, server, and sync release builds

The Rust toolchain is pinned to 1.93.0 in two places that must stay in sync: rust-toolchain.toml (local dev) and the toolchain: input of the CI workflow. All cargo invocations use --locked, so a stale Cargo.lock fails the build instead of silently re-resolving.

Run the exact same checks locally before pushing:

just ci

Environment Variables

Server:

Variable Required Default Description
NAVINOTE_OIDC_ISSUER Yes - Realm issuer URL (e.g. https://auth.example.com/realms/navinote)
NAVINOTE_OIDC_AUDIENCES Yes - Comma-separated aud values to accept. With anz this is the realm URL (e.g. https://auth.example.com/realms/homelab) — anz puts the resource-server identifier in the access token's aud, not the client_id.
NAVINOTE_BOOTSTRAP_SUB One-shot - Operator sub used to backfill user_id on pre-OIDC notes. Set for one deploy, then unset.
NAVINOTE_DB_PATH No navinote.db SQLite database path
NAVINOTE_PORT No 8080 Server port
NAVINOTE_STATIC_DIR No dist Static files directory

Sync CLI:

First-time setup uses OIDC. Run navinote-sync login once on a workstation with a browser — it opens the auth page, catches the callback on http://127.0.0.1:8765/callback, and writes the refresh token to $XDG_STATE_HOME/navinote-sync/credentials.json (mode 0600). Subsequent cron-driven runs use that refresh token (rotated every run).

Variable When Default Description
NAVINOTE_OIDC_ISSUER login only - Realm issuer URL (e.g. https://auth.example.com/realms/navinote)
NAVINOTE_OIDC_CLIENT_ID login only - The PWA/CLI public client (e.g. navinote-sync)
NAVINOTE_URL sync https://notes.navicore.tech API URL
NAVINOTE_ZET_DIR sync - Markdown output directory (required)

If the refresh token expires or is revoked, the next sync writes a #reminder line to today's zet file (navinote-sync needs re-auth — run \navinote-sync login``) and exits non-zero.