Commit Graph

47 Commits

Author SHA1 Message Date
Oliver Kieselbach e63a0bc2bd perf(metrics): fix Platform Usage client timeout — parallel projected scans, 15min cache, single-flight, progress UX
Fresh cross-tenant usage computes took 20-43s server-side but the web app's
default 30s fetch timeout aborted them client-side (HTTP 499), and every
retry stacked another concurrent full compute.

Backend:
- UsageMetricsService: cache 5→15min, single-flight per days-window (retries
  join the in-flight compute), the four source scans run concurrently via
  Task.WhenAll, statics converted to instance fields (singleton, testable)
- New column-projected queries for the usage compute only:
  GetUsageWindowSessionsAsync ($select 13 consumed columns, drops
  FailureSnapshotJson & co.) and GetAppInstallRefsAsync ($select
  SessionId+AppName, lean SessionAppRef DTO); GetSessionsByDateRangeAsync
  is untouched for its other consumers
- Projection equivalence pinned by UsageMetricsProjectionEquivalenceTests
  (incl. the WhiteGlove Part-2 duration branch via IsPreProvisioned/
  ResumedAt); single-flight/cache/failure-eviction pinned by
  UsageMetricsServiceSingleFlightTests

Web (SectionPlatformUsage):
- 180s AbortSignal for this call (backend keeps computing and caches)
- Calculating card with elapsed time and a progress bar sized from the last
  fresh-compute duration (localStorage, cache hits excluded, capped at 95%)
- Friendly timeout error explaining the retry will hit the server cache

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 12:10:56 +02:00
Oliver Kieselbach d8e8cd15fd feat(entitlements): Community/Enterprise editions with self-service trial
Fail-closed entitlement layer (FeatureEntitlementCatalog + TenantEntitlementService): edition resolves at read time (PlanTier == 'enterprise' OR active trial; legacy free/pro => Community, no migration).

- Plan/trial endpoints: PATCH config/{tid}/plan (GA: tier + grant/extend/end trial, audited, cache-safe) and POST config/{tid}/trial (tenant-admin self-service 30d, once per tenant, 409 after). Generic PUT preserves plan/trial fields for all callers. Fixes SetPlanTier writing past the config cache without audit/UpdatedBy.
- Rate limits: Enterprise floor 150/min for BOTH user (portal/JWT) and device (agent/cert) paths - floor raises the global default, an explicit per-tenant override still wins; MSP users follow their home tenant.
- Retention cap: Community 90d / Enterprise 365d, clamped in the retention fanout (warn log) + non-GA write validation 7..cap (only on changed values; 0=infinite stays GA-only).
- Delegated admin (MSP): Enterprise gate on the delegated admin's HOME tenant (JWT tid, fail-closed on unknown) - managed target tenants may be any edition. Grant-time target check removed; inert grants are suppressed at resolve time (single choke point in GetScopeAsync, applied after the UPN-keyed cache).
- MCP quota: McpQuotaService + McpQuotaEnforcementMiddleware (X-Client-Source: mcp only, GA exempt) enforce daily/monthly budgets - per-user plan override > tenant edition plan; limits from SectionUsagePlans with catalog fallbacks (community 100/3000, enterprise 1000/20000); 429 with X-MCP-Quota-* headers + Retry-After; fail-open on counter reads, fail-closed on plan resolution. /api/metrics/mcp-usage/me reports effective plan + counters.
- Trial visibility: TrialExpirySweepFunction (daily 03:30 UTC, informational) emits TenantTrialExpired (Warning, 24h look-back) + TenantTrialExpiring (Info, <=3d heads-up); dual-registered in web OPS_EVENT_TYPES.
- Web: EditionBadge + one-time trial CTA in settings header, Plan & Trial card in the GA tenant edit modal (own PATCH save), retention cap hints from entitlements, pure lib/edition.ts (vitest), feature-flags surface edition/trial/entitlements; MCP TENANT_SAFE_FIELDS + trial fields.

Verified: solution build clean; backend 2653/2653 tests; web tsc + 516/516 vitest; MCP server tsc + tests green.
2026-07-07 13:06:04 +02:00
Oliver Kieselbach bcd307d8a4 perf(backend): project index scans + bound AppInstall reads to window
Two classes of read-efficiency fixes on hot/aggregation paths. No response
shape or value changes — DTOs untouched, all 2541 backend tests pass.

P2 — select projections on full-mirror SessionsIndex scans (bandwidth only):
- GetMetricsSummaryAsync: cross-partition status tally now projects
  [PartitionKey, Status] instead of the ~40-column mirror row (incl. the
  large FailureSnapshotJson) -> ~10-20x less transfer.
- QuickSearchSessionsAsync: typeahead scan projects only the matched fields
  (+ RowKey for the SessionId fallback) instead of the full row, for up to
  QuickSearchMaxScannedRows rows per request.

P3 — push the existing sinceUtc window floor server-side at 8 AppInstall
call sites across 5 files (previously each dematerialized the whole table /
partition and filtered to the window in memory):
- UsageMetricsService (global + tenant): now.AddDays(-days)
- MaintenanceService.Aggregation (global + tenant, per aggregated day): targetDate
- SlaBreachEvaluationService (current ISO week): now.AddDays(-8) margin
- SlaMetricsService: startDate (matches the in-memory lower bound exactly)
- Get(Global)GeographicLocationSessionsFunction: cutoff

Each floor equals the session-window floor the apps are joined against
(app.StartedAt >= session.StartedAt >= floor), so results are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:16:03 +02:00
Oliver Kieselbach d0486de21e perf(backend): push app-install-summary time window server-side + parallelize session join
The app dashboard and metrics endpoints loaded entire AppInstallSummaries
partitions (tenant scope) or the full table (global scope) and filtered
StartedAt >= cutoff in memory, even for days=30. The device-model join then
issued one serial GetSessionAsync point-read per distinct session.

- Add optional DateTime? sinceUtc to GetAppInstallSummariesByTenantAsync /
  GetAllAppInstallSummariesAsync: when set, a server-side StartedAt ge filter
  scopes the scan so only in-window rows are deserialized/transferred. Default
  null preserves the legacy full scan for callers that need all history.
- AppsAnalyticsHelper.LoadSummariesAsync derives sinceUtc from days; all six
  /api/apps/* functions pass it. The four metrics/app + metrics/geographic
  functions pass their existing cutoff. The in-memory Where stays as the exact
  sub-second trim (the OData filter is second-granular). MCP get_app_install_metrics
  benefits automatically (days already flows through; response shape unchanged).
- Replace the serial session point-read loop with a bounded-concurrency
  (SemaphoreSlim=10) LoadSessionLookupAsync, shared by the analytics and
  sessions builders.

AppInstallSummaries is already bounded by the session-retention cascade
(DeletionManifestBuilder) + tenant offboarding, so no separate table retention
is added. Full Backend suite: 2406 passed / 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:16:04 +02:00
Oliver Kieselbach 2d3853c38f feat(rbac): add read-only GlobalReader platform role (backend + MCP + web)
GlobalReader = cross-tenant READ visibility like a Global Admin, but no mutating
operations and no platform settings. Provisioned exactly like a GA: a GlobalAdmins
table row with Role=GlobalReader (empty/legacy Role = GlobalAdmin, back-compat).
Semantics are ADDITIVE — a user who is also their own tenant's Admin keeps edit
rights on that tenant; a pure GlobalReader is read-only everywhere.

Backend:
- GlobalAdmins.Role column + GlobalAdminService.GetGlobalRoleAsync; IsGlobalAdminAsync
  (incl. TableAdminRepository) delegates so a GlobalReader row never reads back as admin
- RequestContext.IsGlobalReader + HasGlobalScope
- Split GlobalAdminOnly into GlobalReadOrAdmin (cross-tenant reads) vs GlobalAdminOnly
  (writes/settings) + TenantAdminOrGlobalReader for config-read
- PolicyEnforcementMiddleware: extracted testable DecideAsync seam; cross-tenant gate keys
  off HasGlobalScope; additive own-tenant role carried so IsTenantAdmin stays correct
- Config secret redaction for readers (RedactedCopyForReader) + save-time placeholder
  restore (RestoreRedactedSecretsFrom) so a redacted view can't blank real secrets
- raw table/log tools stay GlobalAdminOnly; SignalR global-admins read group admits HasGlobalScope
- /auth/me emits isGlobalReader (+ preview-gate bypass, no auto-admin); /auth/mcp emits globalRole

MCP: hasGlobalScope (GA or Reader) drives routing + tool catalog; raw secret-bearing tools
(query_table/list_tables/query_backend_logs) gated strict-GA only.

Web: AuthContext isGlobalReader + hasGlobalScope; reader reaches /dashboard + cross-tenant
views; platform Settings/Ops/Backups/Software GA-only (nav-hidden + requireGlobalAdmin route
layouts); mutating controls on mixed data pages disabled via useCanMutatePlatform; rules pages
read-only on foreign tenants; additive own-tenant edit preserved.

Tests: backend 2369, MCP 252, web 469 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:07:10 +02:00
Oliver Kieselbach dbb4b3f5a7 feat(metrics): server-side Fleet Health aggregation endpoints
Fleet Health previously drained up to 200k raw sessions into the browser
(MAX_EAGER_PAGES=200 x 1000) over as many HTTP round-trips, then computed
7 aggregates in useMemo on the main thread. Move that aggregation to the
backend, mirroring the dashboard-stats server-aggregation path.

- MetricsMath.BuildFleetHealthPayload: single pass over the windowed
  session list producing stats, daily timeline, top failure reasons, and
  model health/slowest/top-failing breakdowns. Semantics ported verbatim
  from the client (success rate over ALL sessions; avg duration over
  non-in-progress sessions incl. failures), so displayed numbers are
  unchanged. Typed FleetHealthMetrics DTO in Shared for a typed contract.
- GET /api/metrics/fleet-health (MemberRead) and
  GET /api/global/metrics/fleet-health (GlobalAdminOnly, optional
  ?tenantId=) reuse the existing ISessionRepository window readers.
- Registered both routes in EndpointAccessPolicyCatalog (fail-closed).
- 9 xUnit tests covering the aggregation semantics.

Frontend swap to these endpoints lands in a follow-up commit. App-metrics
(slowest/failing apps) is already backend-aggregated and untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 14:32:44 +02:00
Oliver Kieselbach fed162946e feat(metrics+mcp): app-install & software-inventory MCP tools + DO rollup
Backend:
- Extract MetricsMath.BuildAppMetricsPayload as the single source for the
  app-metrics aggregation (was duplicated verbatim across the tenant and
  global functions) and add a Delivery Optimization rollup: per-app peer/MCC
  offload bytes + overall deliveryOptimization summary (peers and MCC counted
  separately, peerOffloadPercent credits both as not-from-CDN).
- New tenant-scoped GetTenantSoftwareInventoryFunction (GET metrics/software-
  inventory, MemberRead, JWT tenant) + fail-closed policy-catalog entry.

MCP server:
- get_app_install_metrics: role-aware routing (global/metrics/app vs
  metrics/app), surfaces the DO rollup.
- get_software_inventory: one role-aware tool; non-GA sees only its own tenant
  (no tenantId/scope in schema), GA additionally gets tenantId + scope=unmatched.
  New exported paginateInventory client-side pager.

Tests: MetricsMathAppPayloadTests (DO rollup/offload/sample-floor) + vitest
paginateInventory. Backend 2202/2202, MCP 220 passed, tsc clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:51:36 +02:00
Oliver Kieselbach 908fb8e7ac fix(metrics): clamp duration aggregates, reconcile status buckets, guard slowest-apps sample size
Three data-hygiene fixes for the MCP metric tools, all driven by
incomplete/abandoned sessions distorting aggregates:

- get_usage_metrics: clamp each session duration to the shared 7-day
  ceiling before avg/median/p95/p99, so stuck non-terminal sessions
  (unclamped now-StartedAt wall-clock) no longer push p99 into weeks.
  Surface SampleCount + ClampedSessionCount so the skew stays visible.
- get_metrics: tally Pending/Stalled into their own buckets and route
  any other status into `other`, so the per-tenant buckets reconcile to
  total by construction (closes the silent 214/134 gap). Extracted the
  fold into SessionStatusBuckets.
- slowestApps: require >=3 successful installs via the shared
  MetricsMath.SelectSlowestApps helper, so a single N=1 (often
  unfinished, legacy pre-clamp) install cannot dominate the ranking;
  also de-dupes the copy-pasted block across the tenant + global
  app-metrics functions.

Adds xUnit regression cover for all three.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:39:49 +02:00
Oliver Kieselbach 42678df6e6 fix(mcp-metrics): honor session cap + repair geo drilldown across 3 tools
get_platform_metrics: expose maxSessions (->&limit=), echo sessionLimit +
truncated. Backend already honored days+limit; the tool only sent days, so
results were silently capped at the newest 100 sessions.

get_geographic_sessions: backend (tenant+global) now matches structured
country/region/city against actual Geo* fields via FilterSessionsByFields
(case-insensitive, optional narrowing); 400 relaxed to require locationKey OR
country. MCP forwards structured filters and infers groupBy on the raw
locationKey path so country/region keys resolve (previously matched nothing).
locationKey path retained for the web UI.

get_geographic_metrics: blank Region/City for coarser groupings so a country
row is not mislabeled with an arbitrary sample city; keep Loc for map pins.

Tests: +GeographicDrilldownFilterTests (backend), +geo-platform-helpers (MCP).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:22:22 +02:00
Oliver Kieselbach 0c24719e16 feat(do-telemetry): add MCC + LinkLocal + symmetric breakdown across all layers
Customer reported "From Peers 100% / Peer breakdown LAN 0 | Group 0 | Internet 0"
mid-download. Root cause: OS collector emitted LAN/Group/Internet/LinkLocal
breakdown only on the final do_telemetry event, not on download_progress events
during the download — so UI rendered 0/0/0 until completion. Empirical check of
917 do_telemetry events / 146 sessions / 13 tenants over 30 days confirmed IME
[DO TEL] log path is dead code (current IME version no longer logs it); OS
cmdlet is the sole live source.

Changes:
- AppPackageState (V2): new fields DoBytesFromLinkLocalPeers,
  DoBytesFromCacheServer, DoCacheHost; UpdateDoTelemetry signature extended
  with optional defaults so callers without the data pass 0/null.
- DeliveryOptimizationCollector: read BytesFromLinkLocalPeers + CacheHost
  from cmdlet output; centralised event payload via BuildDoEventData() so
  download_progress and do_telemetry are field-symmetric.
- ImeLogTracker.HandleDoTelemetry: parses new fields null-safe (older IME
  JSON without them defaults to 0/null, no breakage).
- Persistence: PackageStateData DTO + ToPackageStateData / FromPackageStateData
  mappers carry the new fields across agent restart.
- ImeLogTrackerAdapter.EmitDoTelemetry: emits new fields on do_telemetry,
  including doCacheHost when MCC was used.
- Backend ingest (V1 + V2 paths) + AppInstallSummary model +
  TableStorageService.Metrics Store/Map/preserve-from-existing extended for
  the new columns.
- DoAggregator + GeographicApiModels + GetGeographicMetricsFunction surface
  MCC + LinkLocal at location and per-session level.
- UI DownloadProgress.tsx: new "From Connected Cache" line with cache% and
  hover host; LAN merges LinkLocal in breakdown ("local network"); 3-color
  progress bar (Peers green / MCC purple / HTTP blue) computed by subtracting
  CacheServer from HTTP to avoid double-counting (MCC serves over HTTP).
- UI sessions page: hover title now includes MCC bytes and LAN+LinkLocal sum.

Robustness: every new field defaults to 0 / null / "" on machines or paths
that don't supply them; no existing session display regresses.

Tests: backend 1058/1058, agent V2 1007/1007, web vitest 259/259, tsc clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:37:48 +02:00
Oliver Kieselbach 05ce8cac9a fix(mcp,backend): close two gaps from MCP routing PR — get_ops_events tenantId + global metrics summary tenantId filter
Re-test post-deploy of #60 surfaced two minor follow-ups:

1. get_ops_events MCP tool: backend already accepts tenantId filter
   (since C2), but the MCP tool schema didn't expose tenantId so Zod
   silently dropped any caller-passed value. Adds tenantId to the input
   schema and forwards it in the query. 2 LOC.

2. /api/global/metrics/summary: the global handler was hardcoded to
   pass null (all tenants) and ignored ?tenantId=X. Adds the same
   optional filter pattern used elsewhere — null when absent, scoped
   when present. The tenant-scoped /api/metrics/summary route is
   unchanged (JWT-tid still authoritative).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:09:43 +02:00
Oliver Kieselbach 3116a0ecc9 feat(backend,web): geographic-sessions default-lean (?full=1 opt-out)
The full LocationSessionRow shape is ~40 fields per session — for
locations with dozens of sessions the response easily blew past 100KB
and tripped MCP token caps. Most fields aren't needed for the typical
"which sessions enrolled from here" triage flow.

Default is now a 17-field lean projection (sessionId, device basics,
status/duration, geo, app/DO summary). UI keeps the full shape via
?full=1 — single-line addition in lib/api.ts.

Also adds an optional tenantId filter on /api/global/metrics/geographic/
sessions so a GA can scope a single tenant's sessions for a location
without leaving the global endpoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:31:39 +02:00
Oliver Kieselbach 939bc2ebc7 fixed platform metrics, ops and session reports fetching 2026-05-07 09:14:37 +02:00
Oliver Kieselbach 5ef6c8b1d2 fix(mcp): MCP server security & capability audit (Phases A-E)
Critical: GET /api/metrics/mcp-usage/user/{userId} (TenantAdminOrGA, no
TenantScoping) handed the oid to the repo without checking that returned
records belong to the caller's tenant. A tenant admin from tenant A could
read MCP usage records of any oid — including oids in tenant B.

McpUsageMetricsFunction.GetUserUsage now blocks 403 CrossTenantAccessDenied
when records are tenant-foreign and caller is not a Global Admin. The pure
decision logic lives in UsageCrossTenantGuard for unit-testability (9 tests
covering own/foreign/mixed/GA/empty/null/case-insensitive/empty-tid paths).

Also:
- MCP get_api_usage tool was calling /api/metrics/mcp-usage/{userId}
  (without /user/), which is unregistered and returned 404 — corrected.
- list_blocked_devices description honestly states the endpoint is
  GA-only on both variants (catalog policy, no change to the gate).
- days clamp [1, 365] added to /metrics/{app, geographic, geographic/sessions}
  for parity with /metrics/summary, /metrics/usage, /metrics/platform.
- get_geographic_metrics, get_geographic_sessions zod schemas now constrain
  days to int().min(1).max(365) — same pattern as the other tools.
- search/sessions, search/sessions-by-event, search/sessions-by-cve switched
  limit handling from Math.Min(lim, 100) to Math.Clamp(lim, 1, 100); the old
  form let a negative ?limit=-5 reach the repo.

Audit static analysis confirmed all other tenant-scoped endpoints route
tenantId through TenantHelper.GetTenantId(req) (JWT-only, ignores query),
so ?tenantId=<other> is silently dropped. Live-verified with an Operator
token: 14 cross-tenant query probes returned only the caller's tenant,
13 GlobalAdminOnly routes returned 403.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 12:12:54 +02:00
Oliver Kieselbach eee65ba000 fix(metrics): honor days time-window in MCP get_metrics, get_usage_metrics, get_platform_metrics
The three metrics MCP tools previously ignored the time-window: get_metrics never
read the days query param (returned all-time totals), get_usage_metrics didn't
expose days at all and the service was hardcoded to 90, get_platform_metrics
had a fixed 500-most-recent-sessions cap. A "last 7 days" question therefore
returned cross-tenant all-time aggregates (~1300) instead of the actual 7-day
count (~500).

End-to-end fix:
- Plumbing days through MetricsSummaryFunction → IMetricsRepository →
  TableStorageService.GetMetricsSummaryAsync, with a server-side RowKey cutoff
  on SessionsIndex (reuses the inverted-tick D19 prefix pattern; extracted as
  ComputeCutoffRowKeyPrefix and the two pre-existing call sites consolidated).
- UsageMetricsService and PlatformMetricsService now accept int days, with
  per-window in-memory caches and a WindowDays field echoed on the response.
- MCP zod schemas accept any integer 1-365 (replacing the [7,30,90] whitelist),
  so callers can now ask for 5 or 12 days and get the right answer.
- Function-layer defaults stay at 90 for /usage and /platform routes (no
  dashboard regression) and 30 for /summary (Agent API, MCP-only path).

Tests: 22 new xUnit cases across MetricsCutoffRowKeyTests,
UsageMetricsServiceWindowTests, PlatformMetricsServiceWindowTests covering
boundary, clamping, and end-to-end window semantics. Backend 808/808 green,
web vitest 208/208 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 08:45:55 +02:00
Oliver Kieselbach d178fa4ef3 consistent switcher everywhere 2026-04-15 01:18:14 +02:00
Oliver Kieselbach 47a73c08d5 changed SLA metrics to be more useful 2026-04-15 01:07:13 +02:00
Oliver Kieselbach 66587b76d3 geo report drill down has now DO usage stats as well 2026-04-15 00:52:44 +02:00
Oliver Kieselbach cfc412d5ff added SLA telemetry 2026-04-14 10:15:01 +02:00
Oliver Kieselbach 8ab14f0d0a fix immediate view of SLA config creation 2026-04-13 20:54:15 +02:00
Oliver Kieselbach c415872e46 feat: SLA tracking dashboard with notifications 2026-04-13 20:19:24 +02:00
Oliver Kieselbach 96a383bb38 bug fix rule stats and chagned stats to be more useful 2026-04-13 15:12:29 +02:00
Oliver Kieselbach 62918c9cbf added rule stats 2026-04-13 14:12:19 +02:00
Oliver Kieselbach e709d568c0 fixed ime function 2026-04-06 16:31:04 +02:00
Oliver Kieselbach 56a3ce259d added IME version history and MCP tool support for the IME history 2026-04-06 15:46:59 +02:00
Oliver Kieselbach f3dc3909a9 better DO calculations 2026-04-05 00:47:21 +02:00
Oliver Kieselbach c7227df06d feat: added DO details to geo report 2026-04-05 00:16:39 +02:00
Oliver Kieselbach d824dd64fd added structured error handler 2026-04-02 22:02:09 +02:00
Oliver Kieselbach 815dc47886 mcp usage fix, backend datetime fix, agent fix orphaned session handling 2026-03-29 17:13:28 +02:00
Oliver Kieselbach dbb8c20a45 fixed usage log, fixed mcp tools, fixed version comparer vul report 2026-03-29 13:28:00 +02:00
Oliver Kieselbach dd2ee928b0 mcp tool extented and meta, mcp usage data UI, better logging for backend 2026-03-29 12:41:09 +02:00
Oliver Kieselbach 219f5c686a oauth for mcp server 2026-03-28 06:15:12 +01:00
Claude 799ec0a39b Migrate GetPlatformStatsFunction to IMetricsRepository
Completes non-Vulnerability function migrations. Remaining 14 files still
using TableStorageService are: 8 Vulnerability functions (use GetTableClient),
ReseedFromGitHub, ApiKeyManagement, BlockedDevice/VersionService,
SessionReportService, ApiKeyMiddleware — these need interface additions first.

https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:42:39 +00:00
Claude 6582faad17 Migrate GetGlobalGeographicMetricsFunction to DAL
https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:38:20 +00:00
Claude 85cd9ae688 Migrate GetGeographicMetricsFunction to DAL
https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:37:58 +00:00
Claude ff6e43cecc Migrate Geographic Location Sessions functions to DAL
https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:37:41 +00:00
Claude cae99b445f Migrate GetAppMetrics, GetGlobalAppMetrics, TenantOffboard refinements
https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:37:11 +00:00
Claude 5b4e4238f3 Migrate Session and Metrics Functions to DAL repository interfaces
Replace direct TableStorageService injection with ISessionRepository,
IMetricsRepository, and IMaintenanceRepository in 10 Function files.
Add GetSessionEventsAsync to ISessionRepository interface.

Migration in progress — more functions and services to follow.

https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
2026-03-27 06:29:17 +00:00
Oliver Kieselbach 9f7d6e23f1 initial mcp server implementation 2026-03-24 08:06:48 +01:00
Oliver Kieselbach 0fd8ca22d1 renaming global admin 2026-03-23 06:28:59 +01:00
Oliver Kieselbach 3ae19f48b2 renaming global admin 2026-03-23 06:27:58 +01:00
Oliver Kieselbach 9d3e254d2e added drill down in geographic performance 2026-03-17 16:42:43 +01:00
Oliver Kieselbach 4ebe9f7c44 re-architectured session handling with session index table 2026-03-17 13:46:43 +01:00
Oliver Kieselbach 79dce7cf58 enhanced usage metrics 2026-03-09 18:45:02 +01:00
Oliver Kieselbach b67f1a447e impelented PolicyEnforcementMiddleware 2026-03-08 17:29:32 +01:00
Oliver Kieselbach c91fd1a43e massive re-org and re-structuring 2026-03-06 03:02:19 +01:00
Oliver Kieselbach d532ffd7a4 massive re-org and re-structuring 2026-03-06 03:01:24 +01:00