Files
forge/CHANGELOG.md
T

156 lines
8.8 KiB
Markdown
Raw Normal View History

2026-08-29 11:59:28 +03:00
# Changelog
All notable changes to **FORGE** are documented here.
Format based on [Keep a Changelog](https://keepachangelog.com/); this project uses
[Semantic Versioning](https://semver.org/).
## [2.3.1] — 2026-08-29
### Changed
- **PM Insights — collapsible sections.** The **Alert categories** and **Watch list**
sections are now accordions: each heading is a button (chevron + a category-count
badge, `aria-expanded`/`aria-controls`) that collapses/expands its card grid. Both
default to open; the per-card ticket expand and the **Per-PM roll-up** table are
unchanged. Adds a `ChevronIcon` (rotates with the section) and a `.grid[hidden]` rule
so a collapsed grid actually hides.
2026-08-29 11:59:28 +03:00
## [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/jira`** — **attach-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-archives``reseed` 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.
[2.0.0]: #200--2026-08-27--forge-20
[1.0.0]: #100--2026-08-27