Skip to content

Latest commit

 

History

History
110 lines (91 loc) · 6.29 KB

File metadata and controls

110 lines (91 loc) · 6.29 KB

Extraction

Where this code came from, what was cut at extraction time, and what residual UI leftovers remain. Written down because a reader deserves to know the UI was battle-tested before the local server existed.

Current product state (sync, write-through, feed, MCP, snapshot, plugins, and so on) lives in STATE_OF_PLAY.md and ROADMAP.md. This page is the extraction history, not the inventory of what works today.

Origin

The web application in web/ was built as an internal tool inside a company monorepo: a Svelte 5 SPA sitting on a Django backend that already mirrored Jira into PostgreSQL for other purposes. It had been in daily use by a product team against a real backlog of roughly ten thousand issues.

At extraction time that is why the UI was mature — virtualized list, saved views, keyboard triage, ADF rendering, inline write-through — while the server in this repository started as a skeleton. The extraction kept the client and threw away the backend, because the backend was inseparable from the company's other systems. The local Go server, sync, and agent surfaces have since been built out (see STATE_OF_PLAY).

What the internal backend provided

Capability Fate in gadak
Jira mirror in PostgreSQL, synced by cron Reimplemented as a local SQLite mirror synced by gadak sync
Derived fields (reopen counts, status timestamps, priority rank) Reimplemented, with site-specific naming rules replaced by status categories
Full-text search over descriptions and comments Reimplemented on FTS5
Write proxy to Jira with per-user credentials Reimplemented with credentials in a local config file
Attachment caching in S3 with presigned URLs Replaced by a local on-disk cache (internal/attachcache) filled on demand
Team directory (people, parts, aliases, avatars) Cut. Members are now derived from assignees and reporters in the mirror
Team/part taxonomy grouping Cut. The config keys remain so an organization can supply its own labels
Deployment state per issue, from a CI/CD index Cut
Pull-request links per issue Cut
Test-management (Qase) context per issue Cut
Personal activity feed and Web Push Cut from the company backend. A local watch-based feed later shipped in-core; Web Push (VAPID) remains deferred — see ROADMAP
Multi-viewer presence over WebSocket Cut. Meaningless in a single-user local tool
Company SSO and session auth Cut. There are no gadak accounts; identity is the stored Jira credential only
Email/password login dialog, gadak_token localStorage, Authorization: Token Cut. Frontend leftovers from the internal SSO; writes gate on credential settings alone
Data-quality audit endpoint Cut

What was scrubbed

The extraction had to remove every trace of the originating installation. Verified absent from web/, tools/, and the docs:

  • Company and product names, internal domains, and the internal Jira site URL
  • Internal email addresses (placeholders are now you@example.com)
  • Jira project keys that were hardcoded in the built-in view presets
  • Team and part identifiers used as grouping keys and avatar colors
  • Internal workflow status names used to detect resolution and reopening
  • Internal deployment-pipeline vocabulary
  • The internal deployment's base path, baked into the bundle, the manifest, and the service worker scope
  • An internal runbook, including an S3 backup bucket and an AWS profile name

Everything installation-specific now arrives at runtime through config.json. No custom field ids are committed: the internal version hardcoded three of them in its field-edit allowlist, and that allowlist is now empty by default, which simply hides the inline editor until an operator configures it.

Constitution Article 7 exists to keep this true. A leak here is not a style issue; it is the failure mode that makes a public repository unpublishable.

Behavior changes forced by generalization

These are places where the internal rule was wrong outside its own installation, so gadak uses a different one:

  1. Reopen detection. The internal version matched status names ("Reopened", and its Korean translation). gadak counts transitions from a done-category status to a non-done one, which is stable across every site and every account language.
  2. Resolution detection. Same problem, same fix: category, not name.
  3. Staleness. The internal version read a working_hours_in_status column that, on inspection, no code ever populated — the "stale" view was reading a permanent zero. gadak computes staleness from status_changed_at with a configurable threshold, and the dead column is not carried over.
  4. Built-in views. Presets that filtered on internal project keys, status names, and part groupings are replaced by six presets built only on axes that mean the same thing everywhere.
  5. Attachment URLs. The client validates media URLs against an exact path shape before using them as image sources. That check now derives its prefix from the configured API base while remaining an exact-shape allowlist, because loosening it would be an XSS hole.

Still to do

  • PrList, DeployTimeline, and QaImpact are still in the tree. Done via feature flags, same as T0.9: PrList / DeployTimeline sit behind features.deploy, QaImpact behind features.qa. They stay in the tree so a tenant that has the data can switch them on.
  • The UI is Korean-only. Done: the copy is English-first with Korean kept as a locale (web/src/lib/i18n/). Source comments are still partly Korean; translating them is cosmetic, not blocking.
  • The group-taxonomy field carried its originating team's name. Done: renamed to the neutral team_group across the API, client types, and view config before the first stable release of the API contract.

Provenance of the demo data

The public demo data is not derived from the originating installation. It is generated from scratch against a personal Jira Cloud site with three fictional products, using go run ./tools/seed-demo. No real issue text, customer, or person appears in it. The snapshot that ships in examples/ is scanned for credential-shaped strings before it is committed.