LogTide

Changelog & Roadmap

What we've shipped and what's coming next.

36
Releases
v0.9.3
Latest
2
Planned
Released
In Progress
Planned
Roadmap
v1.0
Planned
Feature
H2 2026

Beta Release Target

Scheduled digest reports, webhook event receivers, full documentation coverage, migration guides from ELK/Datadog/Loki, and production-ready Helm chart.

  • Scheduled digest reports via email
  • Webhook event receivers
  • Full documentation coverage
  • Migration guides for ELK, Datadog, Loki
  • Production-ready Helm chart

Planned for v1.0 Beta

  • Scheduled Digest Reports — Email-based summaries on a configurable schedule
  • Webhook Event Receivers — Accept events from external services and integrations
  • Full Documentation — Complete documentation coverage for all features
  • Migration Guides — Step-by-step guides for migrating from ELK, Datadog, and Grafana Loki
  • Helm Chart Stable — Production-ready Kubernetes deployment via Helm
v1.x
Planned
Feature
H2 2026

Stable Release & Enterprise Features

Performance hardening, enterprise SSO/SAML, advanced RBAC, managed cloud GA, and tiered storage with hot/warm/cold data lifecycle.

  • Performance hardening for production scale
  • Enterprise SSO/SAML
  • Advanced RBAC
  • Managed cloud GA
  • Tiered storage (hot/warm/cold)

Planned

  • Performance Hardening — Production-scale optimization and stress testing
  • Enterprise SSO/SAML — SAML 2.0 integration for enterprise identity providers
  • Advanced RBAC — Fine-grained role-based access control
  • Managed Cloud GA — General availability of the hosted LogTide cloud service
  • Tiered Storage — Hot/warm/cold data lifecycle management for cost optimization
2026
v0.9.3
Released
Feature

Traces Live Tail, Dashboard Panels & Async Ingestion Buffer

Traces gain live tail (SSE), row expand, keyboard shortcuts and export; monitoring reorganized into tabs; user settings promoted to a full page; new trace_volume and activity_overview dashboard panels; opt-in ReservoirBuffered async ingestion with in-memory and Redis Streams transports.

  • Traces live tail via SSE, inline span expand, j/k/enter/r keyboard shortcuts and JSON/CSV export
  • Monitoring page split into Monitors / Incidents / Maintenance / Status page tabs with summary cards
  • User settings promoted from dialog to full page at /dashboard/account
  • New trace_volume and activity_overview dashboard panels using continuous aggregates with raw fallback
  • Opt-in ReservoirBuffered async ingestion: in-memory (signal-wakeup) and Redis Streams transports with DLQ, circuit breaker and Prometheus metrics

Added

  • Traces live tail (SSE): new GET /api/v1/traces/stream Server-Sent Events endpoint polls the traces table once a second and emits new trace_ids as they appear, filtered by projectId, service (CSV) and error. On the frontend the traces page now has a “Live tail” switch + rows-limit selector (50/100/200/500/1000, persisted in localStorage) in the filter bar; incoming traces are prepended and the list is capped at the chosen limit. The tracesEventSource is torn down on onDestroy and on every filter-key change
  • Traces row click-to-expand with inline span list: clicking a trace row now toggles an inline panel below it that fetches GET /api/v1/traces/:traceId/spans once (cached per trace_id for the session) and shows a compact table with Service / Operation / Kind / Duration / Status for each span. The “View” action still opens the full trace detail page
  • Traces keyboard shortcuts: / focuses the Trace ID input, r refreshes, j/k move the selection down/up with scroll-into-view, enter expands/collapses the selected trace. Registered via shortcutsStore under scope traces and unregistered on destroy
  • Traces export (JSON / CSV): new Export popover in the filter bar produces a client-side download of the current list (disabled during live tail or when the list is empty). CSV covers start_time / service / operation / duration_ms / span_count / error / trace_id
  • Monitoring entry in the command palette: cmd+k now lists Monitoring under Navigation (icon + g o shortcut hint), matching the sidebar’s Detect group so the page is reachable without leaving the keyboard
  • trace_volume dashboard panel: new panel type that plots span count over time (optional errors line), configurable time range (1h/6h/24h/7d) and optional service filter. Mirrors the shape of the existing logs “Log Volume” panel but for OTLP traces. Reads the spans_hourly_stats / spans_daily_stats continuous aggregate first, falling back to the raw spans hypertable with date_trunc only when the cagg is empty for the window (covers the end_offset=1h refresh lag on freshly-ingested data). TimescaleDB-only
  • activity_overview dashboard panel: unified multi-series timeline combining logs, log errors, spans, span errors, detection events and alert triggers on a common bucket grid (hourly for ≤24h, daily for 7d/30d). Each series is individually toggleable in the config form. Per-source queries run in parallel and prefer the logs_*_stats, spans_*_stats, detection_events_*_stats continuous aggregates for cost; if a cagg returns zero rows for the window the fetcher falls back to the raw hypertable (logs, spans, detection_events) for that source only, so the panel stays correct on freshly-ingested data without running a raw scan in the hot path. Alerts always come from alert_history + alert_rules (no cagg exists for it)

Changed

  • Monitoring page reorganized into tabs: what was a single 1000-line scroll with three unrelated sections (Monitors, Incidents, Maintenance) plus a status-page config block wedged at the top is now a Tabs.Root with four tabs — Monitors, Incidents, Maintenance, Status page — each with its own header, its own primary CTA, and its own empty state. The Monitors tab gains a summary card grid (Total / Up / Down / Paused, each card clickable to filter the list by that status), a search input that matches name / target / type, and a “Clear filters” shortcut. Every row now has a one-click Pause/Resume button (previously buried in the edit form). Status-page visibility, password, slug and embed-badge config moved into the Status page tab. No changes to underlying API calls or permissions
  • Admin dashboard sidebar collapses on mobile: the 256px admin sidebar was previously always visible, taking up a huge chunk of the viewport on phones. It now hides below lg: and opens as a fixed drawer triggered by a hamburger in a new mobile-only sticky header that also shows the current section name (Dashboard / Users / Organizations / etc). The drawer has a backdrop, is dismissed on nav-click or backdrop-click, and locks body scroll while open. Desktop behaviour unchanged
  • Dashboard footer wraps properly on mobile: was a single justify-between row that squeezed “LogTide / Alpha v0.9.2” against ”© 2026 LogTide · Documentation · GitHub” on narrow screens. Now stacks the brand block over the links block below sm: (each block keeps its own horizontal flow with flex-wrap gap-x-4 gap-y-1), and “Documentation” shortens to “Docs” under sm: to fit on a single line. Container padding also drops from px-6 py-4 to px-4 py-3 on mobile
  • User settings promoted from a dialog to a full page at /dashboard/account. The cramped scrollable UserSettingsDialog modal (profile + password + tutorial restart + danger zone stacked inside a 32rem-wide overlay) is now a proper route using a max-w-3xl container with each concern split into its own rounded-lg border bg-card section (Profile / Change password / Onboarding / Danger zone). The dropdown menu item still says “User Settings” but now navigates instead of opening an overlay. UserSettingsDialog.svelte is removed. The delete-account confirmation remains a nested AlertDialog since that one is genuinely destructive and modal-appropriate
  • Public status page polished for mobile and clarity: outer container shrinks from px-4 py-10 to px-3 py-6 on phones (only sm: and up gets the roomy desktop padding). The 45-day uptime bars drop their min-w-[6px] floor to 4px on mobile so the whole row fits comfortably on 320px viewports. The footer (“Last updated …” and “Powered by LogTide”) grows from text-[10px] to text-xs with a taller top margin, and “LogTide” is now styled as text-primary font-medium hover:underline so the link affordance is obvious (previously only a hover recolor). Incident update timestamps/status labels also bumped from text-[10px] to text-xs. The monitor-type badge (HTTP/TCP/etc.) hides below sm to free up the row for the name + uptime%. The password input switches from a fixed w-64 to w-full max-w-xs so it never overflows narrow phones
  • Monitoring forms moved into modal dialogs: the previous inline create/edit monitor form, the “New incident” form, the “Post incident update” form and the “Schedule maintenance” form were expanding/collapsing sections that shifted the whole page layout when opened. They now open as centered Dialog modals with max-h-[90vh] overflow-y-auto so tall forms (monitor create) scroll independently of the page. The per-row “Post update” Dialog is a single instance driven by a showUpdateForm id + an updatingIncident derived lookup, replacing the one-per-row inline expand. Form state, validations and submit handlers are untouched
  • Traces filter UI reworked into the same two-row pill bar as the search page: row 1 keeps Time Range (TimeRangePicker in a popover), the Live tail switch, the List/Map view toggle and the Export menu. Row 2 exposes every filter as its own always-visible pill — Project (single-select), Services (multi-select), Status (tri-state: all / errors / ok), Duration range (min/max ms inputs), Trace ID (direct-navigate to the trace detail page). Pills switch to the secondary variant when a non-default value is set; “Clear all” appears when any filter is active. Mobile popovers use w-[Xpx] max-w-[90vw] so they never overflow the viewport. handleTimeRangeChange syncs picker state back into timeRangeType / customFromTime / customToTime so the trigger label survives popover close/remount
  • Traces backend accepts multi-value projectId and service (CSV on the query string) and two new minDurationMs / maxDurationMs bounds on GET /api/v1/traces. The cross-project access check loops over every project in the list. tracesService.listTraces widens its input types to string | string[] and forwards to reservoir.queryTraces, which already supported these filters
  • Search page paginator now uses the same ellipsis/windowed control as the traces page: shows up to four numbered buttons plus sentinel on each side when totalPages > 7. Falls back to the previous “Page N” label when the backend doesn’t return a total (storage engines without total in the query response). “Previous” / “Next” labels hide on <sm screens so only the chevron shows on phones
  • Empty states wait for the first load to complete before rendering on the search, traces, errors and security-incidents pages. Each page now tracks a hasLoadedOnce flag flipped in the finally branch of its loader; until the first fetch resolves (success or failure) the page shows its skeleton instead of the “No Logs Yet / Start sending logs from your applications” onboarding card. Prevents the flash where an org that already has data showed the onboarding CTA during the initial render between mount and the first query. When a fetch legitimately returns zero rows, the page also distinguishes “nothing matches these filters” (with a Clear-filters shortcut) from “project has no data at all” (the full onboarding)
  • Search page filter UI reworked into a two-row pill bar: row 1 keeps Search + mode, a Time Range popover trigger, Live Tail and Export inline. Row 2 exposes every filter as its own always-visible pill (Projects, Services, Hostnames, Levels, Trace ID, Session ID, Metadata) — each pill displays the current value (e.g. “Service: api-gateway”, “Levels: 2”) and opens its own popover for editing. Pills switch to the secondary variant when a non-default value is set so active filters are visible at a glance. A “Clear all” link appears at the end of the row when any filter is active. Popover widths use w-[min(Xpx,calc(100vw-1rem))] so they never overflow the viewport on phones. No semantic change to the underlying filter behavior (state, query params, live-tail flow, metadata apply/clear) - purely a layout/affordance pass replacing the previous six-column “Filters” Card
  • Auto-created Default dashboard now uses the new activity_overview panel instead of the logs-only time_series “Log Volume” chart. Existing organizations keep their current dashboard untouched; the swap only affects orgs that don’t yet have a default (i.e. new signups or orgs where the default was deleted and re-seeded via ensureDefaultExists)
  • Opt-in async buffer for reservoir writes: new ReservoirBuffered decorator sits between the ingestion API and the storage engine. When enabled via RESERVOIR_BUFFER_ENABLED=true, POST /api/v1/ingest returns as soon as records are accepted into a shard-partitioned queue; a flush consumer pool drains to storage asynchronously. Two transports ship in the box: an optimized in-memory queue with signal-based wakeup (single-instance, not crash-safe) and a Redis Streams transport with consumer groups, XAUTOCLAIM-based stale reclaim, atomic MULTI/EXEC nack, and a DLQ side stream (multi-instance, durable). Circuit breaker bypasses to sync ingestion when the buffer fills beyond a configurable pending threshold or after repeated flush failures in a rolling window. Off by default; see docs/async-buffer/ for when to enable and the per-engine benchmark table
  • IReservoir shared interface: public type that Reservoir and ReservoirBuffered both implement, so downstream code (backend monitoring, etc.) can type against IReservoir without caring which implementation is live
  • Prometheus-style buffer metrics: reservoir_buffer_enqueued_total, reservoir_buffer_bypass_total, reservoir_buffer_flush_success_total, reservoir_buffer_flush_failure_total, reservoir_buffer_flush_duration_ms (histogram), reservoir_buffer_dlq_total, reservoir_buffer_breaker_state (0 closed / 1 open / 2 half-open). All labelled by record kind and shard where applicable
  • Warning at startup when buffer is enabled on non-Timescale engines: benchmarks show the buffer regresses p95 under saturation on ClickHouse and MongoDB (the bottleneck is the flush side, which the buffer cannot hide). The backend now logs a clear warning with a link to the docs when RESERVOIR_BUFFER_ENABLED=true is set together with STORAGE_ENGINE=clickhouse or STORAGE_ENGINE=mongodb
  • k6 load-test script load-tests/buffered-vs-sync.js (pnpm --filter @logtide/backend load:buffered-vs-sync): constant-arrival-rate 100 req/s for 3 min, batch size 10, reports p50/p95/p99 + error rate. The file lives in the gitignored load-tests/ directory; only the npm script is checked in
  • Graceful shutdown now drains the reservoir buffer in parallel with Fastify app.close(): previously serialized, so a slow app.close() (BullMQ workers, websocket connections) could exhaust the container stop timeout before shutdownReservoir() ran. The new order calls them via Promise.all, giving the buffer its full RESERVOIR_BUFFER_GRACEFUL_SHUTDOWN_MS window to drain regardless of how long app.close() takes
  • Redis client in the backend’s buffer path is now explicitly quit()-ed on shutdown: RedisStreamTransport documents that it does not own the client, so the backend owns the lifecycle. Without this, the Redis connection was torn down by the process exit instead of closing cleanly
  • Buffer start-up failure is fail-fast: when RESERVOIR_BUFFER_ENABLED=true and the consumer pool cannot start (e.g. Redis down at boot), the backend logs a CRITICAL message and process.exit(1) instead of silently continuing with a non-flushing buffer
  • RedisStreamTransport hardening: XPENDING now filters by consumer name in claimStale, so delivery-count mapping is accurate even on busy streams with claims from other consumers; getStats.oldestPendingAgeMs now tracks the oldest not-yet-delivered entry (via XRANGE with exclusive start past the PEL tail) to match the documented contract; nack uses MULTI/EXEC so the DLQ write and the original ACK either both land or neither does; enqueueMany inspects pipeline exec() results and throws on the first error instead of swallowing them; default consumer name changed from consumer-${pid} to ${hostname}-${pid}-${randomHex} to avoid collisions between containers with the same PID
  • FlushConsumer isolates partial failures by kind: the three ingest calls (ingest, ingestSpans, ingestMetrics) now run via Promise.allSettled; the breaker records success only when all three succeed; metrics reflect per-kind reality; DLQ only counts the failed kinds on retry exhaustion. An optional FlushLogger can be injected; default falls back to console
  • FlushConsumerPool relaxes drain check to pendingRecords == 0: previously also required inflightRecords == 0, which never converged when another backend instance held claims on the same Redis consumer group. Consumer-task crashes are now surfaced via logger.error instead of being swallowed by Promise.allSettled. Drain poll bumped from 50 ms to 200 ms to reduce chatter
  • InMemoryTransport uses signal-based wakeup: dequeue no longer polls every 50 ms; enqueues wake waiters directly via a per-shard resolver list, and stop() unblocks waiters promptly. enqueueMany now batches records into a single Array.push(...entries) per shard plus one wake, eliminating the N-await bottleneck that made the in-memory buffer slower than sync on fast TimescaleDB workloads (p95 dropped from 4224 ms to 24 ms in the 3-min 100 req/s test)
  • Reservoir exposes getEngine() on the concrete Reservoir class (not on IReservoir): replaces the (inner as unknown as { engine }).engine cast inside ReservoirBuffered’s constructor. Kept out of the public interface so backend consumers typed against IReservoir cannot reach the engine and bypass the decorator
  • ReservoirBuffered.ingest/ingestSpans/ingestMetrics return the correct IngestResult shape: { ingested, failed, durationMs } instead of the previous { inserted } masked by as unknown as casts. durationMs measures the enqueue time, so the value reflects the real cost imposed on the caller
v0.9.2
Released
Feature

Metadata Filters, Admin User Creation & Org-Scoped Status URLs

Generic metadata filters across log search and alert rules, admin-driven user provisioning, editable org/project slugs, org-scoped public status page URLs (BREAKING), plus SIEM heatmap crash fix and three fastify/SvelteKit security bumps.

  • Generic metadata filter builder with 7 operators, backed by GIN-indexed JSONB queries and shared with alert rules
  • Configurable metadata.* columns in the log search table, persisted per project
  • Admins can create users from the dashboard (#198) without enabling public signup
  • BREAKING: public status page URLs moved to /status/:orgSlug/:projectSlug
  • Security: fastify 5.8.5 and SvelteKit 2.57.1 bumps (3 CVEs, 2 HIGH / 1 MEDIUM)

Added

  • Generic metadata filters in log search and alert rules: the search page and alert rule dialogs now expose a “Metadata filters” section backed by a new MetadataFilterBuilder component. Supported operators: equals, not_equals, in, not_in, exists, not_exists, contains. Filters are applied server-side via a GIN-indexed JSONB query builder in reservoir; alert evaluation also runs the same matcher in-process so rules can fire only when a specific metadata field matches
  • Configurable metadata columns in log table view: users can add arbitrary metadata.* keys as extra columns in the search results table via a “Columns” picker. The selected column set is persisted per project in localStorage so it survives page reloads
  • Create user from admin panel (#198): admins can now provision new accounts directly from Admin → User Management via a “Create User” button, without having to temporarily re-enable public signup. Opens a dialog to set email, name, password and optional admin role. Backed by a new POST /api/v1/admin/users endpoint that bypasses the auth.signup_enabled gate and logs a create_user entry to the audit log
  • Set a custom dashboard as default from the UI: the dashboard switcher now shows a clickable star next to each org-wide, non-personal dashboard; clicking it promotes that dashboard to be the org’s default. Backed by a new POST /api/v1/custom-dashboards/:id/set-default endpoint that atomically unsets the previous default and sets the new one in a single transaction, respecting the existing partial unique index. Personal and project-scoped dashboards are rejected with a 400
  • Editable project slug from monitoring page: the status-page settings card in /dashboard/monitoring now exposes a “Public URL slug” input that lets the user rename a project’s slug, with inline validation against a shared format check (lowercase alphanumeric + hyphens, 2-50 chars), reserved-word list (api, admin, dashboard, status, auth, login, signup, logout, _app, health), and per-org uniqueness. Conflicts surface as 409 with a friendly inline error; race conditions are caught at the DB layer via the new composite unique index
  • Editable organization slug from settings: /dashboard/settings/general slug field is no longer read-only; owners can rename the org slug with the same validation rules and global uniqueness, with a warning that any existing status-page links and embed badges will break

Changed

  • Public status page URL is now scoped under the organization (BREAKING): page and badge URLs changed from /status/:projectSlug to /status/:orgSlug/:projectSlug. Affects the public web page, /api/v1/status/:orgSlug/:projectSlug/badge.svg, and /api/v1/status/:orgSlug/:projectSlug/badge.json. No redirect from the old URLs. Anyone embedding the badge SVG/JSON or sharing a status-page link must update the URL to include the org slug. Migration 040 simultaneously moves project-slug uniqueness from global back to per-org, so two different organizations can now both have a project named frontend without auto-suffixing

Fixed

  • Security dashboard crashed with “Cannot read properties of null (reading ‘toLowerCase’)” (#200): root cause was two parallel unnest(mitre_techniques) / unnest(mitre_tactics) calls in the same SELECT list of SiemDashboardService.getMitreHeatmap. PostgreSQL evaluates sibling set-returning functions in lockstep and NULL-pads the shorter array, so any detection event whose tactic and technique arrays had different lengths produced heatmap rows with a null tactic, which then crashed MitreHeatmap.abbreviateTactic on the frontend. The heatmap query now unnests techniques only and resolves each one to its canonical tactic via the shared MITRE_TECHNIQUES map (with sub-technique to parent fallback), eliminating the malformed pairs at the source. Frontend MitreHeatmap also filters cells with null tactic/technique and DetectionEventsList.getLogLevelClass defensively handles a null level as belt-and-suspenders

Security

  • Bump fastify to 5.8.5 (GHSA-247c-9743-5963, CVE-2026-33806, HIGH): body schema validation could be bypassed by prepending a single space to the Content-Type header. Parser and validator disagreed on how to trim the header, so the body was still parsed but the schema lookup returned no validator and validation was skipped entirely. Upgraded from ^5.8.3 to ^5.8.5
  • Bump @sveltejs/kit to 2.57.1 (GHSA-2crg-3p73-43xp, CVE-2026-40073, HIGH): BODY_SIZE_LIMIT could be bypassed under certain conditions in adapter-node. Tightened the pnpm override from >=2.53.3 to >=2.57.1
  • Bump @sveltejs/kit to 2.57.1 (GHSA-3f6h-2hrp-w5wx, CVE-2026-40074, MEDIUM): calling redirect inside the handle hook with a location containing characters invalid for an HTTP header threw an unhandled TypeError, enabling DoS if the location included unsanitized user input
v0.9.1
Released
Fix

Security Hardening, Input Validation & Bug Fixes

SQL injection fix in querySpans, ReDoS protection for monitor assertions, 25+ bug fixes across auth, pipelines, SIEM, monitoring, and SSR safety, plus comprehensive input validation on all route params.

  • SQL injection fix in querySpans sortBy/sortOrder for both TimescaleDB and ClickHouse
  • ReDoS protection on HTTP monitor body assertion via safe-regex2
  • UUID validation, positive-int clamping, and max-length guards across all route params
  • PII salt race condition, SSE duplicate sends, and Sigma sync FK corruption fixed
  • localStorage SSR crash guards and URL-encoding fixes in frontend navigation

Fixed

  • Identifier pattern update/delete failed with “Organization ID is required” (#193): PUT and DELETE routes required organizationId as an explicit query param or API key context, but session-based auth never sets that field. Now falls back to the user’s first organization, consistent with GET and POST
  • Project rename failed with “Expected string, received null” (#195): updateProjectSchema used z.string().optional() which rejects null, but projects without a description send null from the DB. Changed to z.string().nullable().optional() and updated UpdateProjectInput accordingly
  • Pipeline create/preview/import returned generic “Validation error” (#193, #194): POST routes expected organizationId in the request body but the frontend sends it as a query param. Routes now merge the query param into the body before Zod validation. Frontend error messages now surface the first validation detail instead of the generic label
  • Invitation accept race condition: wrapping the membership check + insert in a transaction caused the accepted_at update to roll back when throwing “already a member”. Split the early-exit path out of the transaction and added 23505 unique-constraint handling for true concurrent accepts
  • SSE live tail duplicate sends: latestLog picked the oldest entry from a DESC-sorted array instead of the newest, causing every poll to re-fetch and re-send all logs since the oldest timestamp. Replaced with a defensive max-time computation
  • Sigma sync corrupted alert_rule_id FK: fallback alertRuleId || existing.id wrote the sigma rule’s own PK into the alert_rules FK column when no alert was auto-created. Now omits the column entirely unless a new alert rule was just created
  • Exception log viewer returned empty results for org-wide error groups: getLogsForErrorGroup passed an empty string as projectId to reservoir when no project filter was set. Now groups log IDs by their exception’s project_id and issues one getByIds call per project
  • ReDoS in HTTP monitor body assertion: user-supplied regex pattern was compiled with only a 256-char length limit, no catastrophic-backtracking check. Added safe-regex2 validation and a compile-error catch
  • OTLP int64 precision loss: parseInt() silently truncated int64 attribute values exceeding Number.MAX_SAFE_INTEGER. Unsafe values are now kept as strings in metadata
  • PII salt race condition fallthrough: if two workers raced on the first hash for an org, the loser could return an unpersisted local salt when the retry read failed, permanently desynchronizing PII hashes. Now scopes the catch to 23505 and throws on unexpected errors
  • Monitor status fallthrough on missing row: processCheckResult silently skipped the entire state machine (no status update, no notifications) when monitor_status was undefined. Now re-reads from DB or creates a default row before proceeding
  • Test isolation: auth mode pollution across test files: system_settings was never reset between tests, so any test setting auth.mode='none' caused 12 unrelated “401 without auth” assertions to return 503. Added cleanup + cache invalidation to global beforeEach
  • Sigma detection tests used sigma_id after code migrated to id: fixture data still passed rule.sigma_id as sigmaRuleId, which would not match the new .where('id', '=', ...) queries
  • translateDelete dropped level filter in reservoir: pushFilter return value was discarded for the level condition, corrupting $N parameter slots when both service and level filters were present
  • SQL injection in querySpans via sortBy/sortOrder: user-controlled strings were interpolated directly into raw SQL in both TimescaleDB and ClickHouse engines. Added explicit column/direction allowlists
  • ingestSpans hardcoded ::uuid[] for project_id: ignored the projectIdType engine option, breaking text-based project IDs with a Postgres cast error
  • localStorage SSR crash in organization store: 7 direct localStorage calls without a browser guard would throw ReferenceError during server-side rendering. Added browser check on all accesses
  • Invite token not URL-encoded in redirect: goto(/login?redirect=/invite/${token}) corrupted the redirect path for tokens containing +, =, or /. Now wraps in encodeURIComponent
  • ruleId not URL-encoded in security dashboard navigation: inconsistent with serviceName and technique which already used encodeURIComponent
  • Missing UUID validation on monitoring route params: all /:id handlers passed request.params.id directly to DB queries without format validation. Added Zod .uuid() parsing on every route
  • Negative limit/days in monitoring routes: Number("-1") || 50 evaluates to -1 (truthy), passing a negative value to LIMIT. Replaced with a parsePositiveInt guard that clamps to [1, max]
  • Missing UUID validation on status-incident route params: same issue as monitoring - :id params were used unvalidated in DB queries
  • SIEM comment body has no max length: z.string().min(1) with no upper bound allowed arbitrarily large comment payloads. Added .max(10000)
  • Notifications and alerts limit/offset NaN passthrough: parseInt("abc") returned NaN, which was passed to Kysely .limit(NaN). Added safe integer parsing with fallback and max cap
  • Correlation referenceTime accepted invalid date strings: schema validated only {type: 'string'}, so new Date("garbage") flowed into Kysely WHERE clauses as Invalid Date. Added format: 'date-time' and a defensive 400 response
  • Log pipeline comment contradicted jsonb merge direction: code comment said “do NOT overwrite existing” but the in-progress fix had flipped the jsonb || operand order so pipeline fields now win. Updated comment to match actual behavior
v0.9.0
Released
Feature

Service Monitoring, Log Pipelines & Custom Dashboards

Three major features: uptime monitoring with public status pages (#152), log parsing and enrichment pipelines with grok and GeoIP, and fully customizable dashboards with 9 panel types (#151).

  • Service health monitoring with HTTP/TCP/heartbeat checks and public Uptime Kuma-style status pages
  • Log parsing pipelines with 5 built-in parsers, custom grok patterns, and GeoIP enrichment
  • Custom dashboards with 9 panel types, drag-and-drop reorder, resize, and YAML import/export
  • Scheduled maintenances and manual status incidents on public status pages
  • Versioned dashboard schema with migration framework and cross-org isolation guards

Added

Service health monitoring and status pages (#152)

Proactive uptime monitoring with auto-generated public status pages.

  • 3 monitor types: HTTP/HTTPS (configurable method, expected status, headers, body assertion), TCP ping, and heartbeat (alert when no ping received within grace window)
  • HTTP config: per-monitor httpConfig with method, expectedStatus, custom headers, and body assertion (contains or regex) - stored as JSONB, validated via Zod
  • Per-monitor severity: incident severity is configurable per monitor (critical, high, medium, low, informational) instead of hardcoded high
  • BullMQ-style polling: worker checks all due monitors every 30s, batched in groups of 20 concurrent checks via Promise.allSettled
  • TimescaleDB storage: monitor_results hypertable with 7-day compression, 30-day retention, and monitor_uptime_daily continuous aggregate refreshed hourly
  • State machine: consecutive failure tracking with configurable threshold, atomic incident dedup guard (WHERE incident_id IS NULL), auto-resolve on recovery
  • Auto-incident creation: when failure threshold is crossed, a SIEM incident is created with source: 'monitor' and linked via monitor_id; notifications sent via existing email/webhook channels
  • Public status page (/status/:projectSlug): Uptime Kuma-inspired design with 45-day heartbeat bar grid, per-monitor uptime badge, overall status banner, custom CSS tooltips, light/dark mode toggle
  • Status page access control: configurable visibility per project - disabled (default), public, password-protected, or org-members-only
  • Scheduled maintenances: create maintenance windows with start/end times; active maintenances suppress monitor incident creation and display a banner on the status page
  • Manual status incidents: create public incident communications (investigating → identified → monitoring → resolved) with update timeline, independent from SIEM incidents
  • Heartbeat endpoint: POST /api/v1/monitors/:id/heartbeat accepts both API key and session auth, rate-limited to 600/min
  • Project slugs: auto-generated from project name on creation, unique per org, backfilled for existing projects via migration
  • Dashboard UI (/dashboard/monitoring): monitor list with project selector, create/edit/delete forms with client-side validation, detail page with refresh button, uptime chart, recent checks, copy heartbeat URL
  • Monitoring navigation: added to sidebar under “Detect” section alongside Alerts and Security

Log parsing and enrichment pipelines

Define multi-step processing rules that automatically parse and enrich incoming log messages before they are stored.

  • 5 built-in parsers: nginx (combined log format), apache (identical to nginx), syslog (RFC 3164 and RFC 5424), logfmt, and JSON message body
  • Custom grok patterns: %{PATTERN:field} and %{PATTERN:field:type} syntax with 22 built-in patterns (IPV4, WORD, NOTSPACE, NUMBER, POSINT, DATA, GREEDYDATA, QUOTEDSTRING, METHOD, URIPATH, HTTPDATE, etc.) and optional type coercion (:int, :float)
  • GeoIP enrichment: extract country, city, coordinates, timezone, and ISP data from any IP field using the embedded MaxMind GeoLite2 database
  • Async processing via BullMQ: pipelines run as background jobs after ingestion - zero impact on ingestion latency
  • Project-scoped vs org-wide: pipelines can target a specific project or apply to all projects in the organization; project-specific pipelines take priority over org-wide ones
  • Pipeline preview: test any combination of steps against a sample log message and inspect per-step extracted fields and the final merged result before saving
  • YAML import/export: import pipeline definitions from YAML with name, description, enabled, and steps fields; upserts (replace existing pipeline for the same scope)
  • In-memory cache: getForProject caches the resolved pipeline per project for 5 minutes, automatically invalidated on create/update/delete
  • Settings UI (/dashboard/settings/pipelines): list, enable/disable toggle, create, edit, and delete pipelines with live org-switch reactivity ($effect instead of onMount)
  • Step builder: interactive UI for adding, reordering, and configuring parser, grok, and geoip steps with per-type configuration forms
  • Pipeline edit page redirects to the list when the active organization is switched, preventing stale-ID errors

Custom dashboards with configurable panels (#151)

User-built dashboards replace the previous fixed /dashboard page, with team-specific views across all observability domains.

  • 9 panel types covering every data source: time series, single stat, top-N table, live log stream, alert status (logs/alerts), metric chart and metric stat (OTLP metrics with avg/sum/min/max/count/last/p50/p95/p99 aggregations), trace latency (p50/p95/p99 from spans), detection events (SIEM by severity), monitor status (uptime + response time)
  • Panel registry architecture: adding a new panel type touches only 6 files (shared types, backend Zod schema, backend fetcher, frontend panel component, frontend config form, frontend registry entry); the renderer, container, store, and routes never need to change
  • Drag-and-drop reorder via svelte-dnd-action with optimistic local state and a single PUT save
  • Drag-to-resize with bottom-right pointer-event handle, snapping to grid units; constrained by per-type min width/height from the registry
  • Responsive 12/6/1 column grid that collapses panels to 6 columns on tablet (640-1024px) and 1 column on mobile (<640px); stored widths are always in the canonical 12-col reference and scale proportionally
  • Auto-created Default dashboard per organization, idempotent via Postgres unique-violation guard, replicating the previous fixed layout (4 stat cards + log volume + top services + top error messages) so existing users see no visual change
  • Inline edit mode with toggle, no separate edit page; pending changes are kept in a snapshot and discarded on Cancel
  • Per-panel configuration dialogs with type-specific forms (level toggles, intervals, aggregation pickers, percentile selectors)
  • Dashboard switcher dropdown in the page header with personal/shared distinction, create, delete (default protected), import, export
  • YAML import/export: dashboards round-trip through YAML for version-controlling alongside infrastructure code; import regenerates panel IDs and uses JSON_SCHEMA to block JS-tag prototype pollution
  • Versioned JSON schema (schema_version: 1) with a migration framework in @logtide/shared: each version writes a MigrationFn indexed by target version, migrateDashboard walks the chain on every read; clamps out-of-range versions defensively
  • Cross-org isolation guard: every panel data fetch verifies that config.projectId belongs to the requesting org, preventing data leaks via crafted YAML imports or stale references
  • Batch panel data endpoint (POST /:id/panels/data): single round-trip fetches all panel data via Promise.allSettled, individual panel errors do not fail the dashboard
  • Organization scoping: dashboards are org-scoped with optional is_personal flag (only visible to creator) and created_by tracking; partial unique indexes prevent multiple defaults per (org, project) scope
  • Migration 039_custom_dashboards.sql: JSONB panels column with GIN index for future panel-type filtering, partial unique indexes for default scope guarantees

Fixed

  • Status page slug collision: getPublicStatus now filters by status_page_public flag instead of returning the first project matching the slug, preventing cross-org data leaks
  • createMonitor not transactional: monitor and monitor_status inserts are now wrapped in db.transaction() to prevent orphaned monitors
  • mapMonitor typed: replaced any parameter with proper MonitorWithStatusRow interface for compile-time safety
  • Org membership check optimized: monitoring routes now use a single SELECT WHERE user_id AND organization_id query instead of fetching all user orgs and scanning in JS
  • Redundant DB read eliminated: processCheckResult now receives status data from the already-fetched monitor object instead of issuing a second SELECT
  • Target validation on update: PUT endpoint now validates target format against monitor type (HTTP must start with http:///https://, TCP must contain :)
  • $derived.by fix: monitor detail page uptime calculation now uses $derived.by() instead of $derived(() => ...) for correct Svelte 5 reactivity
  • @const placement: replaced invalid {@const} inside <div> elements with {#if}/{:else} blocks for Svelte 5 compatibility
  • uptimePct type coercion: Postgres ROUND() returns numeric as string - status page now coerces to number before calling .toFixed()
  • Default failureThreshold aligned: frontend form default changed from 3 to 2 to match backend default
  • Test setup cleanup: added monitor_results, monitor_status, monitors, incident_alerts to global beforeEach cleanup
v0.8.7
Released
Fix

Ingestion Schema, Sigma Log Noise & Admin Bootstrap Fixes

Quick Start cURL example now validates without a manual timestamp, Sigma worker no longer floods logs on empty detection batches, and fresh instances without INITIAL_ADMIN_* env vars auto-promote the first registered user to admin.

  • logSchema now defaults time to current ISO string so minimal payloads and copy-paste examples validate
  • Sigma worker [SigmaDetection] No matches found log gated behind DEBUG_SIGMA=true
  • First registered user is auto-promoted to admin when no INITIAL_ADMIN_* is set and no admin exists

Fixed

  • Quick Start cURL example failed validation: the empty-state code snippet sent {logs: [{level, service, message}]} without a time field, but logSchema required it for the standard ingestion path (only the array-format path ran normalizeLogData). The schema now defaults time to the current ISO string when missing, so copy-paste examples and minimal payloads validate without requiring users to inject a timestamp.
  • Noisy Sigma worker logs: [SigmaDetection] No matches found was emitted at info level on every batch with no detections, flooding worker output in normal operation. The line is now gated behind DEBUG_SIGMA=true so it only appears when explicitly opted in.
  • *No admin user when INITIAL_ADMIN_ not set (#188)**: on a fresh instance without INITIAL_ADMIN_EMAIL/INITIAL_ADMIN_PASSWORD, no usable admin existed and admin settings were unreachable. The bootstrap no longer creates a system fallback user; instead, the first user to register (via /register or external auth provider) is automatically promoted to admin if no admin exists yet.
v0.8.6
Released
Fix

ClickHouse Data-Availability & Session Validation Fixes

Fixed ClickHouse traces/metrics data-availability queries failing due to raw epoch date parameters, and resolved stale dashboard sessions after volume resets.

  • ClickHouse traces/metrics data-availability queries now use toDateTime64() clamp instead of raw epoch dates
  • Dashboard validates session token against backend on load and auto-logs out on invalid session

Fixed

  • ClickHouse traces/metrics data-availability always empty: queryTraces and queryMetrics passed raw 0 for epoch dates as DateTime64(3) parameter, which ClickHouse can’t parse; now uses the same toDateTime64() clamp used by log queries
  • Stale session after volume reset: dashboard only checked localStorage for a token without validating it against the backend; now calls /auth/me on load and auto-logs out if the session is invalid
v0.8.5
Released
Fix

Security Hardening, SSE Fixes & Memory Leak Cleanup

Five cross-org and auth security fixes, corrected SSE real-time streams, resolved 20+ Svelte memory leaks on navigation, and multiple bug fixes across SIEM, incidents, webhooks, and retention jobs.

  • Cross-org isolation and auth bypass fixes in SIEM and pattern routes
  • SSRF protection for legacy webhook path and disabled-user login blocked
  • SSE real-time events and log stream duplicate emission fixed
  • 20+ Svelte memory leaks from unsubscribed auth stores resolved
  • Docker config sync and dependency security bumps (picomatch, brace-expansion, fast-xml-parser)

Security

  • Cross-org isolation fix in SIEM: linkDetectionEventsToIncident now scopes detection events to the requesting organization, preventing cross-tenant data corruption via crafted API calls
  • Cross-org auth bypass in pattern routes: PUT and DELETE handlers for correlation patterns now verify organization membership before mutating data (same check GET/POST already had)
  • SSRF protection for legacy webhook path: the alert-notification job’s direct fetch() call now validates URLs against private/internal IP ranges, matching the WebhookProvider safeguard
  • Disabled user login blocked: POST /login now checks the disabled flag before creating a session, preventing disabled accounts from obtaining tokens
  • Expired invitation info leak: getInvitationByToken now filters on expires_at > NOW(), preventing enumeration of expired invitation details

Fixed

  • SIEM dashboard timeline crash: time_bucket() call was missing ::interval cast on the parameterized bucket width, causing a PostgreSQL type error that broke the timeline widget for all users
  • SSE real-time events broken: SIEM store and incident detail page read auth token from localStorage('session_token') (wrong key), so the SSE connection never authenticated; now uses getAuthToken() from the shared auth utility
  • SSE log stream duplicate emission: when multiple logs shared the same timestamp, the inclusive from bound caused them to be re-sent on every poll tick; stream now tracks sent log IDs to deduplicate
  • Incident severity auto-grouping wrong: MAX(severity) used PostgreSQL alphabetical ordering (medium > critical), producing incorrect severity on auto-grouped incidents; now uses ordinal ranking
  • Sigma notification failures silent: notification job payload was missing organization_id and project_id, and markAsNotified was called with null historyId; both now handled correctly
  • Incidents pagination total always zero: loadIncidents in the SIEM store never wrote response.total to incidentsTotal
  • Memory leaks on navigation: 20+ Svelte components called authStore.subscribe() without cleanup; all now store the unsubscribe function and call it in onDestroy
  • offset=0 silently dropped: API client functions used if (filters.offset) which is falsy for zero, so page-1 requests never sent the offset parameter; changed to if (filters.offset != null)
  • Search debounce timer leak: searchDebounceTimer was not cleared in onDestroy, causing post-unmount API calls when navigating away mid-search
  • verifyProjectAccess double call: when projectId is an array, the first element was verified twice (once before the loop, once inside it); consolidated into a single loop
  • updateIncident silent field skip: title, severity, and status used truthy checks (&&) instead of !== undefined, inconsistent with description and assigneeId
  • Webhook error messages empty: response.statusText is empty for HTTP/2; error now reads the response body for useful detail
  • Retention job crash on empty orgs: Math.max(...[]) returns -Infinity, cascading to an Invalid Date in the drop_chunks call; early return added when no organizations exist
  • escapeHtml DOM leak: PDF export’s escapeHtml created orphaned DOM nodes in the parent document; replaced with pure string replacement
  • Webhook headers validation missing: CreateChannelDialog silently swallowed invalid JSON in the custom headers field; now validates on submit
  • getIncidentDetections no org scope: query now accepts optional organizationId for defense-in-depth filtering
  • Stale shared package types: dist contained outdated Project and Incident interfaces with phantom fields (slug, statusPageVisibility, source, monitorId); rebuilt from source

Changed

  • Docker config sync: docker-compose.build.yml now matches docker-compose.yml with all environment variables (MongoDB, TRUST_PROXY, FRONTEND_URL, INTERNAL_DSN, DOCKER_CONTAINER), MongoDB service, and fluent-bit-metrics service
  • NODE_ENV for backend: production docker-compose.yml now sets NODE_ENV: production on the backend service (worker and frontend already had it)
  • docker/.env.example: added STORAGE_ENGINE, ClickHouse, and MongoDB configuration sections

Dependencies

  • picomatch 4.0.3 → 4.0.4 (fix ReDoS via extglob quantifiers + POSIX character class method injection)
  • brace-expansion 5.0.2 → 5.0.5 (fix zero-step sequence DoS)
  • fast-xml-parser 5.5.6 → 5.5.9 (fix entity expansion limits bypass)
  • fastify bumped via dependabot
  • kysely bumped via dependabot
v0.8.4
Released
Feature

Skeleton Loaders, Helm Auto-Release & Performance Fixes

All dashboard pages now show content-shaped skeleton loaders, automated Helm chart releases on every stable Docker image, and multiple performance and correctness fixes for API endpoints and admin pages.

  • Skeleton loaders and loading overlays on all dashboard pages
  • Automated Helm chart releases triggered on every stable Docker image release
  • API 400 responses now include field-level validation errors
  • Fixed admin pages returning 502 on direct load/reload
  • POST /api/v1/logs/identifiers/batch performance: bypasses storage engine, one PostgreSQL query
  • GET /api/v1/logs/hostnames 8+ second queries fixed with engine-specific indexes and a 6h window cap

Added

  • Skeleton loaders and loading overlays: all dashboard pages now show content-shaped loading states instead of blank spinners
    • New Skeleton, SkeletonTable, and TableLoadingOverlay components (src/lib/components/ui/skeleton/)
    • Directional shimmer animation via @keyframes shimmer using design tokens — works in light and dark mode, disabled for prefers-reduced-motion
    • Initial load (no data yet): animated skeleton rows mirroring the page layout — stat cards on /dashboard, project cards on /dashboard/projects, table rows on search, traces, errors, admin tables, incidents, alerts history, and members
    • Re-fetch (filter change, pagination): existing content dims with a translucent overlay and centered spinner, preventing layout shift and context loss
    • Pages updated: /dashboard, /dashboard/search, /dashboard/projects, /dashboard/alerts, /dashboard/errors, /dashboard/traces, /dashboard/security, /dashboard/security/incidents, /dashboard/admin/organizations, /dashboard/admin/users, /dashboard/admin/projects, /dashboard/settings/members
  • Automated Helm chart releases: every stable Docker image release now triggers a repository_dispatch to logtide-dev/logtide-helm-chart, which auto-bumps appVersion and chart version (patch), commits, and publishes a new chart release to the Helm repo on GitHub Pages

Fixed

  • API 400 responses now include a details array with field-level validation errors instead of just a generic message. Covers both Fastify/AJV schema validation and Zod validation errors (including uncaught ZodError that previously returned 500)
  • Admin pages returned 502 Bad Gateway on direct load/reload: the admin layout ([email protected]) breaks out of the dashboard layout chain, so ssr = false was not inherited; added a dedicated +layout.ts to the admin section
  • /dashboard/admin/projects/[id] crashed with “Something went wrong” due to formatDate being called but not defined (function was named formatTimestamp)
  • POST /api/v1/logs/identifiers/batch slow: the route was calling reservoir.getByIds (hitting ClickHouse/TimescaleDB/MongoDB) only to verify project access, then querying log_identifiers (PostgreSQL) separately. Since log_identifiers already stores log_id → project_id + identifier data, the storage engine call is now bypassed entirely — one PostgreSQL query replaces the N×storage-engine-roundtrips loop. Added bloom filter skip index on id in ClickHouse and a standalone id index in TimescaleDB (migration 032) for getByIds used by findCorrelatedLogs
  • GET /api/v1/logs/hostnames taking 8+ seconds: the 6h window cap was only applied when from was absent — explicit from params (e.g. 24h range from the search page) bypassed it and triggered a full-range metadata scan; cap now clamps any window to 6h max. Added limit: 500 to the distinct call. Per-engine optimizations: ClickHouse adds a hostname materialized column (computed at ingest, eliminates JSONExtractString at query time) and uses it directly in distinct queries; TimescaleDB adds a composite expression index (project_id, (metadata->>'hostname'), time) (migration 032); MongoDB adds a sparse compound index on metadata.hostname. All three engines also now extract the metadata field in a subquery (once per row vs 3×)
v0.8.3
Released
Feature

Comprehensive Audit Logging & OIDC Brand Icons

Major expansion of the audit trail system covering all critical platform actions for GDPR/SOC2 compliance, OIDC provider brand icons, and fixes for date formatting localization and data availability routing.

  • Audit logging for log access, auth events, identity management, provider config, settings, and sessions
  • OIDC login page shows brand icons for well-known providers (Google, Microsoft, GitHub, GitLab, Okta, Auth0, Keycloak, Authentik)
  • Backend auto-detects OIDC provider icon from issuer URL
  • Date/number formatting now respects user's browser/system locale
  • Fixed data-availability endpoint for ClickHouse and MongoDB storage engines

Added

  • Comprehensive Audit Logging: major expansion of the audit trail system to cover all critical platform actions for improved compliance (GDPR/SOC2) and security monitoring.
    • Log Access Auditing: every log search, trace view, context lookup, single log detail view, and live stream connection is now recorded with user identity, IP address, and query parameters.
    • External Authentication Auditing: successful logins via OIDC and LDAP providers are now tracked, including new user registration events.
    • Identity Management Auditing: linking and unlinking of external identities (Google, GitHub, LDAP, etc.) to user accounts is now recorded.
    • Authentication Provider Auditing: all administrative actions on auth providers (create, update, delete, reorder) are now fully audited with configuration change summaries.
    • System Settings Auditing: any changes to global platform settings (auth mode, signup status, default users) are now tracked with before/after metadata.
    • Session Auditing: viewing of active session lists and individual session event timelines is now recorded.
    • Audit metadata now includes detailed context like search queries (q), filter parameters, and updated keys for configuration changes.
  • OIDC login page now shows brand icons for well-known providers (Google, Microsoft/Azure, GitHub, GitLab, Okta, Auth0, Keycloak, Authentik); unknown providers fall back to the generic icon
  • Backend auto-detects the provider icon from the issuer URL when creating or updating an OIDC provider, with name/slug matching as fallback for self-hosted setups

Fixed

  • Date and number formatting localization: removed hardcoded locales (it-IT, en-US) from the frontend (SIEM, Search, Admin, etc.) to ensure the application automatically respects the user’s browser/system language settings.
  • GET /api/v1/projects/data-availability returned logs: [] (and incorrect traces/metrics) when STORAGE_ENGINE=clickhouse or mongodb; the endpoint now routes all three checks through the reservoir so they hit the correct backend
v0.8.2
Released
Fix

SigmaHQ Auto-Sync, Trace Links & Security Fixes

Daily auto-sync for SigmaHQ community rules, trace navigation from log detail panel, audit logs for alert rules, and security/robustness fixes for ingestion and admin endpoints.

  • SigmaHQ rules auto-sync daily at 2:30 AM
  • View Trace link in log detail panel when trace_id is present
  • Audit log entries for alert rule create/update/delete
  • Admin pagination capped at 200 to prevent oversized allocations
  • NDJSON lines exceeding 1MB rejected with HTTP 400
  • api_key_id removed from log metadata (information disclosure fix)

Added

  • SigmaHQ auto-sync: SigmaHQ community rules now auto-sync daily at 2:30 AM for organizations that have existing community rules enabled.
  • Trace link in log detail panel: The log detail panel now shows a “View Trace →” link that navigates directly to the trace timeline when a trace_id is present in the log.
  • Audit logs for alert rules: Create, update, and delete operations on alert rules now generate audit log entries.

Fixed

  • Admin pagination cap: The limit parameter on admin list endpoints is now capped at 200, preventing oversized result set allocation.
  • NDJSON ingestion size limit: Individual lines exceeding 1 MB in NDJSON payloads are now rejected with HTTP 400 instead of being silently processed.
  • Log metadata information disclosure: api_key_id is no longer stored in log metadata. It was previously injected in v0.8.1 for exception log display but exposed sensitive data; the display now resolves the key name at read time instead.
v0.8.1
Released
Breaking

Project Visibility in Errors & Storage Engine Fix

Project name display in error pages, API Key visibility in exception logs, and a fix for data-availability routing when using ClickHouse or MongoDB.

  • All existing API Keys have been invalidated — regenerate your keys
  • Project name shown in Exceptions list and error group detail pages
  • API Key name visible in recent exception logs
  • Data-availability endpoint now respects storage engine selection
  • Search page project filter fixed for empty logs array

Breaking Changes

  • All API Keys have been invalidated: All existing API Keys were deleted as part of this release. You must regenerate your API Keys from the dashboard and update your SDKs and ingestion clients accordingly.

Added

  • Project visibility in Exceptions: The /dashboard/errors list and the individual error group detail pages now explicitly display the name of the project that generated the error.
  • API Key visibility in Exception logs: The recent logs tab within an error group detail page now displays the specific API Key name used to ingest the log. Ingestion now injects the api_key_id into log metadata.

Fixed

  • Project data-availability ignoring storage engine: GET /api/v1/projects/data-availability was always querying the PostgreSQL logs table via Kysely, returning logs: [] when STORAGE_ENGINE was set to clickhouse or mongodb. The logs check now uses reservoir.distinct() which routes to the correct storage backend.
  • Search page showing no projects when logs is empty array: the project filter guard logsProjectIds ? was truthy for [], filtering out all projects. Changed to logsProjectIds?.length so an empty array correctly falls back to showing all projects.
v0.8.0
Released
Feature

MongoDB Adapter, Browser SDKs & Metrics Dashboards

MongoDB storage adapter for @logtide/reservoir, browser and frontend SDKs with source maps and Core Web Vitals, and OTLP metrics dashboards with cross-signal correlation.

  • MongoDB storage adapter for @logtide/reservoir
  • Browser/Frontend SDKs with session tracking & source maps
  • Core Web Vitals and network breadcrumbs
  • OTLP Metrics rollups & Golden Signals (P50/P95/P99)
  • Correlation across logs, traces, and metrics

Added

  • Browser & Frontend SDK Enhancements — Sentry-level browser observability across all frontend framework SDKs.
    • @logtide/browser: Dedicated browser SDK with session tracking, Web Vitals, and offline resilience.
    • Source Maps: @logtide/cli for source map uploads and backend un-minification service.
    • Frameworks: Deep integrations for Next.js, Nuxt, SvelteKit, and Angular.
  • Metrics Dashboard & Rollups — Redesigned metrics page with pre-aggregated rollups for TimescaleDB and ClickHouse.
  • MongoDB Storage Adapter — Full MongoDB backend for the @logtide/reservoir storage layer.
  • Golden Signals with Percentiles — P50/P95/P99 percentile aggregation across all storage engines.
  • Smart Project Selectors — Dropdowns now only show projects that have data in the relevant category.

Optimized

  • TimescaleDB Skip-Scan — Recursive CTEs for instant distinct queries on high-cardinality fields.
  • Intelligent Volume EstimationcountEstimate support for instant dashboard loads on high-volume projects.
  • Batch Ingestion — Ordered-false inserts and tuned connection pools for maximum throughput.
  • ClickHouse Projections — Faster query execution for common search patterns.

Fixed

  • Internal Logging Plugin — Fixed DSN passing to @logtide/fastify for self-monitoring.
  • Backend Self-Monitoring — Improved DSN construction and verbose startup logging.
  • Docker Compose — Fixed missing environment variables and worker health check race conditions.
  • Admin Dashboard — Fixed missing metrics series in platform activity chart.
v0.7.0
Released
Feature

OTLP Metrics, Service Graph & Audit Log

OpenTelemetry metrics ingestion, service dependency graph visualization, audit logging, and major UX restructuring.

  • OTLP Metrics with protobuf/JSON support
  • Service Dependency Graph with force-directed layout
  • Audit Log for compliance tracking
  • UX sidebar restructured into Observe/Detect/Manage
  • 46 TypeScript/Svelte warnings eliminated

Added

  • OTLP Metrics Ingestion — Full OpenTelemetry metrics support with protobuf/JSON, all 5 metric types, exemplar support, TimescaleDB hypertables, ClickHouse support, query API with 7 aggregation intervals and 6 functions, group-by label support, 118+ tests
  • Service Dependency Graph — Force-directed graph visualization with health color-coding, click-to-inspect panels, and PNG export
  • Audit Log — Tracks 4 event categories (login, config changes, user management, data modifications) with high-performance buffer and CSV export

Changed

  • Batch ingestion endpoint accepts flexible payload formats (standard, direct array, wrapped array) with auto-normalization
  • UX Restructuring — Sidebar grouped into Observe/Detect/Manage sections, Service Map merged into Traces, Sigma Rules moved to Security, Settings restructured, Command palette updated

Fixed

  • OTLP Traces typo using resource_logs instead of resource_spans
  • OTLP Authentication for /v1/otlp routes
  • JavaScript SDKs updated to v0.6.1 for OTLP compatibility
  • Frontend environment loading via $env/dynamic/public
  • SDK code examples across dashboard
  • Pagination total count with fast approximate estimates
  • Admin dashboard timeline gaps (ClickHouse bucket key format)
  • Chart locale now respects system language
  • Silent API errors now show toasts
  • Empty states for services/errors
  • Docker auto-database creation
v0.6.3
Released
Fix

Fix: Unauthenticated SMTP Support

SMTP no longer requires user/password credentials. Only the host is needed, and the from address uses the SMTP_FROM parameter.

  • SMTP works without USER/PASS credentials
  • From address uses SMTP_FROM parameter

Fixed SMTP configuration to support unauthenticated mail servers. Only SMTP_HOST is now required — SMTP_USER and SMTP_PASS are optional. The sender address is configured via SMTP_FROM.

v0.6.2
Released
Breaking

Write-Only API Keys & Domain Allowlists

New write-only API key type safe for browsers and mobile, plus domain/IP allowlists with wildcard subdomain support for origin validation.

  • Write-only API keys safe for client-side use
  • Domain/IP allowlist with wildcard subdomains
  • Dogfooding SDK migration to official plugins
  • fast-xml-parser security fix

Added

  • Write-Only API Keys — New type field (write/full), safe for browsers and mobile, defaults to write
  • Domain/IP Allowlist — Up to 50 allowed origins per key with wildcard subdomain support and Origin header validation

Security

  • fast-xml-parser bumped to >=5.3.6 for entity expansion DoS fix
  • Read endpoints reject write-only API keys with 403
  • Origin allowlist validation with wildcard subdomain parsing

Breaking Changes

  • API key default type changed to write — existing keys migrated automatically, server-side queries need full type
  • Database migration 024_api_key_scopes.sql required
v0.6.1
Released
Feature

ClickHouse Storage Engine

ClickHouse as a full alternative to TimescaleDB via the @logtide/reservoir abstraction layer, with factory pattern engine selection and full query migration.

  • ClickHouse via @logtide/reservoir abstraction
  • Factory pattern engine selection
  • 26 integration tests against both engines
  • Full log query migration to Reservoir

Added

  • ClickHouse Storage Engine — Full support as TimescaleDB alternative via @logtide/reservoir abstraction layer with PREWHERE, async_insert, and ngrambf_v1 indexes
  • Full Log Query Migration — All query operations (alerts, dashboard, admin, retention, ingestion, correlation) migrated to the Reservoir abstraction

Performance

  • Removed COUNT(*) full scans in admin queries, switched to continuous aggregates
  • ClickHouse DateTime64(3) millisecond precision with hasToken() fallback
  • TimescaleDB removed redundant indexes, added UNNEST batch inserts
v0.6.0
Released
Feature

Security Packs, PII Masking & Keyboard Shortcuts

Host security detection packs with MITRE ATT&CK mapping, PII masking at ingestion, rate-of-change alerts, keyboard shortcuts, and admin dashboard revision.

  • 3 security packs with 15 MITRE-mapped rules
  • PII masking with mask/redact/hash strategies
  • Rate-of-change alerts with baseline detection
  • Command palette and keyboard shortcuts
  • Revised admin dashboard with health monitoring

Added

  • Host Security Detection Packs — 3 packs (Antivirus & Malware, Rootkit Detection, File Integrity Monitoring) with 15 rules total, MITRE ATT&CK mapped
  • PII Masking at Ingestion — Content patterns (email, credit card, phone, SSN, IPv4, API keys), field name masking, custom rules, three strategies (mask, redact, hash with per-org salt), Settings UI with live test panel
  • Keyboard Shortcuts — Command Palette (Ctrl/Cmd+K), Help Modal (?), sequence navigation (G+D/S/A/P/T/E/R/X), search shortcuts, first-time toast
  • Admin Dashboard Revision — Health status cards, 24h activity timeline, 8 stat cards, System Health page with database/pool/Redis diagnostics
  • Rate-of-Change Alerts — 4 baseline methods (same_time_yesterday, same_day_last_week, rolling_7d_avg, percentile_p95), anti-spam, frontend baseline picker
  • Timeline Event Markers — Alerts and security detections shown on log timeline chart
  • Version Update Notifications — GitHub release checking with 6-hour cache and release channel setting

Fixed

  • Sigma API missing tags and MITRE fields
  • Badge components stretching in containers
  • Client errors (4xx) returning 500 instead of correct status
  • Log Context metadata expanding dialog infinitely
  • Email logo not rendering in Outlook/Gmail
  • Continuous Aggregates showing “Refresh: unknown”
  • Charts not resizing on sidebar toggle (switched to ResizeObserver)
v0.5.4
Released
Fix

Detection Pack Routing & Exception Fixes

Detection pack category routing directs results to correct UI sections. Multiple fixes for exception handling and onboarding.

  • Detection results routed to correct UI sections
  • Exception detection for metadata.error structure
  • Onboarding race condition fixed

Added

  • Detection Pack Category Routing directing results to correct UI sections

Fixed

  • Exception Detection for metadata.error structure
  • Exception Details Dialog showing [object Object]
  • Onboarding race condition with concurrent requests
  • Internal org missing members assignment
  • Unwanted email/webhook notifications dispatch
  • Email logo not rendering with hosted SVG URLs
  • Ingestion JSON parse errors returning proper 400 status
v0.5.5
Released
Fix

Detection Filter Fix & Admin Performance

Fixed detection category filter validation and optimized admin dashboard from 31s to ~1s with continuous aggregates.

  • Detection category filter validation fix
  • Admin stats optimized from 31s to ~1s
  • Error Group Logs timeout fixed

Fixed

  • Detection Category Filter Validation Error with schema correction
  • Admin Dashboard timeout fixed with continuous aggregates

Performance

  • Admin stats endpoints optimized from 31s to ~1s
  • Error Group Logs timeout fixed with time bounds
v0.5.3
Released
Improvement

Hostname Filter & Hypertable Optimization

Hostname filter for syslog sources, log retention fixes for compressed chunks, and major performance improvements with TimescaleDB hypertables.

  • Hostname filter for syslog sources
  • log_identifiers as TimescaleDB hypertable
  • Continuous aggregates for spans and detections
  • Hybrid query architecture for historical data

Added

  • Hostname Filter for Syslog Sources with automatic extraction and filtering

Fixed

  • Log Retention on Compressed Chunks with proper decompression handling
  • Fluent Bit Kubernetes metadata extraction improvements

Performance

  • log_identifiers table optimized as TimescaleDB hypertable
  • Continuous aggregates for spans and detection events
  • Hybrid query architecture using aggregates for historical data
  • Admin monitoring endpoints for compression and aggregate stats
v0.5.2
Released
Security

Security Fixes & Batch Splitting

Fastify security vulnerabilities patched, automatic batch request splitting, and Unicode escape sanitization.

  • Fastify upgraded to 5.7.3+ for security fixes
  • Automatic batch request splitting
  • Unicode escape sequence sanitization

Security

  • Fastify security vulnerabilities fixed in upgrade to 5.7.3+

Fixed

  • API batch request limit with automatic batch splitting
  • Unicode escape sequences sanitization
  • POST requests without body compatibility
  • Log retention cleanup for compressed chunks
  • Fluent Bit Kubernetes metadata extraction
v0.5.1
Released
Feature

Notification Channels

Configurable email and webhook notification destinations with channel testing before saving and UI space optimization.

  • Email and webhook notification channels
  • Test channel before saving
  • UI space optimization

Added

  • Notification Channels — Configurable email and webhook destinations with channel testing before saving

Changed

  • UI space optimization reducing margins and padding across the dashboard

Fixed

  • Invitation email resend functionality
  • Unwanted notifications when channels unconfigured
v0.5.0
Released
Feature

Terminal View, Detection Packs & Event Correlation

Terminal log view with ANSI color coding, pre-configured detection packs, event correlation by identifier, alert preview testing, and optional Redis dependency.

  • Terminal Log View with ANSI color coding
  • Pre-configured Sigma detection packs
  • Event correlation by request/trace/user ID
  • Alert preview with 'Would Have Fired' simulation
  • Redis dependency now optional

Added

  • Terminal Log View — ANSI-style color coding for a familiar terminal experience
  • Detection Packs — Pre-configured Sigma rule bundles for common scenarios (startup, auth, database health)
  • Event Correlation — Click any request ID, trace ID, or user ID to see all related logs
  • Alert Preview — “Would Have Fired” simulation to test rules before enabling
  • Optional Redis — PostgreSQL-based alternatives with adapter pattern queue system

Fixed

  • Log Context modal reopening after close
  • Exception details from metadata display
  • WebSocket memory leak in live tail handler
  • SQL injection prevention in notification publisher
v0.4.2
Released
Fix

Clipboard Utility & Config Validation

Centralized clipboard copy function, config validation test coverage, and documentation corrections.

  • Centralized clipboard utility
  • Config validation test coverage

Added

  • Clipboard utility with centralized copy function
  • Config validation test coverage

Fixed

  • Documentation corrections for API configuration
  • Docker Compose configuration information
v0.4.1
Released
Improvement

Multi-Language Exception Parsers

Stack trace parsing support for multiple programming languages and dependency updates including @sveltejs/kit.

  • Multi-language stack trace parsing
  • SvelteKit and dependency updates

Added

  • Exception parsers for multi-language stack trace parsing

Changed

  • Dependencies updated including @sveltejs/kit

Fixed

  • OTLP endpoint URLs in documentation
v0.4.0
Released
Breaking

LogWard to LogTide Rebrand & Search

Project rebranding from LogWard to LogTide, substring search with trigram indexes, clickable dashboard elements, exception visualization, and customizable retention.

  • Project rebranded from LogWard to LogTide
  • Substring search with PostgreSQL trigram index
  • Clickable dashboard elements
  • Enhanced exception & stack trace visualization
  • Customizable log retention policy

Added

  • Substring Search — Full-text search with PostgreSQL trigram index
  • Clickable Dashboard Elements — Interactive navigation from charts and widgets
  • Enhanced Exception Visualization — Improved stack trace display
  • Customizable Log Retention — Configurable retention policies per project
  • Full-Page Export — Export all matching logs across pages
  • Custom Time Range Picker — Improved date/time selection UI

Breaking Changes

  • Environment variables renamed (LOGWARDLOGTIDE)
  • Fluent Bit configuration variables renamed
  • Database defaults changed
  • Docker container and service names changed
  • SMTP default sender changed

Fixed

  • Mobile navigation menu hamburger functionality
  • Services dropdown showing all services
  • Journald log format detection
  • Syslog level mapping improvements
  • OTLP protobuf parsing with proper binary support
2025
v0.3.2
Released
Fix

SvelteKit 2 Compatibility Fixes

Fixed SvelteKit 2 compatibility with new store patterns, traces page navigation 404s, and registration error handling.

  • SvelteKit 2 store pattern compatibility
  • Traces page 404 navigation fix

Fixed

  • SvelteKit 2 compatibility with new store patterns
  • Traces page navigation fixing 404 links
  • Registration error network handling
v0.3.3
Released
Feature

LDAP, OIDC & Auth-Free Mode

Enterprise authentication with LDAP and OpenID Connect, auth-free mode for home labs, initial admin via environment variables, and ARM64 Docker builds.

  • LDAP authentication for enterprise directories
  • OpenID Connect (OIDC) SSO
  • Auth-free mode for home labs
  • ARM64 / Raspberry Pi Docker builds
  • Disable sign-ups capability

Added

  • LDAP Authentication — Enterprise directory integration
  • OpenID Connect (OIDC) — SSO with any OIDC-compliant provider
  • Initial Admin via Environment Variables — Bootstrap admin user at first startup
  • Disable Sign-ups — Control user registration for private instances
  • Auth-free Mode — No authentication required, ideal for home labs and local development
  • ARM64 / Raspberry Pi Support — Docker images for ARM architecture

Changed

  • Fluent Bit default version pinned to 4.2.2
v0.3.1
Released
Fix

Security Policy Update

Updated security policy with current supported versions for responsible disclosure.

  • Supported versions updated for security policy

Updated security policy with current supported versions.

v0.3.0
Released
Feature

SIEM Dashboard, C# SDK & GeoIP Enrichment

Real-time SIEM dashboard with security widgets, C# / .NET SDK, IP reputation and GeoIP enrichment, and organization invitations.

  • Real-time SIEM dashboard with security widgets
  • C# / .NET SDK
  • IP reputation & GeoIP enrichment
  • Organization invitations
  • Horizontal scaling docs with Traefik

Added

  • SIEM Dashboard — Real-time security dashboard with dedicated widgets
  • C# / .NET SDK — Full .NET application support
  • IP Reputation & GeoIP Enrichment — Automatic IP context enrichment for security analysis
  • Organization Invitations — Invite users to join your organization
  • Horizontal Scaling Documentation — Traefik-based setup guide

Fixed

  • PDF export functionality in incident detail
v0.2.4
Released
Improvement

Syslog Integration & Go SDK Docs

Syslog integration documentation with device-specific guides, Go SDK documentation, and documentation restructure with new Integrations section.

  • Syslog integration with device guides
  • Go SDK documentation
  • Documentation restructure
  • Runtime PUBLIC_API_URL configuration

Added

  • Syslog integration documentation with device-specific guides
  • Go SDK documentation at /docs/sdks/go
  • Documentation restructure with new Integrations section

Changed

  • Docker Compose improved container orchestration
  • Onboarding flow skip behavior refinement
  • Runtime configuration for PUBLIC_API_URL

Fixed

  • Sign Up Free link pointing to correct route
  • Skip tutorial redirect loop
  • API URL in code examples
v0.2.3
Released
Improvement

Docker Image Publishing & Self-Hosting Docs

Automated Docker image publishing via GitHub Actions CI/CD and comprehensive self-hosting deployment documentation.

  • Docker images via GitHub Actions CI/CD
  • Self-hosting deployment documentation
  • Pre-built images in docker-compose.yml

Added

  • Docker image publishing with GitHub Actions CI/CD pipeline
  • Self-hosting documentation with deployment guides

Changed

  • docker-compose.yml now uses pre-built images by default
v0.2.2
Released
Feature

Onboarding Tutorial & Empty States

Multi-step onboarding wizard with progress tracking, empty state components for guidance, and expanded testing infrastructure.

  • Multi-step onboarding wizard
  • User onboarding checklist with progress
  • Empty state guidance components
  • Expanded testing infrastructure

Added

  • Onboarding Tutorial — Multi-step wizard guiding new users through setup
  • Empty State Components — Helpful guidance when dashboards have no data yet
  • User Onboarding Checklist — Progress tracking for initial setup steps
  • UI enhancements with help components

Fixed

  • Organization context handling improvements
  • Error states and loading indicators
v0.2.1
Released
Improvement

Redis Caching & 50x Performance Boost

Type-safe Redis caching layer with session validation 30x faster, API key verification 20x faster, query results 10x faster, and aggregations 50x faster.

  • Session validation 30x faster
  • API key verification 20x faster
  • Query results 10x faster
  • Aggregations 50x faster

Added

  • Redis Caching Layer — Type-safe cache keys with automatic invalidation
  • Landing page public index

Changed

  • Database optimization with composite indexes

Performance

  • Session validation 30x faster with caching
  • API key verification 20x faster
  • Query results 10x faster
  • Aggregations 50x faster

Fixed

  • Admin panel double sidebar issue
  • Admin routes navigation path corrections
v0.2.0
Released
Feature

OpenTelemetry & Distributed Tracing

Full OpenTelemetry support with OTLP endpoints, distributed tracing with complete CRUD operations, and 563+ tests.

  • OpenTelemetry OTLP endpoints
  • Distributed tracing with full CRUD
  • 563+ tests
  • Keyboard navigation for span selection

Added

  • OpenTelemetry Support — OTLP ingestion endpoints for traces and logs
  • Distributed Tracing — Full CRUD operations with waterfall visualization
  • Testing Infrastructure — 563+ tests covering all major features

Changed

  • OTLP ingestion performance optimization
  • Span selection UX with keyboard navigation

Fixed

  • Frontend UX issues in OTLP data display
  • trace_id handling flexibility for various formats
v0.1.0
Released
Feature

Initial Release

First public release of LogTide with multi-organization architecture, batch log ingestion, real-time streaming, TimescaleDB storage, Sigma detection engine, and official SDKs.

  • Multi-organization architecture
  • High-performance batch log ingestion
  • Real-time log streaming via SSE
  • Sigma detection engine
  • Node.js, Python, PHP & Kotlin SDKs
  • Docker Compose deployment

Added

  • Multi-organization architecture — Isolated workspaces for teams and projects
  • High-performance batch log ingestion — Optimized for high throughput
  • Real-time log streaming — Server-Sent Events for live tail
  • Advanced search and filtering — Query logs with complex filters
  • TimescaleDB storage — Automatic compression and retention policies
  • Dashboard with statistics — Overview of log volume, errors, and trends
  • Alert system — Rules with email and webhook notifications
  • Sigma detection engine — Industry-standard threat detection rules
  • Official SDKs — Node.js, Python, PHP, and Kotlin
  • Docker Compose deployment — Single-command setup

Have a feature request?

Open a discussion on GitHub or vote on existing proposals to help shape the roadmap.

Open a Discussion