diff --git a/.env.example b/.env.example index d1e47fa..e77831a 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ -# Copy this file to .env and provide your private OpenAI API key. +# Copy this file to server/.env (or export the variables) before running the Node service. OPENAI_API_KEY=replace-with-your-openai-api-key -# Optionally override the Flask secret key for session security -# FLASK_SECRET_KEY=change-me +PORT=5001 diff --git a/.gitignore b/.gitignore index b6cf5f0..7b3ca18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ -__pycache__/ -*.pyc +node_modules/ +client/node_modules/ +server/node_modules/ +dist/ +client/dist/ +server/dist/ .env +server/.env +.DS_Store diff --git a/README.md b/README.md index cbf1c16..d0652b5 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,107 @@ -# Insight Navigator +# Insight Nexus CRM -Insight Navigator is a local-first business intelligence assistant that combines -predictive analytics, risk management, and guided advisory conversations through -your ChatGPT connection. +Insight Nexus CRM is an immersive, local-first Vite + React command center for predictive revenue intelligence. +It fuses data management, forecasting, risk analysis, AI advisory, and deep comparison workflows into one cinematic +experience powered by your private OpenAI key. + +## Architecture + +``` +root +├── client # Vite + React + Tailwind front-end (TypeScript) +└── server # Node/Express API broker that talks to OpenAI Responses +``` + +The UI runs on Vite (port 5173) and proxies API calls to the Node service (port 5001 by default). All OpenAI traffic +is handled server-side so your key never touches the browser. ## Features -- **Business predictor module** that transforms your metrics into growth outlooks - and actionable recommendations. -- **Risk management insights** with mitigation strategies aligned to your stated - tolerance level. -- **Dynamic SWOT summaries** and professional-grade data visualizations powered by Chart.js. -- **Advisor chat workspace** for continuing strategic discussions and next steps. -- **Responsive, multi-page Flask interface** with polished styling. +- **Data fabric ops** – upload CRM CSV/JSON/TXT intelligence, track freshness, and surface AI-generated coverage maps. +- **Prediction studio** – craft multi-dimensional business scenarios, attach documents, and receive structured forecasts, + risk posture, CRM plays, and AI advisory in one response. +- **Risk command** – monitor Atlas-generated risk matrices, mitigation sprints, and telemetry streams in a premium glassmorphism UI. +- **AI advisor** – chat with Atlas, the revenue copilot, for executive-ready guidance that remembers context across turns. +- **Collaboration hub** – upload two intelligence files for deep delta analysis with suggested actions, automation plays, and executive summaries. ## Prerequisites -1. Python 3.10+ -2. An OpenAI API key with access to the ChatGPT Responses API. +- Node.js 18+ +- npm 9+ +- An OpenAI API key with access to the Responses API (e.g., `gpt-4.1-mini`) + +## Setup + +### Windows quick-start + +If you're on Windows 11, the repository includes helper scripts: + +1. Double-click `install.bat` to verify Node/npm are available and install server/client dependencies. The installer skips + modules that are already present. +2. Copy `server/.env.example` to `server/.env` and set `OPENAI_API_KEY=`. +3. Double-click `run.bat` to launch both the Node API broker and Vite client in separate terminals. -## Quick start +### Manual setup -1. Clone the repository and move into the project directory. -2. Run the auto-installer (skips packages that are already installed): +1. **Install dependencies** ```bash - python install.py + cd server && npm install + cd ../client && npm install ``` - On Windows you can double-click `install.bat` or run it from a terminal: +2. **Configure environment variables** - ```bat - install.bat + ```bash + cp server/.env.example server/.env + # edit server/.env and set OPENAI_API_KEY= ``` -3. Create a `.env` file based on the provided template and add your private key: + The server respects `PORT` (default `5001`). Ensure it matches the proxy target in `client/vite.config.ts` if changed. + +3. **Run the Node API broker** ```bash - cp .env.example .env - # edit .env and set OPENAI_API_KEY without quotes + cd server + npm run dev ``` -4. Launch the application: +4. **Run the Vite client** + + In a second terminal: ```bash - python app.py + cd client + npm run dev ``` -5. Open your browser at [http://localhost:5000](http://localhost:5000). +5. Navigate to [http://localhost:5173](http://localhost:5173) to experience the Insight Nexus CRM suite. + +## Usage workflow + +- Start in **Command Center** to review real-time telemetry and AI advisories. +- Head to **Data Management** to ingest supporting docs and monitor Atlas automations. +- Launch predictions in **Predictive Strategy**; attach up to four documents to enrich outcomes. +- Use **Risk Command** to understand threat vectors and mitigation plays. +- Chat with **AI Advisor** for curated actions, then compare intelligence files inside **Collaboration Hub** for deep delta insights. + +## Testing & linting + +- Front-end: `cd client && npm run lint` +- Server: `cd server && npm run lint` -## Usage tips +Both projects are TypeScript/ESM aware. Adjust scripts or integrate additional tooling as needed. -- Populate the predictor form with the most recent financial metrics to receive - tailored forecasts, mitigation plans, and SWOT analysis. -- Use the advisor chat page to iterate on board decks, investor updates, or go-to-market plans. -- The application never stores your API key; it reads the value from the - environment at runtime. +## Security -## Development +- Never expose your OpenAI key to the browser. Keep it in `server/.env` or your preferred secret manager. +- Do not commit `.env` files. Keys listed here are placeholders only. +- Consider adding request authentication before deploying beyond localhost. -- Additional Python dependencies can be installed with `pip install -r requirements.txt`. -- The Flask app entry point is `app.py`; the blueprint routes live in `app/routes.py`. -- Static assets are managed in `static/` and HTML templates in `templates/`. +## Troubleshooting -## Security note +- If you encounter `Unable to generate insights` or `Unable to compare documents`, confirm the server console is running and that + `OPENAI_API_KEY` is valid. +- Update the `model` in `server/src/index.js` to match the tier available to your account if `gpt-4.1-mini` is unavailable. -Never commit your real API key to version control. Keep `.env` files private and -rotate keys regularly according to your organization’s security policies. +Enjoy orchestrating a next-generation CRM experience powered by Atlas. diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs new file mode 100644 index 0000000..0379c21 --- /dev/null +++ b/client/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-refresh/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { jsx: true }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['@typescript-eslint', 'react-refresh'], + rules: { + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], + }, +}; diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..e5c2a47 --- /dev/null +++ b/client/index.html @@ -0,0 +1,13 @@ + + + + + + + Insight Nexus CRM + + +
+ + + diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..29e3487 --- /dev/null +++ b/client/package.json @@ -0,0 +1,44 @@ +{ + "name": "insight-crm-client", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint \"src/**/*.{ts,tsx}\"" + }, + "dependencies": { + "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.1", + "axios": "^1.7.7", + "framer-motion": "^11.3.16", + "lucide-react": "^0.446.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.52.0", + "react-router-dom": "^6.26.2", + "recharts": "^2.10.4", + "zod": "^3.23.8", + "@hookform/resolvers": "^3.9.0", + "react-dropzone": "^14.2.3" + }, + "devDependencies": { + "@types/node": "^22.7.4", + "@types/react": "^18.3.5", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^8.9.0", + "@typescript-eslint/parser": "^8.9.0", + "autoprefixer": "^10.4.20", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.11", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.13", + "typescript": "^5.6.2", + "vite": "^5.4.10" + } +} \ No newline at end of file diff --git a/client/postcss.config.js b/client/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/client/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/client/src/components/ChatPanel.tsx b/client/src/components/ChatPanel.tsx new file mode 100644 index 0000000..fbde4cc --- /dev/null +++ b/client/src/components/ChatPanel.tsx @@ -0,0 +1,80 @@ +import { FormEvent, useMemo, useState } from 'react'; +import { motion } from 'framer-motion'; +import { Bot, Send } from 'lucide-react'; +import { useChat } from '../hooks/useChat'; + +export const ChatPanel = () => { + const [message, setMessage] = useState(''); + const { history, sendMessage, loading } = useChat(); + + const reversedHistory = useMemo(() => [...history].reverse(), [history]); + + const handleSubmit = async (event: FormEvent) => { + event.preventDefault(); + if (!message.trim()) return; + await sendMessage(message.trim()); + setMessage(''); + }; + + return ( +
+
+ + + +
+

Atlas Copilot

+

Strategic CRM advisor

+
+
+
+ {reversedHistory.map((entry, index) => ( + +
+ {entry.content} +
+
+ ))} + {loading && ( + +
+ Atlas is synthesizing... +
+
+ )} +
+
+
+ setMessage(event.target.value)} + /> + +
+
+
+ ); +}; diff --git a/client/src/components/GradientCard.tsx b/client/src/components/GradientCard.tsx new file mode 100644 index 0000000..7d1d3ef --- /dev/null +++ b/client/src/components/GradientCard.tsx @@ -0,0 +1,27 @@ +import { PropsWithChildren, ReactNode } from 'react'; + +interface GradientCardProps extends PropsWithChildren { + title: string; + subtitle?: string; + icon?: ReactNode; + emphasis?: 'accent' | 'neon'; +} + +export const GradientCard = ({ title, subtitle, icon, emphasis = 'accent', children }: GradientCardProps) => ( +
+
+
+
+

{subtitle}

+

{title}

+
+ {icon && {icon}} +
+
{children}
+
+
+); diff --git a/client/src/components/Layout.tsx b/client/src/components/Layout.tsx new file mode 100644 index 0000000..0930c11 --- /dev/null +++ b/client/src/components/Layout.tsx @@ -0,0 +1,18 @@ +import { PropsWithChildren } from 'react'; +import { Navigation } from './Navigation'; + +export const Layout = ({ children }: PropsWithChildren) => ( +
+ +
+
+
+
+
{children}
+
+
+
+); diff --git a/client/src/components/MetricCard.tsx b/client/src/components/MetricCard.tsx new file mode 100644 index 0000000..c0a0ee8 --- /dev/null +++ b/client/src/components/MetricCard.tsx @@ -0,0 +1,39 @@ +import { ReactNode } from 'react'; +import { motion } from 'framer-motion'; + +interface MetricCardProps { + label: string; + value: string; + trend?: string; + icon: ReactNode; + accent?: 'primary' | 'success' | 'warning'; +} + +const ACCENT_MAP = { + primary: 'from-accent/60 via-accent/30 to-transparent border-accent/50', + success: 'from-emerald-500/60 via-emerald-500/20 to-transparent border-emerald-400/40', + warning: 'from-amber-500/60 via-amber-500/20 to-transparent border-amber-400/40', +}; + +export const MetricCard = ({ label, value, trend, icon, accent = 'primary' }: MetricCardProps) => ( + +
+
+
+

{label}

+

{value}

+ {trend &&

{trend}

} +
+
+ {icon} +
+
+ +); diff --git a/client/src/components/Navigation.tsx b/client/src/components/Navigation.tsx new file mode 100644 index 0000000..9bba754 --- /dev/null +++ b/client/src/components/Navigation.tsx @@ -0,0 +1,63 @@ +import { NavLink } from 'react-router-dom'; +import { Layers, Database, LineChart, ShieldCheck, Bot, MessagesSquare } from 'lucide-react'; +import { motion } from 'framer-motion'; + +const NAV_ITEMS = [ + { to: '/overview', label: 'Command Center', icon: Layers }, + { to: '/data', label: 'Data Management', icon: Database }, + { to: '/prediction', label: 'Predictive Strategy', icon: LineChart }, + { to: '/risk', label: 'Risk Command', icon: ShieldCheck }, + { to: '/advisor', label: 'AI Advisor', icon: Bot }, + { to: '/collaboration', label: 'Collaborative Chat', icon: MessagesSquare }, +]; + +export const Navigation = () => ( +
+
+
+ + Atlas + + Insight Nexus +
+

+ Enterprise CRM intelligence fabric layering predictions, risk sensing, AI co-pilots, and deal velocity in one command + desk. +

+
+ +
+

Telemetry

+

Live CRM pipelines synchronized

+

Data refresh cadence: every 12 minutes

+
+
+); diff --git a/client/src/components/UploadDropzone.tsx b/client/src/components/UploadDropzone.tsx new file mode 100644 index 0000000..986b6db --- /dev/null +++ b/client/src/components/UploadDropzone.tsx @@ -0,0 +1,59 @@ +import { useCallback, useState } from 'react'; +import { useDropzone } from 'react-dropzone'; +import { UploadCloud } from 'lucide-react'; + +interface UploadDropzoneProps { + onFiles: (files: File[]) => void; + label: string; + description?: string; + maxFiles?: number; +} + +export const UploadDropzone = ({ onFiles, label, description, maxFiles = 4 }: UploadDropzoneProps) => { + const [active, setActive] = useState(false); + + const onDrop = useCallback((acceptedFiles: File[]) => { + onFiles(acceptedFiles.slice(0, maxFiles)); + setActive(false); + }, [onFiles, maxFiles]); + + const { getRootProps, getInputProps, isDragActive, acceptedFiles } = useDropzone({ + onDrop, + maxFiles, + }); + + return ( +
setActive(true)} + onDragLeave={() => setActive(false)} + > + +
+ + + +
+

{label}

+ {description &&

{description}

} +
+ {acceptedFiles.length > 0 && ( +
+

Attached

+
    + {acceptedFiles.map((file) => ( +
  • + {file.name} + {(file.size / 1024).toFixed(1)} KB +
  • + ))} +
+
+ )} +
+
+ ); +}; diff --git a/client/src/components/VelocityTrend.tsx b/client/src/components/VelocityTrend.tsx new file mode 100644 index 0000000..fcf80c5 --- /dev/null +++ b/client/src/components/VelocityTrend.tsx @@ -0,0 +1,32 @@ +import { Area, AreaChart, ResponsiveContainer, Tooltip, XAxis } from 'recharts'; + +interface VelocityTrendProps { + data: Array<{ period: string; value: number; baseline?: number }>; +} + +const tooltipStyles = { + backgroundColor: 'rgba(5, 6, 10, 0.85)', + borderRadius: '16px', + border: '1px solid rgba(75, 107, 251, 0.3)', + padding: '12px', + color: '#fff', +}; + +export const VelocityTrend = ({ data }: VelocityTrendProps) => ( +
+ + + + + + + + + + + + + + +
+); diff --git a/client/src/hooks/useChat.ts b/client/src/hooks/useChat.ts new file mode 100644 index 0000000..70081b1 --- /dev/null +++ b/client/src/hooks/useChat.ts @@ -0,0 +1,39 @@ +import { useCallback, useRef, useState } from 'react'; +import axios from 'axios'; + +type ChatMessage = { role: 'user' | 'assistant'; content: string }; + +type ChatResponse = { reply: string }; + +export const useChat = () => { + const [history, setHistory] = useState([]); + const [loading, setLoading] = useState(false); + const historyRef = useRef([]); + + const sendMessage = useCallback(async (prompt: string) => { + const trimmed = prompt.trim(); + if (!trimmed) return; + + setLoading(true); + const userMessage: ChatMessage = { role: 'user', content: trimmed }; + historyRef.current = [...historyRef.current, userMessage]; + setHistory(historyRef.current); + + try { + const response = await axios.post('/api/chat', { + prompt: trimmed, + history: historyRef.current.map((entry) => ({ role: entry.role, content: entry.content })), + }); + const assistantMessage: ChatMessage = { role: 'assistant', content: response.data.reply }; + historyRef.current = [...historyRef.current, assistantMessage]; + setHistory(historyRef.current); + } catch (error) { + historyRef.current = [...historyRef.current, { role: 'assistant', content: 'Atlas encountered an error. Please retry shortly.' }]; + setHistory(historyRef.current); + } finally { + setLoading(false); + } + }, []); + + return { history, loading, sendMessage }; +}; diff --git a/client/src/lib/api.ts b/client/src/lib/api.ts new file mode 100644 index 0000000..d37151b --- /dev/null +++ b/client/src/lib/api.ts @@ -0,0 +1,79 @@ +import axios from 'axios'; +import { z } from 'zod'; + +const metricSchema = z.object({ + label: z.string(), + value: z.string(), + trend: z.string().optional(), +}); + +const insightsSchema = z.object({ + prediction: z.object({ + headline: z.string(), + confidence: z.string(), + quarterlyOutlook: z.array(z.string()), + }).optional(), + riskAnalysis: z.object({ + threatMatrix: z.object({ + strategic: z.array(z.string()), + financial: z.array(z.string()), + operational: z.array(z.string()), + }), + mitigations: z.array(z.string()), + }).optional(), + dataSignals: z.array(z.string()).optional(), + aiAdvisory: z.object({ + narrative: z.string(), + nextMoves: z.array(z.string()), + }).optional(), + crmPlays: z.object({ + expansion: z.array(z.string()), + retention: z.array(z.string()), + upsell: z.array(z.string()), + }).optional(), + supportingRationale: z.string().optional(), +}); + +const comparisonSchema = z.object({ + overview: z.string().optional(), + dataQuality: z.object({ + matches: z.array(z.string()), + gaps: z.array(z.string()), + actions: z.array(z.string()), + }).optional(), + revenueImpact: z.object({ + wins: z.array(z.string()), + leaks: z.array(z.string()), + plays: z.array(z.string()), + }).optional(), + riskRegister: z.array(z.string()).optional(), + aiAutomation: z.array(z.string()).optional(), + executiveSummary: z.string().optional(), +}); + +export type InsightResponse = z.infer; +export type ComparisonResponse = z.infer; + +export const submitInsightRequest = async (payload: FormData) => { + const response = await axios.post('/api/insights', payload, { + headers: { 'Content-Type': 'multipart/form-data' }, + }); + return { data: insightsSchema.parse(response.data.insights), raw: response.data }; +}; + +export const submitComparisonRequest = async (payload: FormData) => { + const response = await axios.post('/api/compare', payload, { + headers: { 'Content-Type': 'multipart/form-data' }, + }); + return { data: comparisonSchema.parse(response.data.analysis), raw: response.data }; +}; + +export const parseMetrics = (text: string | undefined) => { + if (!text) return [] as Array>; + try { + const parsed = JSON.parse(text); + return z.array(metricSchema).parse(parsed); + } catch (error) { + return []; + } +}; diff --git a/client/src/main.tsx b/client/src/main.tsx new file mode 100644 index 0000000..3aef91e --- /dev/null +++ b/client/src/main.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom'; +import App from './routes/App'; +import './styles/index.css'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + , +); diff --git a/client/src/pages/AiAdvisor.tsx b/client/src/pages/AiAdvisor.tsx new file mode 100644 index 0000000..4d94306 --- /dev/null +++ b/client/src/pages/AiAdvisor.tsx @@ -0,0 +1,50 @@ +import { Sparkles, Workflow, ListCheck } from 'lucide-react'; +import { GradientCard } from '../components/GradientCard'; +import { ChatPanel } from '../components/ChatPanel'; + +export const AiAdvisor = () => ( +
+
+
+

Atlas Copilot

+

AI revenue advisor

+

+ Engage Atlas for decision-grade advisory. Blend predictions, risk optics, and CRM plays into orchestrated actions and + executive narratives. +

+
+
+

Online

+

Latency < 2.3s

+

Context memory synchronized

+
+
+ +
+ +
+ }> +
    +
  • Board-ready forecast briefing in 90 seconds.
  • +
  • Win / churn dual-track advice for top 20 accounts.
  • +
  • Custom GTM war-rooms with executive scripts.
  • +
+
+ } emphasis="neon"> +
    +
  • Summon renewal rescue squad for health score < 60.
  • +
  • Trigger pricing A/B for enterprise packaging insights.
  • +
  • Launch AI account briefings to field teams weekly.
  • +
+
+ }> +
    +
  • Atlas cross-references pipeline + finance for each ask.
  • +
  • Recommendations cite risk, growth, and resources.
  • +
  • Chat retains context for multi-turn strategic planning.
  • +
+
+
+
+
+); diff --git a/client/src/pages/CollaborationHub.tsx b/client/src/pages/CollaborationHub.tsx new file mode 100644 index 0000000..72a5db1 --- /dev/null +++ b/client/src/pages/CollaborationHub.tsx @@ -0,0 +1,191 @@ +import { useState } from 'react'; +import { Loader2, FolderGit2, Users } from 'lucide-react'; +import { GradientCard } from '../components/GradientCard'; +import { UploadDropzone } from '../components/UploadDropzone'; +import { submitComparisonRequest, ComparisonResponse } from '../lib/api'; + +export const CollaborationHub = () => { + const [documents, setDocuments] = useState([]); + const [analysis, setAnalysis] = useState(null); + const [loading, setLoading] = useState(false); + + const handleCompare = async () => { + if (documents.length < 2) return; + setLoading(true); + const payload = new FormData(); + documents.slice(0, 2).forEach((file) => payload.append('documents', file)); + + try { + const response = await submitComparisonRequest(payload); + setAnalysis(response.data); + } catch (error) { + setAnalysis({ + overview: 'Atlas could not complete the delta analysis.', + dataQuality: { + matches: ['Verify the Node backend is running at :5001.'], + gaps: ['Confirm OPENAI_API_KEY is configured.'], + actions: ['Retry the comparison once connectivity is restored.'], + }, + revenueImpact: { + wins: [], + leaks: [], + plays: [], + }, + riskRegister: ['Comparison offline.'], + aiAutomation: ['No automation executed.'], + executiveSummary: 'Retry the request later.', + }); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+

Collaboration Core

+

AI comparison workspace

+

+ Upload two CRM intelligence files. Atlas performs deep delta analysis, highlights risk, and proposes joint actions + across revenue, product, and success pods. +

+
+
+

Collab

+

Live squads

+

8 rooms

+
+
+ +
+ }> + + + + + } emphasis="neon"> +
    +
  • Revenue ops ⇄ Finance — Pricing & forecast sync.
  • +
  • Product ⇄ Success — Churn triggers & adoption plays.
  • +
  • Sales ⇄ Legal — Deal desk policy acceleration.
  • +
+
+
+ + }> + {loading &&

Synthesizing deep comparison...

} + {!loading && analysis && ( +
+
+

Overview

+

{analysis.overview}

+

Data Quality

+
+ {analysis.dataQuality && ( + <> +
+

Matches

+
    + {analysis.dataQuality.matches.map((item) => ( +
  • {item}
  • + ))} +
+
+
+

Gaps

+
    + {analysis.dataQuality.gaps.map((item) => ( +
  • {item}
  • + ))} +
+
+
+

Actions

+
    + {analysis.dataQuality.actions.map((item) => ( +
  • {item}
  • + ))} +
+
+ + )} +
+
+
+

Revenue & Risk

+ {analysis.revenueImpact && ( +
+
+

Wins

+
    + {analysis.revenueImpact.wins.map((item) => ( +
  • {item}
  • + ))} +
+
+
+

Leaks

+
    + {analysis.revenueImpact.leaks.map((item) => ( +
  • {item}
  • + ))} +
+
+
+

Plays

+
    + {analysis.revenueImpact.plays.map((item) => ( +
  • {item}
  • + ))} +
+
+
+ )} + {analysis.riskRegister && ( +
+

Risk register

+
    + {analysis.riskRegister.map((item) => ( +
  • {item}
  • + ))} +
+
+ )} + {analysis.aiAutomation && ( +
+

AI automation

+
    + {analysis.aiAutomation.map((item) => ( +
  • {item}
  • + ))} +
+
+ )} + {analysis.executiveSummary && ( +
+

Executive summary

+

{analysis.executiveSummary}

+
+ )} +
+
+ )} + {!loading && !analysis &&

Upload two files to light up the delta visualizer.

} +
+
+ ); +}; diff --git a/client/src/pages/DataManagement.tsx b/client/src/pages/DataManagement.tsx new file mode 100644 index 0000000..5a50b55 --- /dev/null +++ b/client/src/pages/DataManagement.tsx @@ -0,0 +1,114 @@ +import { useState } from 'react'; +import { Database, Sparkles, FileSpreadsheet, FileJson } from 'lucide-react'; +import { GradientCard } from '../components/GradientCard'; +import { UploadDropzone } from '../components/UploadDropzone'; + +interface DataAsset { + name: string; + owner: string; + freshness: string; + coverage: string; +} + +const INITIAL_ASSETS: DataAsset[] = [ + { name: 'Enterprise Pipeline', owner: 'RevOps', freshness: '11m', coverage: 'Global (42 markets)' }, + { name: 'Customer Health Graph', owner: 'Success Ops', freshness: '28m', coverage: 'Net retention tiers' }, + { name: 'Risk Intelligence', owner: 'Legal', freshness: '7m', coverage: 'Compliance, ESG, credit' }, +]; + +export const DataManagement = () => { + const [assets, setAssets] = useState(INITIAL_ASSETS); + + const handleFiles = (files: File[]) => { + const newAssets = files.map((file) => ({ + name: file.name, + owner: 'Upload', + freshness: 'Now', + coverage: `${(file.size / 1024).toFixed(1)} KB`, + })); + setAssets((prev) => [...newAssets, ...prev].slice(0, 8)); + }; + + return ( +
+
+
+

Data Fabric

+

Data management operations

+

+ Centrally orchestrate CRM datasets, align freshness SLAs, and activate AI-grade governance across documents, + telemetry, and intelligence feeds. +

+
+
+

Quality

+

Atlas scoring

+

98.2

+
+
+ +
+ }> + +

+ Files never leave your environment. The Node service streams content securely to your private OpenAI deployment. +

+
+ } emphasis="neon"> +
    +
  • + Schema harmonization complete — 142 dimensions reconciled across CRM + ERP. +
  • +
  • + Risk anomalies flagged in 3 datasets; mitigation workflows triggered. +
  • +
  • + Predictive features enriched with new propensity signals (win, churn, upsell). +
  • +
+
+
+ + }> +
+ {assets.map((asset) => ( +
+

{asset.owner}

+

{asset.name}

+
+ Fresh: {asset.freshness} + {asset.coverage} +
+
+ ))} +
+
+ + }> +
+
+

Highlights

+
    +
  • 30+ data domains aligned to CRM pipeline objects
  • +
  • Automated data quality scoring with trust heatmaps
  • +
  • AI metadata extraction for buyer committees
  • +
+
+
+

Next ingestion

+
    +
  • Payments ledger feed (JSON API)
  • +
  • Partnership telemetry (CSV)
  • +
  • Support transcripts (TXT)
  • +
+
+
+
+
+ ); +}; diff --git a/client/src/pages/Overview.tsx b/client/src/pages/Overview.tsx new file mode 100644 index 0000000..ca36bb2 --- /dev/null +++ b/client/src/pages/Overview.tsx @@ -0,0 +1,72 @@ +import { TrendingUp, Target, Zap, Shield } from 'lucide-react'; +import { MetricCard } from '../components/MetricCard'; +import { GradientCard } from '../components/GradientCard'; +import { VelocityTrend } from '../components/VelocityTrend'; + +const VELOCITY_SAMPLE = [ + { period: 'Q1', value: 62, baseline: 40 }, + { period: 'Q2', value: 74, baseline: 48 }, + { period: 'Q3', value: 83, baseline: 55 }, + { period: 'Q4', value: 95, baseline: 61 }, + { period: 'Q1+1', value: 108, baseline: 67 }, +]; + +export const Overview = () => ( +
+
+
+

Live Telemetry

+

Revenue Intelligence Command

+

+ Visualize how Atlas orchestrates your CRM data fabric. Predictions, risk, AI actions, and collaboration converge inside + a cinematic dashboard built for board-level precision. +

+
+
+

Sync

+

Operational cadence locked

+

Last AI orchestration: 3m ago

+
+
+ +
+ } /> + } accent="success" /> + } /> + } accent="warning" /> +
+ +
+ + +
+
+

Acceleration

+

+22% QoQ

+
+
+

Conversion

+

36% → 48%

+
+
+

AI Leverage

+

17 automations

+
+
+
+ +
    +
  • + Deploy concierge nurture journey for stalled enterprise deals — predicted lift 11%. +
  • +
  • + Spin up red-team review for LATAM compliance exposure flagged in risk center. +
  • +
  • + Align AI forecasting feed with finance ERP baseline; zero drift tolerance. +
  • +
+
+
+
+); diff --git a/client/src/pages/PredictiveStrategy.tsx b/client/src/pages/PredictiveStrategy.tsx new file mode 100644 index 0000000..3bb6c52 --- /dev/null +++ b/client/src/pages/PredictiveStrategy.tsx @@ -0,0 +1,244 @@ +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Loader2, Rocket, LineChart, Flag } from 'lucide-react'; +import { z } from 'zod'; +import { GradientCard } from '../components/GradientCard'; +import { UploadDropzone } from '../components/UploadDropzone'; +import { submitInsightRequest, InsightResponse } from '../lib/api'; + +const scenarioSchema = z.object({ + companyName: z.string().min(2), + industry: z.string().min(2), + planningHorizon: z.string().min(1), + goals: z.string().min(10), + concerns: z.string().min(10), + metrics: z.string().optional(), + customData: z.string().optional(), +}); + +type ScenarioForm = z.infer; + +export const PredictiveStrategy = () => { + const [documents, setDocuments] = useState([]); + const [insights, setInsights] = useState(null); + const [loading, setLoading] = useState(false); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ resolver: zodResolver(scenarioSchema) }); + + const onSubmit = async (data: ScenarioForm) => { + setLoading(true); + const payload = new FormData(); + Object.entries(data).forEach(([key, value]) => value && payload.append(key, value)); + documents.forEach((file) => payload.append('documents', file)); + + try { + const response = await submitInsightRequest(payload); + setInsights(response.data); + } catch (error) { + setInsights({ + prediction: { + headline: 'Atlas could not complete the projection', + confidence: 'Low', + quarterlyOutlook: ['Retry shortly; verify the Node service is running and API key is configured.'], + }, + }); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+

Prediction Studio

+

Scenario forecasting

+

+ Feed Atlas your CRM context, data intelligence, and documents. Receive structured predictions, risk posture, and + AI-driven go-to-market motions in seconds. +

+
+
+

Confidence

+

Adaptive

+

Model: gpt-4.1-mini

+
+
+ +
+
+ }> +
+ + +
+
+ +