Commit History
-
fix(security): resolve critical and high technical debt from audit
CognxSafeTrackCRITICAL: - Exclude passwordHash from enrollment list response (admin.ts) - Add sanitizeOrg() to strip API keys/tokens from all org GET responses - Fix CORS wildcard on SSE stream; use request origin instead - Restrict super-admin routes to SUPER_ADMIN role only (was also allowing ADMIN) - Replace all Zod .parse() with .safeParse() → proper 400s instead of 500s (ai.ts, admin.ts) HIGH: - Increase ExerciseHandler Redis dedup lock from 30s to 300s - Add take:500 to unbounded trainingData.findMany (OOM risk) - Add take limits to message/contact findMany queries - Add Redis lock in EnrollHandler to prevent duplicate enrollments (TOCTOU) - Wrap override-feedback in try/catch; return 404 on P2025 - Use atomic increment for wallet credits (was TOCTOU race condition) - Scope messages/send to requesting org (was cross-org accessible) MEDIUM: - decryptSecrets returns new object instead of mutating argument in-place - GeminiProvider.generateStructuredData now validates response with Zod schema -…a8e18d6 -
fix(crm-agent): replace generateText+JSON.parse with generateStructuredData for intent detection
CognxSafeTrackThe CRM command agent was always falling back to GENERAL_CHAT and showing the menu again because LLMs wrap JSON in markdown fences, breaking JSON.parse. Switch to generateStructuredData with a Zod schema which guarantees structured output regardless of LLM quirks. Also exposes generateStructuredData as a public method on AIService.3b3d6cd -
fix(audit): resolve remaining TypeScript any types, string enums, and Json validation
CognxSafeTrack +1: Claude Sonnet 4.6TypeScript types (ai-sdk): - Define AIServicePrismaClient structural interface — replaces prisma: any - Define TenantSecrets interface — replaces getTenantSecrets: () => Promise<any> - Define BusinessProfileContext interface — replaces businessProfile?: any in 3 methods - Define BusinessProfileExtraction interface — extractBusinessProfile now fully typed - Define ContactData interface — replaces contact: any in generateCrmCampaign - exerciseCriteria? typed as Record<string, unknown> instead of any - searchResults now typed as SearchResult[] instead of any[] DB enums: - CampaignHistory.status: String → CampaignStatus enum (SENT | DELIVERED | READ | FAILED) - AnalyticsLog.eventType: String → AnalyticsEventType enum (CLICK | READ | RESPONSE) - Migration 20260514000001 applied to production DB Zod validation: - TrackDaySchema: add exerciseCriteria (z.record) and badges (z.array(z.string)) - ai.ts /crm/generate-campaign: enforce contact.phoneNumber (required) via Zod Runtime safety: - wh…2a3e2a1 -
fix(audit): resolve remaining minor technical debt issues
CognxSafeTrack +1: Claude Sonnet 4.6AI/BYOK: - generateText now respects tenant BYOK keys via getProvidersForTenant() (was using global registry) - generateText now applies exponential backoff retry via AIService.withRetry() Backend: - notifications.ts: return 503 instead of 200+undefined when VAPID_PUBLIC_KEY absent - BillingPage: support WA number now reads from VITE_SUPPORT_WA_NUMBER env var (was hardcoded fake number) - KnowledgeBasePage: show toast.error on delete failure (was silently swallowed) DB: - Add @@index([organizationId, exerciseStatus]) on UserProgress for live-feed query performance - Add @@index([createdAt]) on AuditLog for time-range admin queries - Migration 20260513000005 applied to production DB i18n: - Add knowledge.delete_error translation key to all 4 locales (fr, en, es, pt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>d74c1b3
-
fix(audit): resolve 15 critical and major technical debt issues
CognxSafeTrack +1: Claude Sonnet 4.6Security: - campaigns.ts: prevent cross-tenant write by using req.organizationId instead of URL param - billing.ts: restrict org mode change to SUPER_ADMIN only (was incorrectly allowing ADMIN) - CommandHandler: guard SEED command with NODE_ENV !== 'production' - search.ts: return [] instead of fabricated mock data when SERPER_API_KEY absent - scheduler: filter out hard-stopped organizations from nudge and lesson delivery - payments.ts: HMAC signature verification for Wave and Orange Money webhooks + fix track.priceAmount Data integrity: - schema: TrackDay.dayNumber Float → Int, Enrollment.currentDay Float → Int - schema: add @@unique([userId, trackId]) to Enrollment to prevent race condition double-enrollment - Migration 20260513000004 applied to production DB Performance: - admin.ts /live-feed: fix N+1 queries with batch findMany + in-memory map - organizations.ts /:id/messages: add pagination (was unbounded, OOM risk) - crm-service.ts listMessages: add skip/limit/total support Co…97f541f -
fix(jour11): real Gemini vision for team member extraction + correct mediaType
CognxSafeTrack +1: Claude Sonnet 4.6- ai-sdk: add extractTeamMemberFromImage() — uses callWithFailover with VISION capability (Gemini base64 inlineData), structured schema {name, role, bio} - FeedbackHandler: replace generateText() (text-only) with extractTeamMemberFromImage() so Day 11 photos are actually analyzed visually, not just via URL in text prompt - MediaHandler: fix hardcoded mediaType AUDIO → IMAGE for image mimeTypes; remove duplicate isImage declaration in spinner block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9d56788 -
feat: complete agentic audit roadmap — retry, KB generate, real costs, traceId, rate-limit
CognxSafeTrack +1: Claude Sonnet 4.6- ai-sdk: exponential backoff retry (3 attempts, 1s→2s) in callWithFailover; skips 4xx and QuotaExceededError - api/whatsapp: traceId (crypto.randomUUID) propagated to worker bridge via x-trace-id header - api/whatsapp: route-level rate limit 500/min on POST /webhook, returns 200 on rejection - api/organizations: POST /:id/kb/generate — GPT-4o-mini JSON mode generates FAQ pairs, embeds via IndexingService - api/indexing-service: new service batching OpenAI text-embedding-3-small + pgvector INSERT - admin/AnalyticsPage: real cost from UsageEvent aggregate + byFeature breakdown table - admin/KnowledgeBasePage: KB auto-generation panel (description textarea, generate button, FAQ preview) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>b438786 -
feat: Claude Sonnet 4.6 provider + Stripe billing automation
CognxSafeTrack +1: Claude Sonnet 4.6AI: - packages/ai-sdk: ClaudeProvider implements LLMProvider via tool_use structured outputs + zod-to-json-schema - Claude registered at priority 120 (TEXT only), supersedes Gemini for feedback/lessons/chat — -40% cost, better French - ANTHROPIC_API_KEY added to API and worker env validation Stripe: - apps/api/src/routes/stripe.ts: POST /v1/stripe/webhook handles checkout.session.completed, subscription.updated/deleted, invoice.payment_failed/succeeded - Schema: stripeCustomerId + stripeSubscriptionId added to Organization - tenant.ts: 402 gate for isHardStopped orgs (x-api-key calls always pass) - ClientsManagementView: SUSPENDU badge on hard-stopped orgs - STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET added to config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>4a0c3ba -
feat(agentic-week2-4): 5 major features — AI content generator, handoff, tags, soft-delete, SSE
CognxSafeTrack +1: Claude Sonnet 4.6## Agent Créateur de Contenu (Semaine 3) - AIService.generateCurriculum() — structured GPT-4o prompt generates full Track + TrackDays - POST /v1/organizations/:id/content/ai-generate — persists curriculum directly to DB - TrackListPage: "Générer avec IA" button + modal (description, numDays, language, audience) - Auto-redirects to the generated program days after creation ## Human Handoff Detection (Semaine 4) - AIAgentHandler: detects 15 multilingual handoff keywords (FR/EN/ES) - Sets Redis flag handoff:{userId}:{orgId} (24h) — pauses AI responses - Emails org admin with contact info + link to admin UI - Handles subsequent messages while in handoff mode gracefully ## Contact Segmentation by Tags (Semaine 2) - Contact.tags String[] added to Prisma schema (migration + db:push applied) - GET /contacts/tags — list all unique tags in org - PATCH /contacts/:id/tags — set tags on a contact - GET /contacts?tags=tag1,tag2 — filter contacts by tags (hasSome) ## SSE Real-time Updates (Semaine…99f6bca
-
feat(billing): complete billing system, push notifications, and tech debt fixes
CognxSafeTrack +1: Claude Sonnet 4.6- Usage tracking: instrument pedagogy, audio transcription, AI Agent mode (was silently untracked) - EmailHandler: implement templates 2 (password reset), 3 (quota alert), 4 (monthly report) - Quota alert: auto-queue email + push at 85% threshold via maybeQueueQuotaAlert - Push notifications: PushHandler + send-push BullMQ job; sendPushToUser scoped by organizationId to prevent cross-tenant reads - BillingPage: add credit recharge modal with 3 packs, null guard for missing orgId - i18n: add nav.billing key in fr/en/es/pt locales - Tests: billing.test.ts (10 tests), payments.test.ts (13 tests) - Tech debt: fix empty catch blocks in ai-pedagogy.ts, exclude usage tokens from CRM API response, pass organizationId to generateChat in AIAgentHandler - Docs: add backlog and business model to docs/business/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>8280d7d -
fix(bot): eliminate double feedback, fix gemini model, fix multilingual prompts
CognxSafeTrack +1: Claude Sonnet 4.61. Double feedback (critical): Bridge was enqueuing both download-media AND handle-inbound for every audio/image message. Both paths independently transcribed the audio and called WhatsAppLogic.handleIncomingMessage → two generate-feedback jobs → user received two Coach responses. Fix: remove handle-inbound and send-message-direct from bridge for media. MediaHandler (download-media) already handles full pipeline. MediaHandler now sends a localized spinner after user lookup (sendSpinner flag). 2. gemini-1.5-pro → 404: gemini-1.5-pro is deprecated via Google API v1beta. Updated GeminiProvider to use gemini-2.0-flash for both flash and complex (pro) requests. 3. Multilingual deep-dive invitation (EN/ES/PT): action-feedback-standard.md only had FR and WO variants for the APPROFONDIR/SUITE invitation at end of feedback. Added EN, ES, PT — AI was mixing languages for English/Spanish/Portuguese users. 4. InboundHandler [object Object] bug: aiService.tran…5f0a436
-
feat: backlog P0→P3 — toast system, payments, tenant isolation, feedback handler, i18n parity
CognxSafeTrack +1: Claude Sonnet 4.6P0 — Critical fixes - Fix generate-feedback job silently dropped: register FeedbackHandler in worker index.ts - Wire FeedbackHandler: AI feedback, Day 11 TeamMember extraction, atomicity enforced P0 — Toast system (replace all alert()) - Add useToast hook + ToastContext + Toaster component - Replace every alert() across admin pages with toast.success/error/warning/info - Migrate all raw fetch() in pages to api.upload() / api.get() / api.post() P1 — Type safety - CrmAIAssistant: icon prop any → React.ElementType - useAudioRecorder: add onError callback instead of alert() - api.ts: add upload() method for multipart FormData P1 — Payment gateway - Add payment-gateway.ts: Orange Money + Wave initiation and webhook parsing - Rewrite payments.ts routes: initiate, status, webhook handlers with auto-enrollment on SUCCESS P1 — AI regression tests - Add apps/api/test/regression/ai-gold-standards.test.ts (12 tests, 5 suites) P2 — Visual recruitment (Day 11) - FeedbackHandler extracts TeamMem…6dd9bad
-
chore: stabilization, audit fixes and project synchronization
CognxSafeTrack7b0c22b
-
feat: centralize AI logic in @repo /ai-sdk, harmonize worker HTTP clients
CognxSafeTrack +1: Claude Sonnet 4.6Architecture refactoring: - Extract all AI providers (OpenAI, Gemini, ProviderRegistry, ffmpeg, search) from apps/api/src/services/ai/ into new packages/ai-sdk package - API's services/ai/index.ts is now a thin wrapper that injects prisma, redis and organization context into the shared AIService - Worker gains @repo/ai-sdk dependency; ai-pedagogy.ts delegates to aiService.generatePersonalizedLesson instead of duplicating logic - New apiClient (Axios, 30s timeout) and whatsappClient replace bare fetch calls in InboundHandler and MediaHandler for consistent error handling - Prisma seed fixed: Tracks now include organizationId for multi-tenant compliance Build: all 8 packages pass pnpm turbo run build from clean state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>2849f33