Commit graph

29 commits

Author SHA1 Message Date
Vadym Samoilenko
327deed1dd feat: budgets scope picker with live dropdowns
Workspace/team/project selects are populated from API on mount.
Falls back to source_apps when projects collection is empty.
Table now shows resolved name + truncated ID hint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:25:17 +01:00
Vadym Samoilenko
fe65b3b309 feat: source app filter as dropdown on dashboard
Fetches available source_apps via breakdown endpoint on mount,
replaces text input with select. Defaults to "All apps".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:20:04 +01:00
Vadym Samoilenko
c85ba20501 fix: use source_app as project dimension, drop empty project_id
project_id is never populated (all null); source_app is the de-facto
project identifier. By Project preset now shows real data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:59:54 +01:00
Vadym Samoilenko
05da6e9b82 fix: show all users in Top Users chart (limit 20, dynamic height, truncate labels)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:52:18 +01:00
Vadym Samoilenko
1c215b571a fix: resolve user IDs to names in Top Users chart on Dashboard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:49:22 +01:00
Vadym Samoilenko
3d0d5c8538 feat: add SVG favicon (indigo bar chart icon)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:47:51 +01:00
Vadym Samoilenko
a8555d40b8 fix: split pivot row dimensions into separate table columns
Each selected row dimension (user, team, source_app, etc.) now gets
its own <th>/<td> instead of being joined into one combined cell.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:45:44 +01:00
Vadym Samoilenko
8e163d8514 feat: add Inter font preconnect for faster load
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:42:22 +01:00
Vadym Samoilenko
e0f5584545 fix: remove /admin/ prefix from explorer API calls (baseURL already includes /admin) 2026-04-27 15:09:44 +01:00
Vadym Samoilenko
6654d57270 feat: redesign Pivot Explorer with presets, name resolution, smart formatting
- Quick view presets: By User, By Model, By Project, By Team
- Resolve user_external_id → full_name (email) from /admin/users
- Resolve project_id → project name from /admin/projects
- Smart cost formatting: $X.XX / $0.XXXX / $0.XXXXXX / exponential
  (fixes 0.0000 display for small google_tts values)
- Sortable columns (click any column header)
- Grand total footer row
- Pill-style dimension chip buttons (no hidden checkboxes)
- Source app filter in controls
- Empty / hint states

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:07:27 +01:00
Vadym Samoilenko
dfa32a91c7 feat: add google_tts generic model pricing + video-accessibility backfill script
- Add google_tts/google_tts entry to models.yaml (16 USD/1M chars, WaveNet tier)
- Add scripts/migrate_video_accessibility.py for historical data backfill:
  migrates 25 users and 103 jobs (Gemini + TTS usage records) from
  accessible_video MongoDB into cost tracker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:59:42 +01:00
Vadym Samoilenko
2822e9cb99 fix: pricing engine unit keys and google→vertex_ai provider alias
- compute_total_cost: read token_input/token_output/char (new keys)
  with fallback to old input_tokens/output_tokens/chars for compat
- _PROVIDER_ALIAS: google/gemini → vertex_ai-language-models
- _infer_provider: gemini → vertex_ai-language-models

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:41:14 +01:00
Vadym Samoilenko
36ce10eb50 fix: show 6 decimal places for small costs (< $0.01)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:36:15 +01:00
Vadym Samoilenko
9491a11903 fix: analytics query usage_events directly for real-time data
- analytics_service now queries usage_events (not usage_rollups)
  so data appears immediately without waiting for nightly rollup
- match on ts datetime range (was string 'date' field — broken)
- correct units field names: token_input/token_output/char
- rollup_daily.py: same field name fix for historical aggregation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:34:19 +01:00
Vadym Samoilenko
954e7c21eb fix: audit log ObjectId serialization, add user PATCH/DELETE endpoints
- _str_id now recursively converts ObjectId in nested before/after fields
- PATCH /admin/users/:id — edit email, full_name, role, workspace_id
- DELETE /admin/users/:id — remove user mirror record
- Users frontend: inline edit form + delete button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 14:22:06 +01:00
Vadym Samoilenko
6d4bd44926 feat: premium redesign v2 — featured KPI card, AreaChart gradient, rgba badges
CSS:
- KPI grid: 2fr 1fr 1fr 1fr 1fr asymmetric layout (breaks "generic AI" pattern)
- kpi-card--featured: indigo gradient bg, white text, decorative glow orb, 34px value
- Surface bg #eef2f7 (deeper than #f8fafc — creates card lift contrast)
- Badges: rgba backgrounds (rgba(99,102,241,0.1)) instead of solid colors
- btn:active: scale(0.97) press feedback — 80ms transition
- chart-card-header with .chart-dot indicator (colored glowing dot)
- skeleton-block shimmer for loading state
- row-action: table buttons hidden by default, fade in on row hover
- Inter font-feature-settings for crisp numerics
- Responsive breakpoints for KPI grid

Dashboard:
- AreaChart with SVG linearGradient fill (indigo, 18% → 0%)
- Featured KpiCard component with loading skeleton + period label
- fmtK() helper: 1.2M / 456K formatting for large token counts
- Initial loading=true to show skeleton immediately on mount
- chart-card-header with dot on all 3 charts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 13:12:04 +01:00
Vadym Samoilenko
cfd6359733 feat: full frontend redesign — premium SaaS UI with CSS design system
- index.css: 580+ new lines — buttons, filter-bar, kpi-grid, chart-card,
  data-table, badges, inline-form, progress-bar, alert-key, pagination,
  stagger animations, keyframes (fadeSlideUp, shimmer)
- hooks/useCountUp.ts: requestAnimationFrame count-up with ease-out cubic
- Dashboard: KPI cards with count-up, dark Recharts tooltips, clean grid lines
- Explorer: styled controls panel, chart-card, data-table
- All 6 list pages: page layout, inline create forms, data-table-wrap,
  badge status pills, progress bars, pagination — zero inline style={{}} on HTML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:54:27 +01:00
Vadym Samoilenko
d4e1e4bf60 feat: add server-side update.sh script for in-place deploys 2026-04-27 12:30:50 +01:00
Vadym Samoilenko
a3c9e5b739 fix: pass VITE_APP_ENV build arg so dev login shows on dev server 2026-04-27 12:27:39 +01:00
Vadym Samoilenko
5c01532e30 fix: add vite-env.d.ts for import.meta.env types 2026-04-27 12:23:28 +01:00
Vadym Samoilenko
e4c9dd80c3 fix: copy source before editable install, add packages path for Poetry 2026-04-27 12:22:13 +01:00
Vadym Samoilenko
7c4b9d8d68 fix: remove secrets from deps (built-in Python module) 2026-04-27 12:21:18 +01:00
Vadym Samoilenko
a083fddf11 fix: remove readme field from pyproject.toml, add README.md 2026-04-27 12:20:50 +01:00
Vadym Samoilenko
c953684cb6 fix: use npm install instead of npm ci (no package-lock.json in repo) 2026-04-27 12:19:41 +01:00
Vadym Samoilenko
8da227275b design: replace inline styles with professional CSS design system
- index.css: full CSS variables design system (tokens, reset, typography)
  Dark sidebar (#0f172a) + light content (#f8fafc) + indigo accent (#6366f1)
- App.tsx: sidebar with inline SVG icons, two-section nav (Analytics / Management),
  CSS class-based layout replacing all inline styles
- Login.tsx: branded login card on dark radial gradient, proper Microsoft SSO button
  with brand colors, dev login section with dashed divider and amber badge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:13:26 +01:00
Vadym Samoilenko
53d0367b94 feat: dev login + optical-dev deploy setup
Backend:
- routes_auth: POST /v1/auth/dev-login — bypass Azure AD (disabled in production),
  creates admin in DB and sets JWT cookie; takes email + full_name
- routes_auth: use settings.frontend_callback_url instead of parsing CORS origins
  for SSO post-login redirect — configurable per environment
- config: add frontend_callback_url setting
- dependencies: fix get_current_admin — was querying _id as string (ObjectId bug)
  and filtering is_active:True (never set by SSO flow)

Frontend:
- Login.tsx: dev login form shown in non-production builds below SSO button
- api.ts: use import.meta.env.BASE_URL so API paths work under any subpath prefix
- main.tsx: pass BASE_URL as BrowserRouter basename for correct SPA routing
- vite.config.ts: read VITE_BASE_PATH env var to set Vite base (default /)
- nginx.conf: serve app at /cost-tracker/ prefix, proxy API routes internally
- Dockerfile: accept VITE_BASE_PATH build arg, copy build to /cost-tracker/ subdir

Infra:
- docker-compose.yml: API host port 8003 (8001 taken by ppt-tool on optical-dev)
- infra/deploy/apache-cost-tracker.conf: Apache include for optical-dev routing
- infra/deploy/deploy.sh: one-shot deploy script (clone/pull, build, Apache config)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:05:42 +01:00
Vadym Samoilenko
c595ea47d7 fix: resolve startup import errors and Docker port conflicts for optical-dev deploy
- database.py: add connect_db/disconnect_db aliases, get_db_instance() sync
  getter, get_db() async dependency, and optional db arg on create_indexes()
  to match all call sites in main.py, celery_worker.py, and route modules
- docker-compose.yml: remove host-port exposure for mongodb/redis to avoid
  conflicts with existing services on optical-dev (:27017, :6379 already in use)
- .env.example: use Docker service-name hostnames (mongodb/redis) instead of
  localhost so the API container can reach them inside the Compose network

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 11:56:41 +01:00
Vadym Samoilenko
2f070ce503 feat: initial implementation of Oliver AI Cost Tracker
Complete Phase 1 implementation:

Backend (FastAPI + MongoDB + Celery):
- Core: config, DB with indexes, JWT security, API key auth middleware
- Models: org hierarchy (workspace/team/project), user mirror, pricing,
  usage events/rollups, budgets, alert log, audit log
- Services: pricing engine (LiteLLM/YAML/override priority), budget check
  with preflight, email alerts at 50/80/100%, analytics aggregations,
  audit logger
- API routes: public (preflight/record/upsert), admin CRUD, pricing
  management, budget management, analytics (summary/timeseries/breakdown/pivot),
  Microsoft SSO auth
- Celery tasks: daily LiteLLM price sync with change notifications,
  daily rollup aggregation, 5-minute alert evaluator
- Pricing catalogue: ElevenLabs + Google Cloud TTS in models.yaml

SDK (oliver-cost-tracker Python package):
- CostTracker client with httpx + exponential backoff (3 retries)
- SQLite outbox with 30s background flusher (never blocks AI pipeline)
- Estimators: token/char estimation per provider
- BudgetExceeded / CostTrackerUnavailable exceptions

Frontend (React 18 + Vite + TypeScript):
- Dashboard with KPI cards, daily cost timeseries, top-model/top-user charts
- Pivot Explorer with multi-dim row/col selection + stacked bar chart + table
- Admin pages: Workspaces, Pricing (with LiteLLM sync + override), Budgets
  (with live spend bar), API Keys (show-once), Users (mirror), Audit Log
- Microsoft SSO login flow

Infra: docker-compose.yml (mongo + redis + api + celery worker + beat + frontend)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 11:26:08 +01:00
Vadym Samoilenko
aaa8b61ec2 Initial commit 2026-04-27 09:51:21 +00:00