Ticku v2.1.0
Release date: 2026-08-10
Email-to-ticket is substantially reworked: mailboxes now belong to the tenant rather than to a project, one mailbox can feed several projects through routing rules, and there are three ways to connect one — including a per-mailbox "Sign in with Microsoft" that needs no Global Admin consent. This release also adds followers, comment replies and reactions, and tightens Azure directory verification on every Microsoft sign-in.
⚠️ Breaking / Migration Steps
- Per-tenant Azure mail credentials are gone. Email now authenticates with the platform SSO app registration against each tenant's registered
entraDirectoryId. There is nothing for a tenant admin to type in. TheMicrosoftMailConfigtable is dead and pending cleanup. - Add Mail permissions to the SSO app. The app-only connection mode needs
Mail.ReadWriteandMail.Sendapplication permissions with admin consent. Without them every app-only mail call returns 403. See Azure App Registration. - Inbox ownership flipped.
ProjectEmailConfig.projectId(unique, one inbox per project) becameEmailInbox.defaultProjectId(the fallback destination). The table keeps its name via@@map, so the rename costs no data movement — but anything readingprojectIdon it must be updated. - Set
CRON_SECRET. The new email cycle calls/api/cron/emailevery 2 minutes and refuses unauthenticated triggers. It falls back toGRAPH_WEBHOOK_SECRET; if neither is set the worker skips the job entirely and no mail flows. - The daily webhook-renewal job was removed. The email cycle renews subscriptions as well as polling, so renewal now happens on a 2-minute cadence instead of daily.
- Email can only target Support projects. Existing rows pointing elsewhere are grandfathered and still saveable as-is, but cannot be moved to a different non-Support project.
- Run
npm run db:migrate(migrate deploy) after updating.
✨ New
- Email routing rules — one shared mailbox can feed many projects. Match on recipient address (aliases and plus-addressing) or sender domain, with recipient taking precedence and the inbox's default project as the fallback. Rules can override priority, acknowledgement, notification flags, subject folder, and assignee. A Simulate tool shows which rule would win before you commit to it. See Routing Rules.
- Three connection modes — app-only Microsoft Graph (push, seconds), per-mailbox delegated OAuth (polled, no Global Admin needed), and IMAP/SMTP with a password (polled; not usable against Microsoft 365). See Connection Modes.
- Followers — subscribe anyone to a single ticket or sub-task without giving them the project. A follower from outside the organization gets a minimal guest membership that grants nothing beyond the followed item. See Followers.
- Comment replies and reactions — comments thread via replies, and any comment can be reacted to with an emoji (one per person, changing rather than stacking). New
COMMENT_REPLY,COMMENT_REACTION, andFOLLOWER_ADDEDnotification events. Reactions are in-app only. - Auto-assign on comment — a non-Viewer commenting on an open ticket or sub-task they didn't create takes ownership of it.
- Commit id capture — the Dev Fixed → Review transition can record the commit a fix shipped in, alongside a review note.
- Work Schedule table — planned work per assignee (project, ticket, planned start/end, status, priority) in Analytics, plus a Monthly Timesheet Excel/PDF export with a daily hours grid. See Analytics.
- Due-date filters —
dueby:andduewithin:on the dashboard filter bar. - Product tour — a guided walkthrough per screen, launched from the header. It never auto-opens.
🛠 Improved
- Azure directory verification on every sign-in. The
tidcheck previously ran only at account creation, so any returning user — a password signup, a Teams user, a guest — could sign in via Microsoft without ever passing it. It now runs on every Microsoft sign-in, and a tenant with no registered directory adopts one from its designated first admin (trust on first use). Enforcement is behindENTRA_TID_ENFORCE, off by default: a mismatch is logged but allowed until you turn it on. See Authentication. - Outbound email is now opt-in per event. Comments, status changes, and acknowledgements each have their own toggle. Notify on comment defaults to off — comments carry no internal/public flag, so the previous unconditional behaviour mailed internal team discussion to the customer verbatim. An agent opts a single comment in by writing
@creator. - Assignment notifications folded into status changes. Assigning auto-transitions
OPEN → ASSIGNED, so a separate assignment toggle made the same real-world event send different mail depending on which control the agent used. - Sub-tasks in global search, plus display-ID lookup —
EMA-15.2or15.2jumps straight to a sub-task. - Clickable ticket and sub-task mentions in comments and the rich-text editor.
- Health reporting that doesn't lie. A poll cycle that ingests successfully and then fails later now records its progress; previously a late error hid earlier success, so an inbox reported "Not yet polled" while it was actively creating tickets.
- Settings shell — Notifications, Analytics, and Bulk Upload now share a consistent settings layout.
- Notification read state fixes and escalation notification tuning.
🗑 Removed
- Auto-create ticket toggle. With it off, mail produced no ticket and no record while both transports still marked it read — messages vanished silently. Ticket creation is now unconditional.
- Per-inbox allowed/blocked sender domains. They duplicated routing and fought it: a domain missing from the allow-list had its routing rule rejected before the rule was ever consulted, with nothing to indicate why. The allow-list was also suppressing bounce messages by accident. Blocking a sender is the mail provider's job.
Both remain as unused columns pending a cleanup migration.
📚 Documentation
The Email-to-Ticket guide is now a five-page section covering the pipeline, connection modes, inbox settings, routing, and troubleshooting. Screenshots have been added throughout the user and admin guides, captured by a committed, re-runnable script.