- TypeScript 80.5%
- Svelte 16.8%
- Go 2.1%
- CSS 0.2%
- Makefile 0.2%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The pinned-highlight chip rendered behind Pro's time rail, and — reported in the same breath — the encoding legend has been hidden by every left sidebar: it sits at `left: 12px; z-index: 6` against a dock at `left: 44px; z-index: 20`. Not one unlucky corner. Floating chrome and floating panels shared a coordinate space with no agreement about who owned which region, so each picked absolute coordinates and a z-index alone and they collided. **There is no corner that stays free**, so moving either one only defers it. `stores/canvas-insets.ts` is a signal channel named for its effect: FOSS owns it and each thing occupying an edge is one producer — the left dock, the right inspector (already a store in `panels.ts`, reused rather than copied), and the bottom rail. `canvasInsets` says where the free area starts; the legend and the chip offset themselves by it. The pattern already existed, applied exactly once: `TimeRail` takes `leftInset` and `rightInset` props, which is why the rail never collides with anything. This makes it shared, so the next piece of chrome inherits the answer. Measured, not inferred from which panel is open: panels differ in width, and a hardcoded number is a second source of truth that drifts. Five mutations verified on the channel, three on the two consumers — including that removing the legend's offset fails, which is the bug as reported. Signed-off-by: Marcel M. Otte <marcel.otte@mmo.to> |
||
| .forgejo/workflows | ||
| .vscode | ||
| backend | ||
| CLA | ||
| desktop | ||
| dev/ci-templates | ||
| docs | ||
| docs-site | ||
| e2e | ||
| shared/proxycore | ||
| src | ||
| static | ||
| .gitignore | ||
| .npmrc | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| Makefile | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
Juurakko
A browser-first application that visualizes issues and tickets from project management tools on an interactive infinite canvas with tree connections.
Load issues from your PM tool, see parent/child and blocking relationships as a visual graph, and edit issues directly from the canvas.
About the name
Juurakko is Finnish for the root system of a tree — the whole spreading, interwoven mass of roots a tree grows from (also rootstock / rhizome). It comes from the Finnish juuri ("root") plus the collective suffix -kko. The name suits a tool that lays your project out as a tree: rarely a single "root of all evil" but many roots, with every issue tracing back through its links to them.
How to say it (stress the first syllable)
- For humans: YOO-rah-ko — "YOO" long like moon, a rolled r if you can manage it, and hold the double k a beat longer (YOO-rahk-ko).
- In phonetic notation (IPA):
[ˈjuːrɑkːo]
Features
- Interactive canvas — pan, zoom, collapse/expand subtrees, search and filter
- Multiple PM tool plugins — Forgejo, GitHub, and more coming
- Write-back — edit status, assignee, title, description, labels, and comments directly on cards
- Link creation — create parent/child and blocking relationships between issues from the canvas
- Filters — per-dimension chip filters with fade/hide modes and boundary visualization
- Child progress — progress bars showing closed/total counts with optional recursive descendant counting
- Saved views — persist and switch between canvas configurations
- Appearance — light/dark/system themes with customizable colors
- Desktop app — native desktop application via Wails for Linux and Windows — double-click and go, no terminal needed
- Go backend — single binary with embedded frontend and CORS proxy, cross-compiled for Linux, Windows, and macOS
- Offline-capable — runs entirely in the browser with IndexedDB caching; backend only needed for CORS proxy
Quick Start
Desktop app (recommended)
Download the latest release for your platform from the Releases page:
- Linux —
juurakko-desktop-linux-amd64 - Windows —
juurakko-desktop-windows-amd64-installer.exe(installer) or.exe(portable)
Run the app, add a connection to your PM tool in settings, and load a project.
Development
npm install
npm run dev
Open http://localhost:5173, add a connection to your PM tool in settings, and load a project.
Build
Desktop app
Requires Wails CLI:
make desktop # build for current platform
make desktop-debug # build with devtools enabled
make release # Linux + Windows desktop apps + server binaries
make wails-config # say which webkit ABI and Go toolchain the build will use
Two things are detected rather than asked of you, because both fail with errors that name the wrong culprit:
- webkit2gtk 4.1 is used when present. The old 4.0 ABI is deprecated, and a
leftover 4.0 package on a current distro links a stale libjxl and dies at the
link step with
undefined reference to 'JxlDecoderCreate@JXL_0'. Force the old ABI withmake desktop WAILS_TAGS=webkit2_40if you really need it. - An experimental Go toolchain — one whose version carries an
-X:suffix, e.g.go1.26.5-X:nodwarf5— is swapped for the stock build of the same version. Experimental toolchains emit export data the x/tools pinned by Wails cannot read, and the build fails withinternal error: package "context" without types, which does not mention the toolchain. A stockgois left exactly as it is. Override withmake desktop WAILS_GOTOOLCHAIN=go1.25.0, or=localto force your default and see the raw error.
make wails-config prints both decisions, so a failure can be diagnosed without
reading the Makefile.
Frontend only (static SPA)
npm run build
Output in build/ — serve with any static file server.
Server binary (Go backend)
make backend # current platform
Output in dist/. The binary embeds the frontend and serves it alongside a CORS proxy.
It listens on 127.0.0.1:8080 by default. The proxy forwards requests on
behalf of the page it serves, so binding every interface would make it reachable
by anything on the network — that has to be asked for explicitly:
./juurakko # loopback only (default)
./juurakko --addr :8080 # every interface — needed in a container
./juurakko --allow-origin http://localhost:5173 # when a dev server serves the page
In a container, --addr :8080 is required: a process bound to 127.0.0.1 inside
a container cannot be reached through a published port.
Each run mints a proxy token, stamps it into the HTML it serves, and refuses any
/api/proxy request that does not present it. Nothing to configure — but it does
mean a page this binary did not serve cannot use the proxy.
Tests
make test-unit # vitest (unit + component tests)
make test-e2e # playwright (end-to-end tests)
make test # both
Plugin Architecture
PM tool integrations are implemented as plugins conforming to the PMPlugin interface in src/lib/plugins/interface.ts. Each plugin handles authentication, issue fetching, write operations, and link management for its specific PM tool.
| Plugin | Status |
|---|---|
| Forgejo | Included |
| GitHub | Included |
| GitLab | Soon(tm) |
| Taiga | Soon(tm) |
| OpenProject | Soon(tm) |
| Redmine | Soon(tm) |
Tech Stack
- Svelte 5 + TypeScript
- @xyflow/svelte for the canvas
- dagre for graph layout
- Dexie for IndexedDB persistence
- Wails for the native desktop app
- Go for the backend and desktop proxy
- Vitest + Playwright for testing
Contributing
Contributions are welcome! Juurakko is open core, so contributing requires a DCO
sign-off and a one-time Contributor License Agreement (CLA) acceptance — both are quick.
See CONTRIBUTING.md and CLA/icla.md for details.
License
Juurakko (this FOSS core) is licensed under the GNU Affero General Public License v3.0
only (AGPL-3.0-only) — see LICENSE.
Juurakko is open core: the commercial editions (Juurakko Pro, Juurakko Enterprise) build on this core under separate commercial terms. Contributions are accepted under the CLA (see Contributing), which is what allows them to be included in those editions while contributors keep their copyright.