Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ dotenv.config({ path: path.resolve(__dirname, '../.env') });

import express, { Request, Response } from 'express';
import cookieParser from 'cookie-parser';
import { PrismaClient } from '@prisma/client';
import { PrismaClient,Prisma } from '@prisma/client';
import { z } from 'zod';
import { AuthService } from './services/auth.service';
import {
Expand All @@ -28,10 +28,14 @@ import { WebSocketService } from './services/websocket.service';
import { TelegramBotService } from './services/telegram-bot.service';
import { TelegramNotificationService } from './services/telegram-notification.service';

console.log("1");
const app = express();
console.log("2");
const prisma = new PrismaClient();
console.log("3");
const PORT = process.env.PORT || 8000;

console.log("4");
app.use((req, res, next) => {
const origin = req.headers.origin;
if (
Expand Down Expand Up @@ -774,7 +778,7 @@ app.get(
const hooks = await prisma.webhookEndpoint.findMany({
where: { userId },
});
const formatted = hooks.map((h) => ({
const formatted = hooks.map((h: (typeof hooks)[number]) => ({
id: h.id,
targetUrl: h.targetUrl,
events: JSON.parse(h.events),
Expand Down Expand Up @@ -1297,7 +1301,7 @@ app.put(
validation.data;

// Run delete-then-create inside a transaction
const updatedRule = await prisma.$transaction(async (tx) => {
const updatedRule = await prisma.$transaction(async (tx:Prisma.TransactionClient) => {
await tx.ruleCondition.deleteMany({ where: { ruleId: id } });
await tx.ruleAction.deleteMany({ where: { ruleId: id } });

Expand Down Expand Up @@ -1411,8 +1415,9 @@ app.get('/api/auth/google', (req: Request, res: Response) => {
});

// Start Server

console.log("Reached app.listen");
const server = app.listen(PORT, () => {
console.log("Server started");
logger.info(`Auth service running on port ${PORT}`);

// Register EventBus fallback handler AFTER server is listening
Expand Down
105 changes: 103 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
Radio,
Bell,
} from 'lucide-react';
import { Modal } from './components/Modal';

const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';

Expand Down Expand Up @@ -77,6 +78,36 @@ const MetricCard: React.FC<MetricCardProps> = ({

// Extracted Dashboard Component to protect via ProtectedRoute
const DashboardContent: React.FC = () => {
const [isDiagnosticOpen, setIsDiagnosticOpen] = useState(false);
const [diagnosticData, setDiagnosticData] = useState<any>(null);
const [loading, setLoading] = useState(false);

const handleDiagnostic = async () => {
try {
setLoading(true);

const response = await fetch(`${API_BASE}/api/health`);

if (!response.ok) {
throw new Error('Failed to fetch diagnostics');
}

const data = await response.json();

setDiagnosticData(data);
setIsDiagnosticOpen(true);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
};

const [isPipelineOpen, setIsPipelineOpen] = useState(false);
const handleRunPipeline = () => {
setIsPipelineOpen(true);
};

const location = useLocation();
const navigate = useNavigate();
const { socket } = useSocket();
Expand Down Expand Up @@ -776,10 +807,16 @@ const DashboardContent: React.FC = () => {
</p>
</div>
<div className="flex items-center gap-3">
<button className="px-4 py-2 text-xs font-semibold rounded-xl bg-white/5 hover:bg-white/10 text-gray-200 border border-white/5 transition-all">
<button
onClick={handleDiagnostic}
className="px-4 py-2 text-xs font-semibold rounded-xl bg-white/5 hover:bg-white/10 text-gray-200 border border-white/5 transition-all"
>
Diagnostics
</button>
<button className="px-4 py-2 text-xs font-semibold rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white flex items-center gap-1.5 transition-all glow-accent">
<button
onClick={handleRunPipeline}
className="px-4 py-2 text-xs font-semibold rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white flex items-center gap-1.5 transition-all glow-accent"
>
<Play size={12} fill="currentColor" />
<span>Run Pipeline</span>
</button>
Expand Down Expand Up @@ -898,6 +935,70 @@ const DashboardContent: React.FC = () => {
</div>
</div>
</div>

<Modal
isOpen={isPipelineOpen}
onClose={() => setIsPipelineOpen(false)}
title="InboxOS Pipeline"
className="max-w-3xl w-full"
>
<div className="space-y-5 text-sm text-gray-300">
<p className="text-gray-400">
This illustrates how an email moves through the InboxOS processing
pipeline.
</p>

{[
{
title: 'Layer 1 — Inbox Ingestion',
description:
'Connects to Gmail, Outlook, or IMAP and converts incoming emails into a standard internal format.',
},
{
title: 'Layer 2 — Intelligence Engine',
description:
'AI classifies the email, determines its importance, extracts entities, deadlines, and action items.',
},
{
title: 'Layer 3 — Decision Engine',
description:
'Rules combined with AI determine what should happen next, such as notifications, tasks, or calendar events.',
},
{
title: 'Layer 4 — Action Engine',
description:
'Executes the selected action, such as creating tasks, sending WhatsApp alerts, or labeling emails.',
},
{
title: 'Layer 5 — Delivery Channels',
description:
'Sends the final output to Slack, Telegram, WhatsApp, the dashboard, or other configured channels.',
},
].map((layer, index) => (
<div
key={index}
className="rounded-xl border border-white/10 bg-white/5 p-4"
>
<div className="font-semibold text-white mb-1">{layer.title}</div>

<div className="text-gray-400 text-xs leading-6">
{layer.description}
</div>
</div>
))}

<div className="rounded-xl border border-indigo-500/20 bg-indigo-500/10 p-4">
<div className="text-indigo-300 font-semibold mb-2">
Pipeline Flow
</div>

<div className="text-xs text-gray-300 break-words">
Raw Email → Inbox Ingestion → Intelligence Engine → Decision
Engine → Action Engine → Delivery Channels
</div>
</div>
</div>
</Modal>
</Layout>
);
};
Expand Down