- Add userId guard in trace upsert to prevent cross-user overwrites
- Move AUTH_SECRET, STRIPE_WEBHOOK_SECRET, POSTGRES_PASSWORD to .env
- docker-compose.yml now references env vars instead of hardcoded secrets
- Add .env.example with placeholder values for documentation
- Add forgot-password and reset-password pages and API routes
- Add email verification with token generation on registration
- Add resend-verification endpoint with 60s rate limit
- Add shared email utility (nodemailer, Migadu SMTP)
- Add VerificationBanner in dashboard layout
- Add PasswordResetToken and EmailVerificationToken models
- Add emailVerified field to User model
- Extend NextAuth session with isEmailVerified
- Add forgot-password link to login page
- Wire EMAIL_PASSWORD env var in docker-compose
- NextAuth v5 credentials auth with registration/login pages
- API key CRUD (create, list, revoke) with secure hashing
- Stripe checkout, webhooks, and customer portal integration
- Rate limiting per subscription tier
- All dashboard API endpoints scoped to authenticated user
- Prisma schema: User, Account, Session, ApiKey, plus Stripe fields
- Auth middleware protecting dashboard and API routes
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Adds /dashboard/decisions page with colored type badges, search,
filters (by type), sort (newest/oldest/costliest), pagination,
and links to parent traces. New /api/decisions endpoint with
Prisma queries. Removes 'Soon' badge from sidebar nav.
Adds metadataBase, full OpenGraph + Twitter card tags, keywords,
JSON-LD structured data (SoftwareApplication + Organization),
sitemap.ts, robots.ts with AI crawler directives, and llms.txt
for AI agent discoverability.
Spans must be inserted before decision points due to
DecisionPoint.parentSpanId FK referencing Span.id. Switched from
nested Prisma create to interactive transaction with topological
span ordering. Also adds real MoonshotAI LLM test script.
- Remove duplicate span append + tool call decision logging block (lines 328-426)
- Fix _extract_tool_calls_from_response to use getattr() instead of .get() on objects
- Fix _calculate_cost to use exact match first, then longest-prefix match (prevents gpt-4o-mini matching gpt-4 pricing)
- Fix test mock setup: set return_value BEFORE wrap_openai() so wrapper captures correct original
- All 11 OpenAI integration tests + 8 SDK tests passing (19/19)
- LangChain: AgentLensCallbackHandler with auto-span creation for
LLM calls, tool calls, chains, and agent decision logging
- Dashboard: trace list with search, status filters, pagination
- Dashboard: trace detail with Decision/Span/Event tabs
- Dashboard: sidebar layout, responsive design, dark theme
- SDK: client with BatchTransport, trace decorator/context manager,
log_decision, thread-local context stack, nested trace→span support
- API: POST /api/traces (batch ingest), GET /api/traces (paginated list),
GET /api/traces/[id] (full trace with relations), GET /api/health
- Tests: 8 unit tests for SDK (all passing)
- Transport: thread-safe buffer with background flush thread