Files
forge/CHANGELOG.md
T
Dmytro Tkachenko 28d817ebe9 Init
2026-08-29 11:59:28 +03:00

8.3 KiB
Raw Blame History

Changelog

All notable changes to FORGE are documented here. Format based on Keep a Changelog; this project uses Semantic Versioning.

[2.3.0] — 2026-08-27

Added

  • Jira status durations (chart #17) — a new "Jira status durations (avg days)" chart on the Active-stats page: average time each Jira workflow status is held, in the board's column order, min-2-tickets. Server endpoint GET /api/analytics/jira-durations (PM+) aggregates jira.statusDurations (ms) across tickets.
  • The extension's Jira collector now fetches each issue's changelog (expand=changelog) and computes statusDurations (time per status) + movements ({at, who, from, to}), sent inside the jira object.
  • Seed enrichment: statusDurations + the Jira workflow column order are ingested from the dump's jira_board_state (so the chart is populated before any live sync — 73 seeded tickets carry durations). JiraInfo type extended with statusDurations/movements.

[2.2.0] — 2026-08-27

Added

  • Jira sync in the extension (per the sync ADR). One "Sync now" now refreshes SNOW then Jira: SNOW stays as the in-page same-origin session collector → /api/sync; Jira is pulled by a new service-worker collector via direct REST (/rest/agile/1.0/board/{id}/issue) authenticated with a Jira API token — Basic (email+token, Cloud) or Bearer PAT (Server/DC, e.g. support.dataart.com). Issue links are built as <baseUrl>/browse/<KEY> (custom Jira domains supported).
  • New extension options: Jira base URL, email, API token/PAT, and board id(s).
  • New server endpoint POST /api/sync/jiraattach-only: updates only the jira JSONB (merged) + jira_key on existing tickets, keyed by RITM number; never touches status/state/assignee/activity (avoids the ticket-upsert clobber). Token-authed. Jira RITM↔issue resolved via customfield_26001 or a RITM\d+ regex; Jira failures are best-effort and never fail a successful SNOW sync.

Added

  • Polished Excel export — the board's Excel export is now filterable and readable: the ticket Number is a clickable ServiceNow hyperlink (a real OOXML hyperlink relationship — locale-proof, unlike a HYPERLINK() formula which breaks in ;-locale Excel), auto-filter on every column, zebra-striped rows, taller rows + wider columns, a frozen indigo header, right-aligned numbers, #,##0 cost, short dates, and a dated filename (forge-active-tickets-YYYY-MM-DD.xlsx). The standalone Link column was folded into the Number cell. (auto-filter + hyperlinks injected via fflate.)
  • App favicon (indigo snowflake) + theme-color.
  • A proper Excel-brand button icon (green tile) replacing the placeholder glyph.

Changed

  • RITM number links out to ServiceNow in the ticket table + board cards (new tab).
  • Deploy: ported Husky's push-to-nas.sh + on-NAS deploy.sh (SSH key pinning, openrsync→tar fallback, Synology PATH/sudo, health poll, forge-db volume preserved on --fresh); macOS AppleDouble (._*) files excluded from sync/build/tests.

Dependencies

  • Added fflate (xlsx auto-filter post-processing). write-excel-file pinned at 2.x (v4 drops the default export + still has no hyperlink support).

2.0.0 — 2026-08-27 · FORGE 2.0

The analytics release. FORGE grows from a ticket board into a full ServiceNow analytics portal ported from the Let it Snow Chrome extension, with role-based access, admin tooling, and the complete statistics suite.

Added

  • Full analytics data ingest. The seed now loads the entire analytics_data master (954 ticket records) merged with the operational cache, plus SLA norms, FX rates, size thresholds, brand palette, and the colleague roster. New ticket columns (all additive): currency_code, opened_by, opened_date, closed_date, to_do_at, in_uat_at, jira_key, ticket_year, size, po_number, invoiced. A reproducible dump-to-archivesreseed pipeline regenerates seed data from a storage dump. app_config key/value table for norms/thresholds/palettes.
  • Server analytics engine (server/analytics.ts, server/insights.ts): /api/analytics/overview, /api/analytics/sla, /api/insights, /api/config.
  • Overall statistics page — year-overlay grouped bars (opened/closed/revenue, bars↔line + YoY%), a Cost↔Tickets toggle, a ticket-share donut (#/% + top-N), brand→market and requester→brand drill-downs, KPI tiles, lifetime histogram.
  • Active statistics page — by-status, age distribution, opened-per-month, median days-in-status, by-brand.
  • PM KPIs — SLA page — six PM×size heatmaps (TTFR, PM response, avg-close, OTD, assign, preview) scored against per-size norms, green/red vs target.
  • PM Insights page — problem/alert KPIs over the active backlog (unassigned, on-hold, WIP-stalled, customer-replied, awaiting, lifetime, inactive), Jira-breach and client-owed rules, waiting-PO with L1/L2/L3 escalation, revenue-at-risk, and a per-PM roll-up. (Rev-at-risk matches the initial app's own figure within rounding.)
  • Board redesign — 7-state kanban (Unassigned → Open/Assigned → On Hold → WIP → Customer replied → Awaiting) with the WIP→"Customer replied" pseudo-status, SLA subtitles, per-column counts, brand/market/PM filters, board/list toggle, and a ticket detail modal.
  • Role-based access control — four roles (Viewer, PM, Project Leadership, Admin) enforced server-side per route; the client hides nav/pages above a user's role. Only admins can create admins.
  • Admin page — user management (Project Leadership+) and API-token management (Admin only): create/list/revoke fg_… sync tokens from the UI.
  • Filtered Excel export — the board's ⭳ Excel button exports the currently filtered tickets as a styled .xlsx (branded indigo frozen header, per-column widths, right-aligned numbers, #,##0 cost, short dates, grid borders).
  • Finance ingest — cost + PO + invoiced per ticket from the finance sheet, enriching active tickets with cost/size and powering waiting-PO.
  • Config bundle exposed via /api/config (brand colours, colleagues, norms, FX).

Changed

  • All analytics pages are full-width (removed the 1280px cap).
  • /api/tokens is now gated by the admin session role instead of an ADMIN_KEY header. The mint-token CLI is unchanged.
  • Non-destructive sync upsert: a thin sync no longer nulls seeded-rich fields (COALESCE/CASE preserve brand/market/description/jira/activity/analytics).

Fixed

  • due_date timezone off-by-one (emit local YYYY-MM-DD, not toISOString()).
  • Activity render-crash vector (ingest sanitizes activity entries; parseDate guards).
  • Seed "active wins" ordering on tickets present in both archives.
  • Ticket-share donut used a truncated distribution (center 375); now the full 966.

Security

  • Read-API authentication (session, username+password, bcrypt, Postgres session store).
  • Least-privilege database role (forge_app, not a superuser) owns the app tables.
  • API tokens: fg_<id>_<secret>, only the SHA-256 stored, constant-time verify, revocable; token_hash never leaked by the list endpoint.
  • RBAC hardening (post-audit): only an admin can delete an admin; the last admin cannot be deleted (lockout guard); deleting a user purges their sessions; the session id is regenerated on login (anti session-fixation); delete of a missing user returns 404.

1.0.0 — 2026-08-27

Initial full-stack scaffold, ported from the Let it Snow Chrome extension onto the Husky repo list template.

Added

  • Vite + React 18 + TypeScript client (SCSS modules, react-router) with a Sidebar/ TopBar layout; Active board, Closed, and basic Statistics pages.
  • Express + TypeScript server on Postgres (forge); self-bootstrapping schema (initDB) that seeds bundled ticket archives on first boot.
  • REST API: /api/tickets, /api/tickets/:number, /api/stats, /healthz, and a token-authed /api/sync ingest.
  • Chrome sync extension ("FORGE Snow Sync") — reads active RITM tickets from the ServiceNow Table API and pushes them to the portal with a bearer token.
  • Multi-stage Dockerfile + docker-compose (bundled Postgres) targeting forge.mycloud.dp.ua; README + SETUP docs.