# Changelog All notable changes to santi are listed here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow [Semantic Versioning](https://semver.org/). Until 1.0.0 the HTTP API may change between minor versions. This file covers the server and the web UI together; `web/CHANGELOG.md` points here until the UI moves to its own repository. ## [Unreleased] ## [0.26.0] - 2026-10-22 > Pricing on the landing page, with self-hosting free and open source first. ### Added - **Pricing** on the landing page: self-hosting first, free and open source with every feature; a free hosted plan; and the Team plan at US$ 19 a month per workspace (US$ 190 a year), not billed yet. The stale "Coming next" block is gone and the FAQ answers about price and roadmap are current. ## [0.25.1] - 2026-10-21 > The website moves to getsanti.app and the README puts self-hosting first. ### Changed - The site lives at [getsanti.app](https://getsanti.app); `www` redirects to it. - The README is a short landing page with self-hosting first; configuration, upgrades, backups and restore, reverse proxy and importing moved to [docs/self-hosting.md](docs/self-hosting.md), development setup to CONTRIBUTING.md and plans to [docs/pricing.md](docs/pricing.md). ### Fixed - The landing page, `llms.txt` and the terms of use now state the AGPL-3.0 license instead of MIT or Apache-2.0. ### Upgrade notes - The published image is `linux/amd64` only; on ARM hosts pull it with `--platform linux/amd64` first. ## [0.25.0] - 2026-10-21 > santi is now AGPL-3.0 with a trademark policy, on refreshed dependencies. ### Changed - **License**: santi is now licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only), with a [trademark policy](TRADEMARK.md) for the name and logo (D61). - Web dependencies updated within the bundle budget (TanStack Query and Router, Prettier 3.9, ESLint, typescript-eslint and others); React 19.3, zod 4.6, react-hook-form 7.90, lucide-react 1.59 and sonner 2.0.8 are held back until there is room (SAN-204) or a fix. - CI actions updated (checkout 7, docker login 4, buildx 4, build-push 7, pnpm setup 6) and base images refreshed (busybox 1.38, distroless); the image stays on Node 24 LTS. ### Upgrade notes - Self-hosting and internal use are unaffected. If you offer a modified santi to others over a network, publish your changes under AGPL-3.0. Versions up to 0.24.1 stay available under MIT OR Apache-2.0. ## [0.24.1] - 2026-10-21 > A security patch with updated TLS and archive dependencies, HSTS, and one search for the link picker. ### Security - Updated `rustls-webpki`, `webpki-roots`, `webpki-root-certs` and the `zip` crate used by the API docs to fix RUSTSEC-2026-0381, -0382, -0383, -0367, -0368 and -0369. CI now fails on any open RustSec advisory, every third-party action and base image is pinned, and workflow tokens are read-only by default. - Every response sends `Strict-Transport-Security` (browsers ignore it over plain HTTP) and `X-Frame-Options: DENY`. ### Changed - The linked-issues picker searches all your projects in one request (`GET /api/me/issues/search`). ### Upgrade notes - New API: `GET /api/me/issues/search?q=&limit=&include_archived=`. ## [0.24.0] - 2026-10-21 > Linked issues, restore from an export, password and sessions on your account, and a server ready to be measured. ### Added - **Linked issues**: blocks / is blocked by, relates to, duplicates, clones, shown on both issues and grouped by relation; add with "Link issue" or `l`, remove from either side. Cards and backlog rows show **Blocked** while a blocker is not done. Links to projects you cannot open stay hidden. CLI `santi issues link` / `unlink`, MCP `link_issues` / `unlink_issues`. - **Restore a project from a santi export**: `santi restore [--project KEY]` (and `POST /api/projects/restore`) recreates the board, statuses, sprints, issues with their keys and comments. The restorer is the only member; other people are listed so you can invite them again. Attachments, notifications and history are not in an export. - **Change your password** from the account page or `santi password`; every other session is signed out and earlier reset links stop working. - **Active sessions** on the account page: device, signed-in date and last activity, sign out one or all others. Only a short device label is stored, never the browser string or an address. - **Request logs**: one JSON line per request with route, status, latency and request id (`RUST_LOG`, `SANTI_LOG_FORMAT`). - **Scale strategy** in `docs/specs/scale-strategy.md`, with targets for an online team, a self-hosted team and a large company. ### Changed - Every date and time follows the time zone on your account, including the sprint dialog, comments and the home page groups. - Issue search uses its index on large projects; `SANTI-12` or `12` find that issue exactly (`SANTI-12` no longer also finds SANTI-120). - `/account` and board settings load less code up front. - The server answers 503 "busy" with `Retry-After` instead of hanging when a request, a query or the connection pool runs out of time. ### Upgrade notes - Migrations `0029_issue_links` and `0030_session_activity`. - New settings: `SANTI_REQUEST_TIMEOUT_SECS` (30), `SANTI_DB_STATEMENT_TIMEOUT_MS` (15000), `SANTI_DB_ACQUIRE_TIMEOUT_MS` (5000), `RUST_LOG` (info), `SANTI_LOG_FORMAT` (json). Logs are now JSON on stdout. - New API: `POST /api/projects/restore`; `GET/POST /api/projects/{key}/issues/{number}/links`, `DELETE …/links/{id}`; `POST /api/me/password`; `GET /api/me/sessions`, `DELETE /api/me/sessions[/{id}]`; `Card.blocked_by`. Any route may answer 503 `busy`. - Search: the `q` filter matches summaries, or an exact issue number given as `12` or `KEY-12`. ## [0.23.0] - 2026-10-21 > Dark theme, a People tab for leads, subtasks you update in place, and a published Docker image. ### Added - **Dark theme**: Light, Dark or System from the account page, applied before the first paint and saved on your account, so every browser you sign in to follows it. - **Account page** (the account menu item is now "Account"): edit your display name in place and pick your time zone from a searchable list; sprint dates, sprint reports, token and invite dates follow it. - **People tab** for every project: one row per person for the running sprint or the Kanban board, with done/total issues and points, a to do / in progress / done bar and "Stuck ×N" for work in progress with no update in 3 days. A row opens that person's issues, with a link to the board filtered to them. CLI `santi report people `, MCP `get_team_progress`. - **Unassigned filter**: a dashed avatar after the members on the board and backlog filter bars. - **Subtasks in the issue view** change status, priority and assignee in place, the header shows "N of M done" with a bar, and finishing the last open subtask offers to move the parent to Done. - **CLI paging**: `santi issues list` and `santi search` take `--cursor ` or `--all`. - **Docker image** published to `ghcr.io/emersonjds/santi` on every release; `compose.yaml` pulls it instead of building, `compose.build.yaml` builds your checkout. - **Pricing and sustainability** section in the README. ### Changed - Subtask chips on cards and backlog rows read done/total ("2 of 3 subtasks done"). - On a phone, backlog rows show one whole label plus "+N" instead of cutting labels mid-word. - The sidebar keeps the project key beside its name; the star has its own colour token. - A wrong JSON type for a field (`{"theme": 5}`) answers 422 naming the field, like a wrong value. - Importing an export with points on subtasks now says the points are not kept. - After a second deploy in the same tab, a page whose code moved reloads once instead of showing an error; Try again on that error reloads the page. ### Removed - `POST /api/projects/{key}/members`: it revealed which emails have accounts. Invite links are the way into a project. ### Upgrade notes - Migration `0028_user_preferences` adds `theme` and `time_zone` to accounts (no table rewrite). - `POST /api/projects/{key}/members` answers 405; use invite links. - `compose.yaml` now runs `ghcr.io/emersonjds/santi:${SANTI_VERSION:-latest}` and binds santi to 127.0.0.1. To build from source, add `-f compose.build.yaml`. Put an HTTPS proxy in front for any other host (the session cookie is `Secure`). - New API: `PATCH /api/me`, `GET /api/projects/{key}/people`, `unassigned=true` on board, backlog and search filters; `User` gains `theme` and `time_zone`. ## [0.22.0] - 2026-10-19 > A bell that tells you when someone mentions you, assigns you or comments on your issue. ### Added - **Notifications bell** in the top bar with the unread count (9+ above nine), refreshed every minute and when the tab comes back; it pauses while the tab is hidden. The panel (a sheet on phones) lists who did what on which issue, with an excerpt; a click opens the issue at the comment and marks it read. "Mark all as read" and "Load more". - **Events:** you were @mentioned in a comment or description, an issue was assigned to you, or someone commented on an issue you reported or are assigned to. Never for your own changes; one notice per person per change (assignment, then mention, then comment). Editing only notifies newly mentioned people. - **For you:** up to five unread mentions at the top. - **CLI:** `santi notifications [--unread] [--cursor ] [--limit ]`, `santi notifications read ` and `read --all`. **MCP:** `list_notifications` and `mark_notifications_read`. - **API:** `GET /api/notifications` (`cursor`, `limit`, `unread`, `kind`), `GET /api/notifications/unread-count`, `POST /api/notifications/{id}/read`, `POST /api/notifications/read-all`. ### Changed - Notifications hide when you leave a project or it goes to the trash, and go with a deleted issue, comment or account; they are kept for 90 days. - The CLI strips terminal control characters from names and text written by other people in notification lists. ### Upgrade notes - Migration `0027_notifications.sql` adds the `notification` table and its indexes; it runs on startup. Comment create and edit now run in one transaction with their notifications. ## [0.21.1] - 2026-10-19 > No more page that stops taking clicks after a quick confirm from a menu. ### Fixed - **Menus and dialogs:** a dialog opened from a menu and closed before the menu finished closing (for example a quick Delete confirm on a comment) could leave the whole page unclickable until a reload. Radix components are upgraded so the lock is always released. - **Tests:** the end-to-end specs wait for the comment editor and for the delete answer instead of racing them. ## [0.21.0] - 2026-10-19 > Files on issues: attach images and documents to an issue, a comment or a new issue. ### Added - **Attachments:** an Attachments section in the issue detail (dialog and full page). Attach with the button, drag and drop or paste an image; each file uploads with its own progress, Cancel and Retry. Images show as tiles with a viewer (arrows, swipe, Esc); other files as rows with size, uploader and date. Download and, for the uploader or an admin, Delete. - **Comments and new issues:** attach files while writing a comment (they upload right after it is posted and show under it) or in the create dialog (they upload right after the issue exists). - **Limits:** 25 MB per file, 100 per issue, 10 per upload. Images (PNG, JPEG, GIF, WebP), PDF, Office and OpenDocument files, TXT, CSV, MD and ZIP; the type is read from the file's bytes, so SVG, HTML and renamed files are refused. - **CLI:** `santi issues attach ... [--comment ]`, `santi issues attachments ` with `--download [-o ] [--force]` and `--delete [--yes]`. - **MCP:** `list_attachments`, `add_attachment` (local stdio only; files under the working folder or `SANTI_MCP_ATTACH_DIR`, never hidden files or the home folder), and `get_issue` lists files. - **API:** `POST/GET /api/projects/{key}/issues/{number}/attachments`, `GET` (with `?download=1` to save) and `DELETE …/attachments/{id}`. ### Changed - **Archived projects** keep listing, previewing and downloading files; attach and delete are locked. Trashed projects hide them; purge, issue delete, comment delete and account erase remove the stored files. - **Signing out** clears any upload still listed in the tab. - **A file dropped outside a drop zone** no longer replaces the page. - **Upload buttons** (Retry, Remove, Cancel) are named by file for screen readers. ### Upgrade notes - Migration `0026_attachments.sql` adds the `attachment` table and swaps the `issue_comment` issue index for a unique `(issue_id, id)` (brief lock on that table); it runs on startup. - Storage: set all of `SANTI_S3_BUCKET`, `SANTI_S3_ENDPOINT`, `SANTI_S3_REGION`, `SANTI_S3_ACCESS_KEY_ID`, `SANTI_S3_SECRET_ACCESS_KEY` for an S3-compatible bucket (path-style; a partial set stops the server), or none to keep files on disk at `SANTI_ATTACHMENTS_DIR` (default `./data/attachments`; the image uses `/data/attachments`). On Railway use a Storage Bucket: the container disk is lost on redeploy. A bucket lifecycle rule `AbortIncompleteMultipartUpload` (1 day) is recommended. - The page CSP `img-src` includes the bucket endpoint when S3 is configured. ## [0.20.0] - 2026-10-19 > See every live invite link, who joined with it, and stop a leaked one. ### Added - **Invite links on the Members page (admins):** each live link shows its role, spots used, when it expires, who made it and who joined with it. Revoke ends a link at once (it then reads as expired); people who already joined stay in the project. - **CLI:** `santi invites ` and `santi invites revoke [--yes]` (asks first). - **MCP:** `list_invites` and `revoke_invite`. - **API:** `GET /api/projects/{key}/invites` and `DELETE /api/projects/{key}/invites/{id}` (admins; another project's or an ended invite is 404). ### Fixed - **Invites:** an accept that started just before a revoke can no longer use the revoked link. ### Upgrade notes - Migration `0025_invite_created_at.sql` adds `invite.created_at` (default `now()`) and fills it for existing invites as their expiry minus 7 days; it runs on startup. ## [0.19.0] - 2026-10-19 > One invite link for the whole group: up to 50 people join with it, each one recorded. ### Added - **Group invite links:** the Invite dialog asks "How many people" (1–50, default 1). Each person who joins takes one spot; the join page shows "N of M spots left". People accepting at the same time never take more spots than the link has. Someone already in the project takes no spot. - **Account export** lists the invite links the account joined with (project and date). ### Changed - **Admin invite links** are for one person only; a link for more people adds members. - **Rejoining with the same link** after leaving or being removed is refused with "You already joined with this link. Ask an admin for a new invite." - **Account deletion** also forgets which invite links the account joined with. - **Invite dialog:** a failed request (network) now shows an error instead of nothing; the description no longer says each link works once. - **API:** `CreateInvite.max_uses` (optional, 1–50), `Invite.max_uses`, `InvitePreview.max_uses` and `spots_left`; accept can answer 409 `invite-already-used-by-you`. ### Fixed - **Tests:** the reset link expiry is stored at the database's microsecond precision, so the 0.18.0 check passes on Linux too. ### Upgrade notes - Migration `0024_group_invites.sql` adds `invite.max_uses` (default 1, so existing links work as before) and the `invite_use` table with its index; it runs on startup. - API clients: the new fields are additive; old clients keep creating single-use links. ## [0.18.0] - 2026-10-19 > A forgotten password is no longer a dead end: the server operator sends a one-time reset link. ### Added - **Password reset link:** the `reset-link ` command prints a one-time link (valid 24 h, single use, only its hash stored; a new link replaces the previous one). The person opens `/reset/`, chooses a new password and lands signed in. Every other session of the account ends; API tokens stay. Generating a link does not change the password. Unknown, used and expired links look the same. No email needed. - **API:** `GET` and `POST /api/password-resets/{token}` (public, rate limited per address like invite accept). ### Changed - **Password fields:** 16 px text on phones and a 44 px show/hide button, on sign-in and sign-up too. - **Database connections** can use TLS (`sslmode=require` in `DATABASE_URL`); without `sslmode` nothing changes. - **Account deletion** also removes the account's pending reset link. ### Upgrade notes - Migration `0023_password_resets.sql` adds the `password_reset` table; it runs on startup and only creates a new table. - To reset someone's password on a hosted instance, run the command from a checkout against the database's public URL: `DATABASE_URL='?sslmode=require' SANTI_PUBLIC_URL= cargo run -p santi-server --bin reset-link -- `. ## [0.17.1] - 2026-10-19 > Completing a sprint shows the right counts, and the test suite is green again. ### Fixed - **Complete sprint:** right after moving an issue on the board, the dialog could count it twice (for example "1 issue done · 2 open" for a two-issue sprint), mixing a fresh board with a backlog still being refreshed. It now reads both fresh and says "Counting issues…" meanwhile. - **Tests:** the issue Details layout tests waited for the wrong signal and failed on slower CI machines; the shared fixtures now include a slow terms check so timing bugs show locally. ## [0.17.0] - 2026-10-18 > A comment thread that reads well: roomier comments, a composer that opens with M, quick replies, and edit or delete from each comment. ### Added - **Comments:** edit and delete your own comments (project admins can edit or delete any), with an "(edited)" marker that names who and when; delete asks first. Copy link gives a permalink that scrolls to the comment and highlights it. - **Composer:** starts collapsed as "Add a comment…"; press M or click to write; Save or Cancel, Esc cancels. Quick replies ("Looks good to me", "Thanks!", "Can you say more?", "I'll take a look.") fill the box without posting; self-hosters can hide them with `VITE_QUICK_REPLIES=off`. - **API:** `PATCH` and `DELETE /api/projects/{key}/issues/{number}/comments/{id}` (author or admin; another project's or issue's comment is 404). `Comment` gains `edited_at`, `edited_by_id` and `edited_by_name`. - **CLI:** `santi issues comment-edit` and `santi issues comment-delete`; `issues comments` shows each comment's id and whether it was edited. **MCP:** `edit_comment` and `delete_comment`. ### Changed - **Thread layout:** more space between and inside comments; times read relative for a week, then as a date, with the full date and time on hover. Every comment loads, not only the first 200. - **Archived projects:** comment controls stay in place, locked, like every other control. - **Account export** includes when and by whom each comment was edited. ### Upgrade notes - Migration `0022_comment_edit.sql` adds two nullable columns to comments (`edited_at`, `edited_by`) with a check that both are set or both empty. Additive; no backfill. ## [0.16.0] - 2026-10-18 > Rich text everywhere: Markdown descriptions and comments with a formatting toolbar, live styling, @mentions and emoji. ### Added - **Descriptions and comments:** written and stored as Markdown (CommonMark + GFM, D50). The editor styles as you type (bold, italic, strikethrough, code, links, headings, lists, task lists, quotes, code blocks, tables), has a toolbar with text style, marks, link, code, lists, emoji and a More menu, undo and redo, and the usual keyboard shortcuts; Cmd/Ctrl+Enter saves or posts, Esc cancels. On a phone the toolbar scrolls inside itself. - **@mentions:** type `@` to pick a project member (name or email, assignee and reporter first). A mention is stored as `[@Name](mention:)` and shows as a chip with the member's current name; someone no longer in the project shows as plain muted text. - **Emoji:** type `:` or use the toolbar to insert one of about 250 emoji. - **CLI:** `santi members ` lists a project's people with their ids; `issues show` and `issues comments` print mentions as `@Name` (`--json` keeps the raw token). - **MCP:** `list_members`; the issue and comment tools say bodies are Markdown and how to mention. ### Changed - **Limits:** descriptions and comments share one cap of 65,536 characters (comments were 20,000); a counter appears near the limit. - **Rendering is safe by construction:** raw HTML shows as text, only safe link schemes are clickable, images show as links, links to other sites open in a new tab without access to santi. - **Comments keep their leading indentation** (an indented code block stays a code block). - **Description save** waits for the server and keeps the draft, with the error, if it fails. ### Upgrade notes - Migration `0021_comment_length.sql` widens the comment length check. It rescans every comment under a table lock while it runs (quick at small scale); it is forward-only: once longer comments exist, going back to the 20,000 check fails. - Existing plain-text descriptions and comments render as Markdown with their line breaks kept; no data changes. ## [0.15.0] - 2026-10-18 > Colorful labels and a roomier issue panel: every label keeps its own color everywhere, and the Details panel breathes. ### Added - **Labels:** each label gets one of eight colors from its name (D51), the same on board cards, backlog rows, the issue picker, the label menu and the board's label filter. Every color pair reads at AA contrast in light and dark themes. ### Changed - **Issue details:** fields sit in four groups (status and assignee; priority, type, points and labels; sprint and epic; reporter and dates) with dividers, values line up with their names, long sprint and epic names show in full on hover, and the panel is wider from 1024 px (the dialog grows to 1080 px from 1280 px). ### Fixed - **Board:** a card whose meta line was full pushed the assignee avatar out of the card; labels now shorten instead. ## [0.14.1] - 2026-10-18 > Imports from trackers set in Portuguese, Spanish, French or German keep tasks and subtasks as tasks and subtasks. ### Fixed - **Import:** issue types exported in the site's language (Tarefa, Subtarefa, Tarea, Subtarea, Tâche, Sous-tâche, Aufgabe, Unteraufgabe, Épico, Épica, Épopée, Erro, Fehler) were suggested as stories, so a CLI import with `--yes` turned every task into a story. They now map to task, subtask, epic and bug. ## [0.14.0] - 2026-10-18 > Create projects from the terminal or an AI agent: `santi projects create` and the `create_project` MCP tool. ### Added - **CLI:** `santi projects create --name [--type scrum|kanban]` creates a project (scrum by default), makes you its admin and prints it; `--json` prints the API's answer. A malformed key is refused before any request (exit 2); a key already taken exits 5 with the server's message. - **MCP:** `create_project { key, name, board_type? }` does the same for AI agents. ### Changed - **Board CI:** the board INP end-to-end check retries twice on CI runners only; the budgets did not change. ## [0.13.2] - 2026-10-18 > The MCP server survives a redeploy: tools reconnect on their own instead of failing or hanging. ### Fixed - **CLI and MCP:** after the server redeployed, a running `santi mcp` kept a dead pooled connection, so every tool answered "cannot reach santi" and some calls hung for minutes until the MCP process restarted. Reads now time out after 30 s, idle connections close after 30 s, connecting gives up after 10 s, and a request is retried once after a network error (any request that never connected; otherwise only reads and deletes, never a create, edit or move that may already have reached the server). ## [0.13.1] - 2026-10-18 > Pickers scroll again: the mouse wheel and touch scroll option lists opened inside the issue dialog. ### Fixed - **Issue dialog:** the label picker list (and every popover opened inside a dialog, such as filters, members and the sprint picker) now scrolls with the mouse wheel, the trackpad and touch; before, only dragging the scrollbar worked. ### Documentation - **README:** centered logo, CI, release and license badges, quick links, and a feature list that matches what ships today (reports, sidebar, For you, project lifecycle, data export). ## [0.13.0] - 2026-10-17 > A sidebar that gets you back to your work: Recent and Starred panels, starred and recent projects, More projects and a resizable width. ### Added - **Sidebar:** Recent and Starred panels. Recent lists the projects and issues you opened, grouped by day, with search and 15 more at a time; Starred filters by projects or issues and lets you unstar in place. Both link to the matching For you tab. - **Sidebar:** the Projects section lists your starred projects above the 5 you used last, with a View option (recent and starred, starred only, most recent) and a Manage projects link. The open project shows Board, Backlog and Reports (scrum), and Settings. - **Sidebar:** More projects opens a searchable panel with every project not already listed. - **Sidebar:** project row menu gains Star/Unstar, Add people (admins) and the project type. - **Sidebar:** drag the edge, or use the arrow keys on it, to set the width from 200 to 500 px; double-click collapses it. The width is kept in this browser. - **API:** `GET /api/me/recent` and `GET /api/me/starred` (`kind=project|issue`), both paged with `q` search; `MyProject` gains `starred_at` and `visited_at`. ### Changed - **Sidebar:** hovering a row uses the neutral hover color; the purple fill marks the current page only. A hand-opened project row closes again on reload. ### Fixed - **Stars:** a failed star or unstar of a project no longer breaks the sidebar. ## [0.12.0] - 2026-10-17 > Sprints with a clock: start and end times, presets from 4 hours to a month, and a countdown to the minute. ### Added - **Sprints:** starting a sprint remembers its length for the board's next one (`length` on sprint start, `sprint_length` on the backlog). - **Sprints:** presets from 4 hours to 1 month with date and time pickers, times in your own zone, and a countdown that turns into "Overdue by …" at the minute the sprint ends. - **CLI:** `santi sprints start` takes `--for 4h|1d|1w|2w|1m` and local `--start`/`--end` times; sprint lines show local times with the UTC offset. ### Changed - **Sprints:** start and end are times, not dates. The API fields `start_date`/`end_date` are now `starts_at`/`ends_at` (RFC 3339) on sprints, sprint edits and sprint start; the old names are refused. An active sprint is overdue from the minute its end passes. ### Fixed - **Projects list:** the Lead column shows the lead's avatar and short name ("Emerson Silva"), and the Archived and Trash tabs read "21 hours ago by Emerson Silva" on one line; the full name is on hover. - **CI:** the statement budget check no longer fails at random. Status, type, priority and the other text-backed fields now bind as plain text, so a fresh database connection skips an extra type lookup query. ### Upgrade notes - Migration 0020 turns existing sprint dates into 00:00 (start) and 23:59 (end) in the database's `timezone` setting, UTC when unset. Before deploying, run `ALTER DATABASE SET timezone TO ''` (for example `'America/Sao_Paulo'`) so old sprints keep their day boundaries. - API clients: send `starts_at`/`ends_at` as instants with an offset instead of dates. - During the deploy, sprint endpoints on the old instance fail for a few seconds after the migration runs; open tabs need a reload to pick up the new fields. ## [0.11.0] - 2026-10-17 > Story points and priority stand out in purple and are edited right on the board card. ### Added - **Board cards:** the story points pill is always shown (`–` when empty) and opens a number field on click: Enter or leaving the field saves, Esc cancels, an empty field clears the estimate. The priority glyph opens the platform's priority picker. Both update the card at once and roll back if the server refuses. Archived projects show them read-only. - **Backlog rows:** the same priority picker next to the points pill. - **Issue details:** the priority glyph beside the Priority field. ### Changed - **Priority glyphs:** double chevron up (Urgent), chevron up (High), equals (Medium) and chevron down (Low), in the purple scale for Urgent and High; red is kept for bugs only. ### Fixed - Typing an unreadable estimate (for example `-`) in a points field no longer clears the points. - On phones, a card with labels no longer pushes the column wider than the screen. - The issue dialog shows the new points or priority right after a card or row edit. ### Upgrade notes - None: no migration and no API change. ## [0.10.0] - 2026-10-17 > Sprint reports: every past sprint, its report and the team's velocity, on the web, CLI and MCP. ### Added - **Reports tab** (Scrum projects): velocity of the last 7 sprints (committed vs completed points, with the average, and a "View as table" alternative), and the list of every started sprint, newest first, with dates, goal and totals. The running sprint is listed first as "In progress". - **Sprint report:** open any sprint from the list to see its issues grouped as Completed, Not completed and Removed from sprint, with points at the start and at the end, an "Added" marker for issues that joined after the start, and a "Deleted issues" line. Move between sprints with the picker or the Previous and Next arrows. Totals with no estimate show "—", not 0. - **API:** `GET /api/projects/{key}/reports/sprints`, `GET /api/projects/{key}/reports/velocity` and `GET /api/projects/{key}/sprints/{id}/report`. - **CLI and MCP:** `santi sprints report ` (text, or `--json`) and the read-only MCP tool `get_sprint_report`. ### Fixed - Component tests no longer open a browser window when run locally. ### Upgrade notes - Migration `0019_imported_sprint_facts` runs at startup: closed sprints created by the CSV importer get their sprint facts (completed issues with their points), so their reports and velocity are not empty. Sprints closed in santi are not touched. It is idempotent. - New API routes are additive; no existing response changed. ## [0.9.2] - 2026-10-17 > Landing page scores 100: it paints in about a second on a phone, with lighter screenshots. ### Fixed - **Landing page:** its stylesheet is now inside the page, so the first paint no longer waits for a second request (speed index on a phone went from 4.6 s to about 1 s). Screenshots come in 640, 1000 and full widths, so a phone downloads about 144 KB less. The GitHub star button is named by its visible text for screen readers. Lighthouse gives 100 in performance, accessibility, best practices and SEO on mobile and desktop. ### Added - **`/llms.txt`:** a short plain-text summary of santi with links to the API docs, the OpenAPI document and the source, for AI agents and crawlers. ## [0.9.1] - 2026-10-17 > Drafts that stay: text typed in a new issue or new epic form survives the page finishing loading. ### Fixed - **Backlog and board:** the inline "Create issue" form lost its summary and type, and the new epic form closed, when the drag layer finished loading right after the page opened. Both now keep what was typed. ## [0.9.0] - 2026-10-17 > Archived projects are read-only in place: every write control is visible but disabled. ### Changed - **Archived projects:** on the board, backlog, issue page, sprint header, board settings, members and import, every write control now stays where it is but is disabled and points at the archived banner, instead of failing with an error when used. Drag and drop is off, fields are read-only, and Create issue, More actions and Import issues show as disabled. ### Fixed - **Notifications:** a confirmation sent right after a page opened (for example "Archived SAN" just after opening settings) could be lost before the notification area loaded. It now waits and shows. ## [0.8.2] - 2026-10-16 > Top bar stays on top: rows no longer scroll over the header. ### Fixed - **Top bar:** scrolling the backlog or board, a row's points, avatar and menu painted over the sticky top bar (search and Create). The top bar now stays above page content. ## [0.8.1] - 2026-10-16 > Editors that stay open: an inline edit no longer closes when the page finishes loading. ### Fixed - **Backlog and board:** a summary, points or column-limit editor opened while the drag layer was still loading closed by itself and lost the text typed so far (the rows were rebuilt when the drag layer arrived). The open editor and its draft now survive that, and opening or closing an editor re-renders only that editor. ## [0.8.0] - 2026-10-16 > Create sprint stands out: the backlog's Create sprint is now its primary action. ### Changed - **Backlog:** Create sprint is a filled purple button with a + icon, the primary action of the backlog section (each sprint section keeps its own Start or Complete as primary). ## [0.7.0] - 2026-10-16 > Sidebar project menu: expand any project and reach Copy link, Settings, Archive, Delete or Leave from its row. ### Added - **Sidebar project row:** a chevron expands or collapses any project's Board, Backlog and Settings (the current project starts open; the choice is remembered per project), and a "…" menu offers Copy link, Settings, Archive project, Delete project and Leave project. ## [0.6.0] - 2026-10-16 > Archive and trash projects: read-only archive, a 60-day trash with restore, Active/Archived/Trash tabs, and leaving a project. ### Upgrade notes - Migration `0018_project_lifecycle.sql` runs on start. Trashed projects are purged 60 days after trashing. ### Added - **Archive and trash projects:** a danger zone at the end of project Settings lets admins archive a project (read-only for everyone, hidden from lists and search, still open by link with a banner and Unarchive) or delete it to the trash (type the key to confirm; restorable for 60 days, then purged; Undo for a few seconds after). `/projects` has Active, Archived and Trash tabs with Unarchive, Restore and Delete forever. Any member can leave a project; the last admin cannot. API `POST /api/projects/{key}/archive|unarchive|trash|restore`, `DELETE /api/projects/{key}`, `GET /api/projects?state=`; CLI `santi projects archive|unarchive| trash|restore|purge`; matching MCP tools. Keys stay reserved while archived or trashed. Migration 0018. ## [0.5.1] - 2026-10-16 > Quieter code: narrating comments removed or turned into names; reasons moved to the decision log. ### Changed - **Code comments:** comments that narrated the code were removed or turned into names; the rationale moved to `docs/specs/decisions.md` (D18, D37, D39). No behavior change. ## [0.5.0] - 2026-10-16 > CLI and API clean-up from using santi on santi: names instead of ids, issue commands where you look for them, unknown fields refused. ### Upgrade notes - API: a body with an unknown field or of the wrong shape answers 422 with the reason (it was ignored or 400). Malformed JSON stays 400. ### Added - **CLI:** `santi issues plan`, `santi issues comment` and `santi issues comments` (lists every comment, oldest first; `--json` for the raw list); `santi issues edit --sprint `. `santi issues show` prints status, assignee, reporter and sprint by name. - **MCP:** `list_comments` tool. - **API:** issue answers carry `status_name`, `assignee_name`, `reporter_name` and `sprint_name`; comments carry `author_name`. ### Changed - **API:** request bodies refuse unknown fields; a body of the wrong shape answers 422 with the reason in `detail` and the field at fault (malformed JSON stays 400). ## [0.4.0] - 2026-10-16 > Labels picker: search, defaults, create, chips on cards and backlog rows. ### Added - **Labels picker:** the Labels field in the issue view and the create dialog opens a searchable list: the issue's labels, then the project's, then common defaults (bug, feature, frontend, backend, mobile, infra, design, docs, tech-debt, security, performance, blocked). Pick or create a label; chosen labels sit side by side as chips, removed with x or Backspace. Board cards and backlog rows show up to two label chips and "+k". ## [0.3.0] - 2026-10-16 > Names that fit on one line: first and last name in tight places, full name on hover. ### Changed - **People's names:** shown by first and last name on one line ("Emerson Silva"), with the full name on hover and for screen readers; a name typed all in capitals is shown in title case; avatar initials use the first and last name. The members page and the account menu keep the full name. CLI board and backlog lines use the short form. ## [0.2.0] - 2026-10-16 > A personal home, a CLI and an MCP server: For you home, `santi` CLI, MCP for AI assistants, landing page and logo. ### Upgrade notes - Migration `0017_home.sql` runs on start. Privacy policy version 2026-10-16.2: signed-in people accept it again. ### Added - **For you home:** recommended project cards (star, open issues assigned to you linking to your board), tabs Recommended, Assigned to me, Starred, Worked on and Viewed with rows grouped by day and a status on every row; stars on projects and issues. A `/projects` page lists every project. Views and visits are recorded only when you open an issue or project. The account export includes stars and history, and leaving a project removes them. The privacy policy (version 2026-10-16.2) lists this data. - **Landing page:** a static page at `/` for visitors without a session (and at `/about` for everyone): product tour with screenshots, performance numbers, self-hosting, roadmap and FAQ, no JavaScript beyond a copy button. Ships `robots.txt` and `sitemap.xml` built from `VITE_SITE_URL`. - **Brand:** the santi logo in the top bar, sign-in pages and error pages; favicons, app icons, a web manifest and a social card image. - **CLI:** the `santi` binary: `login` (URL and token saved to `~/.config/santi/config.toml`, mode 0600), `whoami`, `projects`, `issues list|show|create|edit|move|delete`, `board`, `backlog`, `sprints list|create|start|complete`, `plan`, `search`, `comment` and `import` (preview, then confirm). `--json` on every command; API errors print the server's message with distinct exit codes. URL and token from flags, `SANTI_URL`/`SANTI_TOKEN` or the config file. - **MCP server:** `santi mcp` over stdio, or Streamable HTTP with `--http` (bearer token required on every request, passed through to the API). 16 tools for projects, boards, backlog, search, issues, comments, sprints and epics, with JSON Schemas, read-only and destructive hints, and tool errors carrying the server's message. Client setup in `docs/mcp.md`. ### Fixed - **Sign-in:** a wrong email or password now says so ("Email or password is incorrect.") instead of asking for an API token. ## [0.1.0] - 2026-10-16 > First release: Scrum and Kanban boards, backlog, sprints, epics and subtasks, CSV import, self-hosting. First release: the MVP, self-hosted with `docker compose up -d`. ### Added - **Accounts:** sign up, sign in and sign out with a server session cookie (`HttpOnly`, `Secure`, `SameSite=Lax`); passwords hashed with Argon2id. - **Projects:** Scrum and Kanban projects with a short key (`WEB-12`), a project list on the home page and a new-project form. - **Members and invites:** admin and member roles, invite links with a preview before joining, a members page for admins to change roles or remove people. - **Board:** columns that hold one or more statuses, WIP limits with warnings, drag and drop across and within columns (optimistic, with a keyboard "Move to…" path), inline create at the foot of each column, a card menu (move, assign, priority, copy key, delete), one column at a time on phones. Kanban hides done work after a set number of days. - **Board settings:** add, rename, reorder and delete columns; add, rename and delete statuses; map statuses to columns; the rightmost column means done. - **Backlog:** sprint sections and the backlog in one list, drag and drop or "Move to…" to plan, inline create per section, in-place edit of summary, points and assignee, virtualized long lists. - **Sprints:** create, edit, delete, start and complete; completing moves open work to the backlog, a future sprint or a new one and keeps the sprint's scope facts. - **Issues:** epics, stories, tasks, bugs and subtasks; an issue dialog over the board and a full issue page with per-field edits, comments, labels, points, priority, assignee, parent and epic; delete for admins and the reporter, with a confirm that names what goes with it. - **Epics:** an epic panel on the backlog to filter by, create and assign epics. - **Filters:** assignee, "only my issues", recently updated, type, label, epic and text, kept in the URL; a filter sheet on phones. - **Search:** a project search page with URL filters and a search field in the top bar. - **Keyboard:** `c` to create, `j`/`k` to move between issues, `o` or Enter to open, `?` for the full list; shortcuts can be turned off per browser. - **API tokens:** personal tokens for scripts (`Authorization: Bearer santi_…`), created and revoked from the account page. - **Import:** preview and import CSV exports from Jira Cloud and Linear (statuses, people, sprints or cycles, types, parents, labels, points, comments), idempotent on re-run. - **API:** JSON over HTTP with an OpenAPI 3.1 document at `/openapi.json`, interactive docs at `/docs`, RFC 9457 problem errors, cursor pagination. - **Packaging:** a multi-stage `Dockerfile` (distroless, non-root, healthcheck) and a `compose.yaml` that runs santi with PostgreSQL 17; migrations run on start. ### Performance - Budgets at 5k issues / 50 users / 20 sprints: p95 under 30 ms for board, backlog, issue, search and move on a laptop; SQL statement counts per request guarded in CI. - Short rank keys, one-query token and membership lookup, database pool sized from the core count, gzip and Brotli responses. - Under 170 KB of gzipped JavaScript on a first visit to any page, with menus and popovers loaded after first paint. ### Security - Cross-site write protection (`Sec-Fetch-Site`, with an `Origin`/`Host` fallback). - Content-Security-Policy, `nosniff` and referrer policy headers on every response. - Import limits on file size, rows, columns and distinct values; parsing runs off the async workers. - Hashed API tokens and sessions; non-members get 404 for a project, members without the right role get 403. [Unreleased]: https://github.com/emersonjds/santi/compare/v0.26.0...HEAD [0.26.0]: https://github.com/emersonjds/santi/compare/v0.25.1...v0.26.0 [0.25.1]: https://github.com/emersonjds/santi/compare/v0.25.0...v0.25.1 [0.25.0]: https://github.com/emersonjds/santi/compare/v0.24.1...v0.25.0 [0.24.1]: https://github.com/emersonjds/santi/compare/v0.24.0...v0.24.1 [0.24.0]: https://github.com/emersonjds/santi/compare/v0.23.0...v0.24.0 [0.23.0]: https://github.com/emersonjds/santi/compare/v0.22.0...v0.23.0 [0.22.0]: https://github.com/emersonjds/santi/compare/v0.21.1...v0.22.0 [0.21.1]: https://github.com/emersonjds/santi/compare/v0.21.0...v0.21.1 [0.21.0]: https://github.com/emersonjds/santi/compare/v0.20.0...v0.21.0 [0.20.0]: https://github.com/emersonjds/santi/compare/v0.19.0...v0.20.0 [0.19.0]: https://github.com/emersonjds/santi/compare/v0.18.0...v0.19.0 [0.18.0]: https://github.com/emersonjds/santi/compare/v0.17.1...v0.18.0 [0.17.1]: https://github.com/emersonjds/santi/compare/v0.17.0...v0.17.1 [0.17.0]: https://github.com/emersonjds/santi/compare/v0.16.0...v0.17.0 [0.16.0]: https://github.com/emersonjds/santi/compare/v0.15.0...v0.16.0 [0.15.0]: https://github.com/emersonjds/santi/compare/v0.14.1...v0.15.0 [0.14.1]: https://github.com/emersonjds/santi/compare/v0.14.0...v0.14.1 [0.14.0]: https://github.com/emersonjds/santi/compare/v0.13.2...v0.14.0 [0.13.2]: https://github.com/emersonjds/santi/compare/v0.13.1...v0.13.2 [0.13.1]: https://github.com/emersonjds/santi/compare/v0.13.0...v0.13.1 [0.13.0]: https://github.com/emersonjds/santi/compare/v0.12.0...v0.13.0 [0.12.0]: https://github.com/emersonjds/santi/compare/v0.11.0...v0.12.0 [0.11.0]: https://github.com/emersonjds/santi/compare/v0.10.0...v0.11.0 [0.10.0]: https://github.com/emersonjds/santi/compare/v0.9.2...v0.10.0 [0.9.2]: https://github.com/emersonjds/santi/compare/v0.9.1...v0.9.2 [0.9.1]: https://github.com/emersonjds/santi/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/emersonjds/santi/compare/v0.8.2...v0.9.0 [0.8.2]: https://github.com/emersonjds/santi/compare/v0.8.1...v0.8.2 [0.8.1]: https://github.com/emersonjds/santi/compare/v0.8.0...v0.8.1 [0.8.0]: https://github.com/emersonjds/santi/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/emersonjds/santi/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/emersonjds/santi/compare/v0.5.1...v0.6.0 [0.5.1]: https://github.com/emersonjds/santi/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/emersonjds/santi/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/emersonjds/santi/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/emersonjds/santi/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/emersonjds/santi/compare/v0.1.0...v0.2.0 [0.1.0]: https://github.com/emersonjds/santi/releases/tag/v0.1.0