github Leantime/leantime v3.10.0
Leantime v3.10.0

latest release: latest
4 hours ago

Version: 3.10.0

Highlights

Telegram Messenger Integration

Connect Leantime to Telegram to receive rich, auto-detected task notification cards directly in your chats, keeping your team informed without leaving their messenger. (#3726)

Redesigned Goals with Multi-Milestone Support

The goal dialog has been rebuilt with a split layout, monitor/manage tabs, and inline updates, and a single goal can now link to many milestones with a new chip UI and milestone rollup progress. (#3739, #3688, #3687, #3690)

New Features

  • Period-Based Status Reports - Added period-based status report screens backed by a shared report engine and a period-aware actuals window for resources. (#3643, #3714)
  • Mobile SSO - Introduced a generic OIDC mobile SSO bridge with one-time-code to bearer-token exchange, a public /status discovery endpoint advertising auth methods, and AdvancedAuth gating. (#3637, #3662, #3664, #3711)
  • User Capacity Fields - Added weekly hours and employment type to user profiles for better resource planning. (#3653)
  • Resources Contract - Added a new Resources gateway surface with value objects, registry, and shared Blade primitives, including current-week actuals on the resource summary. (#3645, #3669)
  • Canvas Events - Added a CanvasItemUpdated event as a foundation for change propagation. (#3691)

Bug Fixes

  • Routing - Resolved plugin controllers whose folder name has an inner capital letter. (#3773)
  • Ideas on Kanban - Fixed the "Edit" option for Ideas not working in the Kanban view. (#3752)
  • Sidebar Projects - Admins and owners now see all projects they have access to, fixing an empty project sidebar. (#3710)
  • Batch Fixes - Resolved a set of five reported bugs across the app. (#3738, #3632, #3685, #3636, #3692, #3746)
  • Upgrades - The installer now self-heals a missing zp_access_tokens table and a stale session-cached db-version so updates can't get blocked. (#3745, #3735)
  • Blueprints - Restored board and item deletion by keeping the id on delete-confirm forms. (#3705)
  • Files - File names now display in full with a title tooltip instead of being truncated to 10 characters. (#3734)
  • Reports - The report deck no longer errors when a projectId is omitted, program supply now reflects capacity rather than booked hours, and fixed an HTML leak, decimal count, and empty burndown. (#3715, #3672, #3665)
  • Telegram - Fixed a status handling bug so "Done" (status 0) is evaluated correctly. (#3747)
  • Editor - Restored Backspace deletion of empty lines in the editor. (#3629)
  • Timesheets - A user's own general-work (no-project) time now appears in account reads. (#3642)
  • Tickets - Archived-project tickets are excluded from open ticket lists, status→Done history is logged with an accurate "last updated" time, and ticket parents are preserved on failed new-ticket submissions. (#3639, #3638, #3650, #3641)
  • Onboarding - First-login completion now persists even when the user can't create tickets. (#3684)
  • Content Templates - Fixed a slug bug, status label rendering, and typos. (#3644)
  • Goals - Fixed invalid Goal input markup by using proper name=value pairs. (#3634)

Improvements

  • Unified UI - Consolidated to one table design, one stat tile, and one period picker with report and button polish. (#3771)
  • Navigation & Chrome - Standardized on the floating pill horizontal tab group, added a glass pageheader and gradient tabs, a Tasks board summary, a reusable subject switcher, and a single document-page mode. (#3728, #3716, #3680, #3676, #3677, #3717)
  • Stakeholder Report - Refined the stakeholder report with a doc-shell header. (#3707)
  • Performance - Batched capacity analyzer ticket reads into a single query. (#3697)
  • Assets - CSS bundles are now cache-busted using the build mtime. (#3724)

Security

  • JSON-RPC Authorization - Closed an account-takeover chain: any authenticated user could call the onboarding service over JSON-RPC to set another account's password and role, activate it, then disable its 2FA. The onboarding and 2FA services are no longer RPC-reachable, and a sweep of the remaining unguarded @api methods closed marketplace license-key exposure, cross-user dashboard/widget writes, unauthorized ticket-dependency rewrites, mention forgery, and installer/scheduler/queue triggers. (#3797)
  • Components - Escaped the statTile sub slot by default; markup now has to opt in via HtmlString. (#3774)
  • Open Redirects - Closed open redirect vulnerabilities in the TwoFA verify and POST flows and the Login POST handler. (#3770, #3750, #3658)
  • Cross-Site Scripting - Escaped user-controlled group labels at the source and stripped markup from board/timeline tab aria-labels. (#3767, #3748, #3768)
  • Blueprints - Validated the import file path to prevent SSRF/LFI and guarded phar:// plugin probes against open_basedir violations. (#3656, #3693, #3762)
  • Access Control - Added a project ownership check to getMilestone() to prevent IDOR. (#3657)
  • OIDC - Hardened the mobile SSO flow with a lock-guarded one-time-code consume, TTL, throttling, and atomic consumption. (#3662, #3663)
  • Invitations - Stopped invite-email spam by sanitizing names and adding rate limits. (#3661)
  • npm Advisories - Cleared all nine high-severity npm advisories and a critical websocket-driver finding. (#3769, #3679, #3667)

Localization

  • Indonesian - Added an Indonesian (id-ID) translation. (#3764)

Dependency Updates

  • Bumped the plugins submodule to current main. (#3742, #3719)

What's Changed

🎉 New Features

  • feat(tickets): getMyClosedTicketsForDate @api + status-change primitive by @gloriafolaron in #3631
  • feat(oidc): mobile SSO bridge — one-time-code → bearer token exchange (generic OIDC) by @gloriafolaron in #3637
  • feat(status): public /status discovery endpoint — advertise auth methods for mobile SSO by @gloriafolaron in #3664
  • feat(resources): ResourceSummary carries current-week actuals by @gloriafolaron in #3669
  • feat(goals): activate the goal↔milestone edge model — helpers, dual-write, edge reads (PR 2) by @gloriafolaron in #3687
  • feat(goals): multi-milestone chip UI — one goal, many milestones (PR 3) by @gloriafolaron in #3688
  • feat(integrations): Add Telegram Messenger integration with auto-detection & rich task notification cards by @maruf-pfc in #3726

🐞 Bug Fixes

  • fix(editor): delete empty lines with Backspace in the tiptap editor by @jeppekroghitk in #3629
  • fix(projects): getProjectsByUserActivity excludes archived projects (projectStatus 'open') by @gloriafolaron in #3638
  • fix(tickets): exclude archived-project tickets from getAllOpenUserTickets by @gloriafolaron in #3639
  • fix(oidc): lock-guarded consumeCode — close the double-mint race (Copilot follow-up to #3662) by @gloriafolaron in #3663
  • fix(reports): 3 audit findings — HTML leak, decimal count, empty burndown by @gloriafolaron in #3665
  • fix(projects): admins/owners access all projects in getProjectsUserHasAccessTo (fixes empty sidebar) by @gloriafolaron in #3710

Other Changes

  • Swap invalid "if" for valid name=value pairs in Goal input by @komali2 in #3634
  • fix(timesheets): show a user's own general-work (no-project) time in account reads by @gloriafolaron in #3642
  • fix(content-templates): polish batch — Phase 4 slug bug, status label rendering, typos by @gloriafolaron in #3644
  • fix(oidc): mobile SSO hardening — TTL, throttle, body-only reads, atomic consume (follow-up to #3637) by @gloriafolaron in #3662
  • feat(core): Resources contract surface — gateway, registry, value objects, shared blade primitives by @gloriafolaron in #3645
  • fix(tickets): assign ticketParents on NewTicket POST validation-failure path (#3640) by @marcelfolaron in #3641
  • feat(tickets): getMyClosedTicketsForRange for period close-lists by @gloriafolaron in #3647
  • fix(tickets): record status→Done in history + report real last-updated by @gloriafolaron in #3650
  • fix: add project ownership check to getMilestone() to prevent IDOR (CWE-639) by @javokhir-sec in #3657
  • fix(security): stop invite-email spam via unsanitized names + missing rate limits by @marcelfolaron in #3661
  • fix(security): resolve critical npm audit failure (websocket-driver) by @marcelfolaron in #3667
  • feat(tickets): getMyCommentedTicketsForRange for Progress "Supported" by @gloriafolaron in #3649
  • docs(oidc): reword consumeCode docblock to lead with the lock, not Cache::pull by @gloriafolaron in #3666
  • feat(reports): period-based status report screens + shared report engine by @marcelfolaron in #3643
  • feat(users): weekly_hours + employment_type on user (Slice 1) by @gloriafolaron in #3653
  • feat(projects): additive addUserToProject() service method by @gloriafolaron in #3671
  • fix(reports): program supply = capacity, not booked hours by @gloriafolaron in #3672
  • fix(security): resolve new high npm audit findings (brace-expansion, shell-quote) by @marcelfolaron in #3679
  • fix: validate file path in Blueprints::import() to prevent SSRF/LFI (CWE-918) by @javokhir-sec in #3656
  • fix(blueprints): repair unit suite broken by import() path validation (#3656) by @marcelfolaron in #3693
  • fix(help): readonly users can't complete first-login onboarding (Fixes #3683) by @marcelfolaron in #3684
  • design(chrome): pageheader is a glass card (app-wide header modernization) by @gloriafolaron in #3676
  • design(chrome): extract subjectSwitcher component + migrate To-Dos by @gloriafolaron in #3677
  • design(chrome): nav-bar redesign — glass pageheader, gradient tabs, Tasks board summary by @gloriafolaron in #3680
  • perf(reports): batch capacity analyzer ticket reads into one query by @gloriafolaron in #3697
  • feat(oidc): gate the mobile OIDC bridge behind AdvancedAuth by @gloriafolaron in #3711
  • design(reports): stakeholder report — doc-shell header + refinement pass by @gloriafolaron in #3707
  • feat(goals): milestone rollup + getMilestonesByGoal @api for mobile Progress (PR 5) by @gloriafolaron in #3690
  • feat(canvas): CanvasItemUpdated event (phase-2 propagation foundation) by @gloriafolaron in #3691
  • style(reverse-wizard): move the reverse-flow stylesheet into the core bundle by @gloriafolaron in #3712
  • style(reverse-wizard): rw-guide-sub class for muted guide sub-paragraphs by @gloriafolaron in #3713
  • feat(resources): period-aware actuals window on the ResourcesGateway contract by @gloriafolaron in #3714
  • fix(reports): stakeholder deck no longer 500s when the caller omits projectId by @gloriafolaron in #3715
  • feat(components): navigation.tabs — one ARIA tab-group + RA chrome joins the core bundle by @gloriafolaron in #3716
  • feat(css): body.lt-doc-page — one document-page mode for doc-shell pages by @gloriafolaron in #3717
  • chore: bump plugins submodule to current main by @gloriafolaron in #3719
  • style(css): drop the orphaned ra-page-active pageheader chrome by @gloriafolaron in #3723
  • fix(assets): cache-bust the css bundles with the build mtime by @gloriafolaron in #3724
  • test(install): cover update_sql_30524 + pin the TrackedBy edge as informational by @gloriafolaron in #3725
  • design(nav): the floating pill group is THE horizontal tab standard by @gloriafolaron in #3728
  • fix(goals): harden the goal↔milestone edge model (audit follow-up) by @gloriafolaron in #3729
  • test(goals): pin the repository-level goal↔milestone link contracts by @gloriafolaron in #3730
  • fix(core): self-heal the session-cached db-version after an update by @gloriafolaron in #3735
  • feat(goals): goal dialog v2 — split layout, monitor/manage tabs, inline updates by @gloriafolaron in #3739
  • fix(files): show full filename with title tooltip instead of 10-char truncation by @marcelfolaron in #3734
  • fix(blueprints): delete-confirm forms drop the id — board/item delete silently no-ops (Fixes #3696) by @marcelfolaron in #3705
  • fix: use resolveSafeRedirect() in Login POST handler to prevent Open Redirect (CWE-601) by @javokhir-sec in #3658
  • chore(plugins): bump the submodule to plugins main (84 commits) by @marcelfolaron in #3742
  • fix(install): self-heal a missing zp_access_tokens so 30504 can't block upgrades by @marcelfolaron in #3745
  • fix: batch of five reported bugs (#3738, #3632, #3685, #3636, #3692) by @marcelfolaron in #3746
  • fix(telegram): handle status 0 (Done) without empty() evaluation bug by @maruf-pfc in #3747
  • Add Indonesian (id-ID) translation by @henryust12 in #3764
  • fix: guard phar:// plugin probes against open_basedir violations by @plugmind-dev in #3762
  • fix: "Edit" option for "Ideas" doesn't work with Kanban by @Roshan931 in #3752
  • fix(tickets): escape user-controlled group labels at the source (XSS) by @marcelfolaron in #3767
  • fix(tickets): strip markup from the board/timeline tab aria-labels (#3748) by @marcelfolaron in #3768
  • changing rendering label to unescaping icon code by @mborecki in #3763
  • fix(2fa): validate redirect in TwoFA Verify to close open redirect (#3741) by @chiliec in #3750
  • chore(deps): clear all 9 high-severity npm advisories by @marcelfolaron in #3769
  • fix(2fa): close the POST half of the TwoFA open redirect by @marcelfolaron in #3770
  • fix(ui): one table design, one stat tile, one period picker; report + button polish by @marcelfolaron in #3771
  • fix(routing): resolve plugin controllers whose folder has an inner capital by @marcelfolaron in #3773
  • fix(components): escape statTile's sub by default, opt into markup via HtmlString by @marcelfolaron in #3774
  • chore(plugins): bump the submodule to main for 3.10.0 by @marcelfolaron in #3775
  • fix(api): close the JSON-RPC account-takeover chain and sweep unguarded @api methods by @marcelfolaron in #3797
  • Release v3.10.0 by @marcelfolaron in #3772

New Contributors

Full Changelog: v3.9.8...v3.10.0

Don't miss a new leantime release

NewReleases is sending notifications on new releases.