Repository navigation
Releases: Docker-Hunterpedia/Helpdock
Release list
Helpdock 0.5.1
A fix release for two admin defects that only show against a real api, so the
mock-backed test suites never caught them. No migration, configuration or API
change; upgrade by pulling the new image.
- Agent assist works in the production admin again. Since 0.4.0 the
composer's Assist menu (suggest reply, summarize, suggest fields, translate,
rewrite, draft article), the "items redacted before AI" notice, voice-note
transcripts and Help center › Proposals called/api/api/…, got a 404 and
stayed hidden. They now reach the api (#175). - The "is viewing" indicator names colleagues for Agents. An Agent, who
cannot read the staff list, saw part of a user id ("01a13522 is replying").
Names now come from the department's assignable list, as the assignee picker's
do (#175).
What's Changed
- fix: release workflow verifies the signer identity of the ref it ran under, and the manual mode finishes an unreleased tag by @Docker-Hunterpedia in #173
- fix: agent assist reaches the api in production builds; the collision indicator names colleagues for Agents by @Docker-Hunterpedia in #175
- docs: mark M10 Meta channels shipped by @Docker-Hunterpedia in #176
- docs: release notes for 0.5.1 by @Docker-Hunterpedia in #178
- chore: version packages by @github-actions[bot] in #177
Full Changelog: v0.5.0...v0.5.1
Helpdock 0.5.0
M10 Meta channels, and the code half of M9 Hardening: the fixes from
the internal pre-pentest review, the gaps the ASVS L2 re-walk of Telegram, AI
and the API found, the automated accessibility audit, and four follow-ups M6
and M7 had left open. What still needs a person before 1.0 is listed under
known gaps.
M10 Meta channels
- WhatsApp numbers, Facebook Pages and Instagram professional accounts are
ticket channels. A customer's message opens a ticket or continues the
conversation's open one, and an agent's public reply, text and files, goes
back on the same platform through the outbox. Images, video, documents,
voice notes and stickers arrive on the ticket; locations and shared
contacts are filed as text. The first message of a reply opens with the
agent's first name and the brand. - One webhook for the install. Every post from Meta is checked against
the app secret before it is parsed, routed to the account it names, filed
within the request and answered at once. Channels › Meta shows the callback
URL and the verify token to paste into Meta's dashboard. - Connect an account per platform on Channels › Meta by pasting the
dashboard's token, test it before saving and route it to a department.
Once an hour a job checks the token and the webhook subscription; the
account's page offers Subscribe now and Reconnect when Meta drops
either. - The reply window. A reply outside Meta's 24-hour window is refused when
it is written, and the ticket view says how long the window stays open. A
person's reply to a Messenger or Instagram customer between 24 hours and
7 days goes out with Meta's Human Agent tag when the account's switch is
on. - Delivery states on every reply: sent, delivered and read as Meta
reports them,failedwith Retry, andrefusedin Meta's words when the
window had closed. - Identities. The ticket view shows which number, Page or account a
ticket is with, the customer's platform id, phone, name or handle, and
which of them is verified. Messenger and Instagram names are looked up by
a job and kept once they arrive. - The whole of it is in
docs/guides/meta-channels.md: what each
platform needs, what Meta charges for WhatsApp, App Review, and developing
without Meta.
M9 Hardening
- Visitor addresses behind a proxy.
TRUST_PROXYnow takes a list of
proxy addresses, CIDRs or the namesloopback,linklocaland
uniquelocal, so the api believes the hop from Caddy and not an address a
client wrote intoX-Forwarded-For. The Cloudflare Caddyfile trusts
Cloudflare's published ranges and forwards the visitor's address. - Widget sockets spend a budget of 120 events a minute per visitor, and a
visitor's sockets are closed when their signed identity is withdrawn or
changed. - OAuth sign-in is bound to the browser that started it by a ten-minute
cookie. - API keys can expire (
expiresAtwhen one is created), a refused key
leaves a trace in the audit log, an API key gets 403 instead of 500 on
routes that act for a person, andwebhooks:manageno longer reads data on
its own. - Brands scheduled for deletion. During the 30-day grace, the brand's API
keys answer 410 and its webhook deliveries are skipped. - Model addresses are checked when saved: https, and no private, loopback
or metadata address unless its range is inOUTBOUND_ALLOW_CIDRS. - Retention purges finished webhook deliveries and sent or failed Telegram
replies after 30 days, and storedIdempotency-Keyanswers after 24 hours.
"Anonymise contact" also erases the contact's Telegram chats, the redaction
maps of AI calls on their tickets and the webhook deliveries that carry
their data. - Uploaded and Google Drive DOCX files are refused past 1,000 entries or
100 MiB unpacked. JSON answers carryCache-Control: no-store. A Notion or
Google Drive connection callback works once. - Accessibility. Zoom, reflow, forced colours, screen-reader markup and
mixed-direction text are checked by Playwright on the widget and the help
center in both languages, and what they found is fixed
(record). The ASVS L2 record
reads 198 Met, 35 Partial and 0 Gap (record).
Gaps closed from M6 and M7
- Telegram bots have their own language prompt.
/startasks for English
or Arabic with the bot's question, edited on the bot's page under
Channels › Telegram. - The widget's handoff line says when the team is back. A visitor writing
out of hours after a handoff reads when the team is away until, by the
department's calendar, else the brand's. A conversation carries the new
optionalhours. - The ticket list says what the assistant did. A row's caption ends with
"AI paused" or "AI answered". - Agent assist sends the brand's Arabic system prompt for an Arabic
ticket, as auto-reply already did.
Upgrade notes
- Run the migrations (
0048–0052). Restart the worker so it picks up the
Meta jobs (sending, media, profile names and the hourly health check). - The Compose file now sets
TRUST_PROXY=uniquelocalinstead oftrue.
truestill works and still believes every hop. Behind Cloudflare, copy the
newdocker/caddy/Caddyfile.cloudflareand rundocker compose up -d
(install guide); behind a proxy
of your own, list its address
(install guide). - API keys that manage webhooks need the read scope of the endpoint's
events (tickets:read,contacts:readorarticles:read), or they get
403webhook-event-scope. Endpoints that already exist keep delivering. - Keys already issued never expire; set
expiresAtthrough the API when you
want one to. - A Google or GitHub sign-in begun just before the upgrade has to be started
again. - To connect a Meta account, set the Meta app's id and secret in
.env
(HD_META_APP_ID,HD_META_APP_SECRET) and restart the api and the worker;
there is no Meta section on the Settings screen in this release
(the four settings).
Optional:META_GRAPH_VERSION,META_GRAPH_API_ROOTand
META_INSTAGRAM_API_ROOT, whose defaults are Meta's.
Known gaps
- The Meta channels have not been run against a real Meta app yet. CI
uses a stand-in for the Graph API. The milestone document lists what only a
real run settles: which secret signs Instagram webhooks (both are tried),
the exact closed-window error code, whether Business Verification is
required for App Review, and whether a Page the operator administers returns
a customer's name without the profile feature. Until an install has been
through App Review, a Messenger contact can be "Messenger user" with its
id. - WhatsApp templates (M10-09), which reach a customer after the window,
come in a later release; the satisfaction survey is not sent on these
channels until they do. - What still needs a person before 1.0: the external pentest
(scope), the screen-reader pass
(runbook), the load-test host run, the
clean-VM onboarding run with outside testers, and the restore drill for the
record (M9). - The rest is listed in
M10.
What's Changed
- feat: sign release images with GitHub OIDC by @Docker-Hunterpedia in #162
- fix: reduce CI feedback time by @Docker-Hunterpedia in #163
- fix: skip full CI for docs-only PRs by @Docker-Hunterpedia in #164
- test: stabilize completed settings screenshots by @Docker-Hunterpedia in #166
- feat: M9 hardening towards 1.0 — pre-pentest fixes, ASVS re-walk and gap fixes, accessibility automation, and the M6/M7 gaps by @Docker-Hunterpedia in #167
- feat: M10 Meta channels — WhatsApp, Messenger and Instagram as ticket channels by @Docker-Hunterpedia in #168
- docs: pentest statement of work (M9-01) and the screen-reader pass runbook (M9-04) by @Docker-Hunterpedia in #170
- docs: release notes for 0.5.0, and the missing 0.4.0 and 0.3.1 sections by @Docker-Hunterpedia in #172
- chore: version packages by @github-actions[bot] in #169
Full Changelog: v0.4.0...v0.5.0
Helpdock 0.4.0
Minor Changes
-
#147
a35e65fThanks @Docker-Hunterpedia! - AI foundation (M7-01, M7-02, M7-08), API only. Install admins configure AI providers through/api/install/ai: an API key, subscription (OAuth) credentials or none for a local OpenAI-compatible server, stored encrypted and never returned; model discovery; the default model; and the one embedding model of the install, whose change re-embeds every knowledge chunk in the worker without ever serving two models at once. Brands set a model override, PII redaction, the injection filter, a daily and monthly budget and a system prompt through/api/brands/:brandId/ai. Every model call is logged toai_callswith its tokens and cost, and a ticket's calls are readable at/api/brands/:brandId/tickets/:ticketId/ai-calls. Data retention now nulls AI call bodies after the brand's AI-log window and keeps their counts and cost. Seedocs/guides/ai.md. -
#149
fd9c371Thanks @Docker-Hunterpedia! - M6 Telegram, M7 AI and M8 API, webhooks, reports are complete. This release connects Telegram bots to the desk, adds grounded AI that assists agents and answers customers from the brand's own knowledge under a budget and a persistent handoff, and opens the platform up: scoped API keys and a documented REST v1, signed outbound webhooks, reports with CSV export, the System page with Bull Board, satisfaction surveys on every channel, and brand deletion with a grace period. What each milestone built, the test behind every exit criterion, and the gaps each left open are indocs/completed/. -
#147
a35e65fThanks @Docker-Hunterpedia! - Close carried gaps: the offline auto-unassign waits for the department to open, the first-run wizard generates the web push key pair, the widget names the agents online, staff socket events have per-person budgets, and signing out of one browser closes only that browser's sockets. CI adds Helpdock's Semgrep rules and a dependency audit; release branches and tags get a ZAP baseline scan.
Patch Changes
- #151
358d464Thanks @Docker-Hunterpedia! - Complete install authentication settings with write-only OAuth credentials, correct shared admin field and session layouts in English and Arabic, add nonce-based admin styles and a restrictive browser permissions policy, and patch the Fastify HTTP/2 trailer-response denial of service.
What's Changed
- fix: close retention and own-sender milestone gaps by @Docker-Hunterpedia in #146
- feat: M6 Telegram, M7 AI, M8 API/webhooks/reports and M9 hardening towards 1.0 by @Docker-Hunterpedia in #147
- docs: close out M6 Telegram, M7 AI and M8 API, webhooks, reports by @Docker-Hunterpedia in #149
- fix: complete M9 settings, usability, and runtime hardening by @Docker-Hunterpedia in #151
- chore: version packages by @github-actions[bot] in #148
Full Changelog: v0.3.1...v0.4.0
Helpdock 0.3.1
Patch Changes
- #140
a2c7c46Thanks @Docker-Hunterpedia! - New widget signing secrets start withhdws_instead ofwhsec_, the prefix Stripe uses for its webhook secrets, so secret scanners no longer report a Helpdock secret as a Stripe key. Secrets generated earlier keep working; replace one only if you want the new prefix.
What's Changed
- ci: never cancel a running release; treat a missing pending output as nothing pending by @Docker-Hunterpedia in #141
- fix(widget): issue signing secrets with an hdws_ prefix (M4-02) by @Docker-Hunterpedia in #140
- chore: version packages by @github-actions[bot] in #142
Full Changelog: v0.3.0...v0.3.1
Helpdock 0.3.0
M4 Widget and realtime and M5 Help center. Customers can now reach the
desk from a brand's own website: an embeddable chat widget, a hosted contact
form, and a bilingual help center on the brand's domain whose articles the
widget searches too.
M4 Widget and realtime
- The chat widget. One
<script type="module" … data-brand>tag. It is a
Preact app in a Shadow DOM, about 26 KB gzipped, with socket.io loaded only
when a conversation starts. It has four modes (chat, chat with suggested
articles, help center only, and contact form), light, dark and auto themes
from the brand's accent, and English and Arabic with right-to-left layout. - Visitor identity and ownership. A server-issued visitor id and a hashed
secret. An optional signed identity comes from the customer's own backend. A
typed email never opens another contact's conversations. - Origin allow-list and rate limits on every widget route and on the socket
handshake. They are set on Channels › Widget. - Delivery you can trust. Messages are deduplicated by client id, carry a
sequence number per conversation, and catch up after a reconnect, with an SSE
fallback. A dropped network, an api restart or a double send leaves exactly
one message. - In the widget: a pre-chat form, business-hours awareness, the transcript
by email, agent name and avatar, and attachments and voice notes within the
brand's content policy. - The hosted web form at
/contact, per brand, with custom fields,
attachments and optional CAPTCHA (Turnstile or hCaptcha). It needs no
JavaScript. - The widget protocol is documented for native apps in
docs/guides/widget-protocol.md.
M5 Help center
- Content: categories, sections and articles with an English and an Arabic
version, drafts, scheduled publishing, and a fallback to the brand's default
language. The admin editor handles headings, tables, callouts, code, images
(re-encoded to WebP), YouTube and Vimeo embeds, and Markdown import and
export. - Visibility: each version is public or internal, and a whole help center
can be internal-only. Internal content never reaches the sitemap, public
search or a public cached page. Staff reach it through a one-minute pass from
the admin. - Pages on the brand's own domain. Custom domains are checked by CNAME and
TXT and get certificates from Caddy on demand. Pages are server-rendered in
both languages and cached, with canonical and hreflang links, Open Graph,
JSON-LD, a sitemap androbots.txt. - Theme: accent colour, logo, favicon, home layout, header and footer
links, and custom CSS, which is filtered through a strict allowlist. - Search in English and Arabic with typo tolerance on titles, plus a search
log that shows what customers looked for and did not find. - Feedback: views and "Was this helpful?" votes, and an Insights tab. From
an article, "Still need help?" opens the widget or the form and tells the
agent which article the customer came from.
Fixes
- A brand added after setup now gets the built-in ticket statuses. Before this
release no ticket could be filed in it, and its widget said it was
unavailable.
Upgrade notes
- Run the migrations (
0030–0035). Restart the worker so it picks up the
help center jobs (publishing, image processing, search indexing). - The image now carries the widget build and serves it at
/widget.js. Set
WIDGET_DIST_DIRonly when you run the api outside the image. - Optional:
HELPCENTER_CNAME_TARGETnames the host customers' help center
domains should point at. It defaults to the host ofAPP_URL. The install
guide's custom domains section has
the DNS steps. - The bundled
Caddyfilechanged. If you keep your own copy, compare it: a
domain marked as proxied by Cloudflare no longer triggers a certificate
request.
Known gaps
Listed in M4 and
M5. The one to know before exposing a help
center: images in internal articles are not access-controlled beyond an
unguessable address.
What's Changed
- feat(widget): the Preact widget app, modes, theming and accessibility (M4-01, M4-11, widget side of M4-05..08) by @Docker-Hunterpedia in #129
- feat(domains): custom help center domains with DNS verification and on-demand TLS (M5-07) by @Docker-Hunterpedia in #131
- feat(widget): widget server, identity, realtime and the live transport (M4-02..08, M4-10) by @Docker-Hunterpedia in #132
- feat(web-form): hosted web form per brand with custom fields and CAPTCHA (M4-09) by @Docker-Hunterpedia in #133
- feat(help-center): content model, article editor and visibility (M5-01, M5-02, M5-09) by @Docker-Hunterpedia in #134
- feat(help-center): search, feedback, Insights and the widget on real content (M5-05, M5-08, M5-10) by @Docker-Hunterpedia in #135
- feat(help-center): server-rendered pages, SEO and site settings (M5-03, M5-04, M5-06) by @Docker-Hunterpedia in #136
- docs: close out M4 Widget and realtime and M5 Help center by @Docker-Hunterpedia in #137
- docs: release notes for 0.3.0 (M4, M5) by @Docker-Hunterpedia in #138
- ci: release automatically when the version PR merges; run widget and api page browser tests by @Docker-Hunterpedia in #139
- chore: version packages by @github-actions[bot] in #130
Full Changelog: v0.2.0...v0.3.0
Helpdock 0.2.0
M2 Email channel and M3 Automation and SLAs. Helpdock now talks to
customers by email and runs the desk on its own: business hours and SLA clocks,
workflow and time-based rules, macros and canned responses, and staff
notifications in the admin, by email and by browser push.
M2 Email channel
- Inbound email from IMAP mailboxes or inbound-parse webhooks (Postmark,
SendGrid, Mailgun, Resend, generic JSON). Replies thread onto their ticket by
Message-ID,Referencesor the ticket number, and only when the sender is a
participant — anyone else quoting a ticket gets a new ticket. - Outbound email through each brand's SMTP server, from the department's
address, in English or Arabic with the agent's signature. Every send goes
through the outbox with a fixedMessage-ID, retries five times, and lands in
Failed sends in the admin when it cannot be delivered. - Auto-replies (acknowledgment and out-of-hours) with loop protection.
- Email security: sanitised HTML, remote images blocked or proxied, an
optional SPF/DKIM spam rule.
M3 Automation and SLAs
- Business hours and holidays per brand, with department overrides.
- SLA engine: first-response and resolution clocks in business time, pause
on "awaiting customer", escalation steps, and timers rebuilt after a Redis loss. - Workflow rules on events and on a schedule, with a test run and a loop
guard; macros and canned responses in English and Arabic. - Notifications in the admin, by email and by web push, with per-person
preferences; an audit log viewer for install admins.
Upgrade notes
- Run the migrations (
0024–0029); the worker needs a restart to pick up the
new queues. - Sign-in links, password resets and invitations are now emailed through the
install's SMTP server (the wizard's outgoing email step). Before this release
they were only logged. Without SMTP they are still not delivered; the install
guide says how to use Mailpit in development. - Optional:
HD_PUSH_VAPID_PUBLIC_KEYandHD_PUSH_VAPID_PRIVATE_KEYturn on
browser push notifications.
Known gaps
Listed in M2 and
M3; none blocks upgrading.
What's Changed
- docs: start M2 Email channel and M3 Automation and SLAs by @Docker-Hunterpedia in #96
- feat(email): outbound SMTP through the outbox, auto-replies and Outgoing email admin (M2-05, M2-06, M2-08 part) by @Docker-Hunterpedia in #97
- feat(channels): inbound email, threading and mailboxes (M2-01, M2-02, M2-03, M2-04, M2-07, M2-08) by @Docker-Hunterpedia in #99
- feat(sla): business hours, holidays and the SLA engine (M3-01, M3-02) by @Docker-Hunterpedia in #100
- feat(rules): workflow rules engine, time-based rules and the rule builder (M3-03, M3-04, M3-05) by @Docker-Hunterpedia in #101
- feat: macros and canned responses, and the admin audit log viewer (M3-06, M3-08) by @Docker-Hunterpedia in #102
- feat(notifications): in-app, email and web push notifications with per-user preferences (M3-07) by @Docker-Hunterpedia in #103
- docs: close out M2 Email channel and M3 Automation and SLAs by @Docker-Hunterpedia in #105
- docs: start M4 Widget and realtime and M5 Help center by @Docker-Hunterpedia in #127
- fix(api): deliver sign-in links, password resets and invitations by email; 0.2.0 release notes by @Docker-Hunterpedia in #128
- chore: version packages by @github-actions[bot] in #98
Full Changelog: v0.1.0...v0.2.0
Helpdock 0.1.0
The first release: M0 Skeleton and M1 Ticketing core. Helpdock is now a
working staff ticket desk — brands, departments and teams, tickets with a full
workspace, contacts, views and search — behind the tenancy, auth and install
foundations of M0. Customers cannot reach it yet: there is no email channel,
help center or widget. Pre-alpha: expect breaking changes before 1.0.
M1 Ticketing core
- Brands, departments and teams. Ticketing settings per brand, departments
with an Arabic name and a default team, and team members scoped to the
departments they can reach. - Tickets under department scope. Tickets, messages, internal notes and an
activity log under row-level security that hides a department's tickets from
anybody outside it. Every change reaches open screens in real time. - One state machine for every status change, with a per-brand reopen policy,
"awaiting customer" on an agent reply, and escalation. - The ticket workspace. List, thread, composer, details panel and new-ticket
dialog, in English and Arabic, with a collision indicator when two agents are
on the same ticket. - Saved views and search. Personal and shared views with sidebar counts, and
ticket search through a token table (ADR 0011), so a search that finds nothing
stays fast under row-level security. - Contacts and accounts, with verified-only automatic merging, duplicate
suggestions and a 24-hour undo. - Desk tools. Tags, custom fields and templates; round-robin and skill-based
assignment; merge (with a 24-hour unmerge) and split; spam and a sender block
list; time tracking; CSAT rating links; attachments with a media pipeline that
re-encodes images, voice notes and video posters. - Retention. Per-brand retention with a nightly purge and contact
anonymisation.
Upgrade notes
- New, optional:
HD_SETUP_TOKEN. When set (at least 32 characters), the
first-run wizard asks for it as a "Setup key" before it creates the admin
account, so nobody who cannot read the server's.envcan claim a fresh
install. Set it before the host is reachable from the internet. Unset, the
wizard behaves as before. See the install guide. - Development MinIO now comes from Chainguard's public image.
Security
- The first-run wizard can be gated by
HD_SETUP_TOKEN(above). - Fixes for the first CodeQL findings: remote response headers can no longer
write to an object prototype, the SMTP deadline is capped at ten seconds, and
an admin asset path is proven to be inside the build before the file system is
touched.
M0 Skeleton
The foundation every later milestone builds on: an install you can stand up,
sign in to and watch.
- One deploy, many brands, enforced in Postgres. Every tenant table carries
brand_idunder aFORCEd row-level-security policy, every request runs
inside a transaction that sets theapp.*session settings, and every route
declares the permission it needs. A negative test suite proves brand A cannot
read brand B. - Install and run with Docker Compose. One image with
APP_ROLE=api|worker,
a Compose stack with Caddy, Postgres 17 with pgvector, Redis and MinIO, and
on-demand TLS that only answers for a verified help-center domain. - A first-run wizard. A brand-new install lands on four steps: the admin
account, the first brand, outgoing email, done. - Four ways to sign in. Password (argon2id), sign-in link, Google and
GitHub, each with TOTP and recovery codes, rotating refresh tokens in Redis
and "sign out everywhere". - Staff and roles. Admin, Team Leader, Agent and the Viewer toggle, with
invite, activate, role change, deactivate, reactivate, delete and per-brand
removal. - An admin shell in English and Arabic, right-to-left included, with the
System page reporting version, commit, queues and dependency health. - The plumbing later milestones need: a Socket.IO
/staffnamespace with
presence, a transactional outbox with a crash-safe relay, an SSRF-safe
outbound HTTP client, pino logs with request and brand ids, OpenTelemetry and
/metrics.
Not in this release
Email, automation and SLAs, the help center, the widget, the Telegram channel,
AI and the public API. They are M2 to M8 in the PRD.
What's Changed
- chore: add CODEOWNERS by @Docker-Hunterpedia in #1
- docs: add license, README, security policy and contributing guide by @Docker-Hunterpedia in #2
- docs: add DOMAIN-RULES and close PRD review findings by @Docker-Hunterpedia in #3
- docs: start M0 and record ADRs 0001-0005 by @Docker-Hunterpedia in #19
- docs: add DESIGN.md design system and UI rules by @Docker-Hunterpedia in #20
- feat: scaffold monorepo with Turborepo, Biome, Vitest and CI (M0-01) by @Docker-Hunterpedia in #21
- docs: record M0-01 and M0-12 shipped in M0 milestone doc by @Docker-Hunterpedia in #22
- docs: add design-first rule for every screen by @Docker-Hunterpedia in #23
- feat: config loader with secret encryption and settings invalidation (M0-02) by @Docker-Hunterpedia in #25
- feat: add @helpdock/net SSRF-safe outbound HTTP client (M0-15) by @Docker-Hunterpedia in #24
- feat: design tokens, MUI theme and en/ar catalogs (M0-07 foundations) by @Docker-Hunterpedia in #26
- docs: record derivation rules made concrete by packages/ui by @Docker-Hunterpedia in #27
- docs: use Helpdock as the example brand in planning docs by @Docker-Hunterpedia in #29
- feat: Drizzle schema, migrations and row-level security (M0-03) by @Docker-Hunterpedia in #28
- feat: transactional outbox relay and idempotent consumers (M0-14) by @Docker-Hunterpedia in #30
- feat: admin shell with sign-in, two-factor and the empty nav (M0-07) by @Docker-Hunterpedia in #31
- feat: tenancy plumbing and the NestJS application (M0-04) by @Docker-Hunterpedia in #33
- docs: record six more M0 deliverables shipped by @Docker-Hunterpedia in #34
- feat: Docker image, Compose stack and Caddy on-demand TLS (M0-09) by @Docker-Hunterpedia in #35
- feat: staff authentication, sessions and the admin http adapter (M0-05) by @Docker-Hunterpedia in #37
- test: fix stale-snapshot race in the jobs consumer integration suite by @Docker-Hunterpedia in #39
- feat: observability and the admin System page (M0-10) by @Docker-Hunterpedia in #38
- docs: align ARCHITECTURE §14 with the observability implementation by @Docker-Hunterpedia in #40
- feat: roles and the staff lifecycle (M0-06) by @Docker-Hunterpedia in #42
- feat: realtime gateway skeleton, rooms and staff presence (M0-13) by @Docker-Hunterpedia in #44
- feat: first-run wizard for a brand-new install (M0-08) by @Docker-Hunterpedia in #41
- feat: CI, the route input-validation check, screenshot baselines and the M0 close-out (M0-11) by @Docker-Hunterpedia in #60
- test: pin the clock in the relay-status metrics tests by @Docker-Hunterpedia in #62
- docs: start M1 Ticketing core by @Docker-Hunterpedia in #61
- feat: contacts, accounts and the identity seam (M1-04) by @Docker-Hunterpedia in #64
- test: baseline the contacts screens (M1-04) by @Docker-Hunterpedia in #65
- feat: tickets, threads and the activity log (M1-02, M1-03) by @Docker-Hunterpedia in #63
- docs: team membership follows the role-change ceiling by @Docker-Hunterpedia in #68
- feat: brands, departments, teams and team members (M1-01) by @Docker-Hunterpedia in #66
- feat: ticket state machine, escalation and the Statuses tab (M1-08) by @Docker-Hunterpedia in #69
- feat: attachments and the media pipeline (M1-10) by @Docker-Hunterpedia in #71
- feat: tags, custom fields and ticket templates (M1-06) by @Docker-Hunterpedia in #72
- feat: the ticket workspace (M1-15, part 1) by @Docker-Hunterpedia in #70
- feat: assignment, merge and split, spam, CSAT and time, identity rules, retention, and the list gate (M1-07, 09, 11, 12, 13, 14, 15) by @Docker-Hunterpedia in #73
- feat: saved views, search through a token table, and the last workspace...