+ {userName && (
+
+ Hi {userName.split(' ')[0]}, what do you need?
+
+ )}
handleSend(
@@ -545,11 +549,18 @@ export default function CoPilot() {
>
Brief me on my territory
- {[
- 'Who should I call this week?',
- 'Draft an outreach email for Ascension',
- "What's urgent across my accounts?",
- ].map((prompt) => (
+ {(isAdmin
+ ? [
+ 'Draft my weekly digest',
+ "What's urgent across all accounts?",
+ 'Which AEs need a follow-up this week?',
+ ]
+ : [
+ 'Who should I call this week?',
+ 'Summarize my most important account',
+ "What's urgent across my accounts?",
+ ]
+ ).map((prompt) => (
handleSend(prompt)}
From a906b77ce4cbf0f7d425fec98c5f42756e7d965c Mon Sep 17 00:00:00 2001
From: Juan Franco <91078895+m1lestones@users.noreply.github.com>
Date: Mon, 22 Jun 2026 20:43:45 -0400
Subject: [PATCH 2/4] fix: deduplicate signal feed by source_url on frontend
---
apps/web/src/app/page.tsx | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index 504c8f2..a29c3a8 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -29,9 +29,15 @@ export default async function HomePage({ searchParams }: PageProps) {
const hospitalMap = Object.fromEntries(hospitals.map((h) => [h.id, h.name]));
// Strip garbage — filtered_out signals should never appear in the feed
- const cleanSignals = allSignals.filter(
- (s) => s.tier !== 'filtered_out' && s.signal_type !== 'filtered_out'
- );
+ const seenUrls = new Set();
+ const cleanSignals = allSignals.filter((s) => {
+ if (s.tier === 'filtered_out' || s.signal_type === 'filtered_out') return false;
+ if (s.source_url) {
+ if (seenUrls.has(s.source_url)) return false;
+ seenUrls.add(s.source_url);
+ }
+ return true;
+ });
// Filter by category
let signals = category
From 8b07c89d2602404a36b6c724fe7db3b279a3d746 Mon Sep 17 00:00:00 2001
From: Juan Franco <91078895+m1lestones@users.noreply.github.com>
Date: Mon, 22 Jun 2026 22:26:27 -0400
Subject: [PATCH 3/4] fix: capitalize Review Queue heading
---
apps/web/src/app/review/page.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/web/src/app/review/page.tsx b/apps/web/src/app/review/page.tsx
index 877eacb..9ba237a 100644
--- a/apps/web/src/app/review/page.tsx
+++ b/apps/web/src/app/review/page.tsx
@@ -20,7 +20,7 @@ export default async function ReviewPage() {
return (
- Review queue
+ Review Queue
Low-confidence signals (under 70%) awaiting Danielle's approval before digest.
{signals.length > 0 && (
From b497a5c77e6fcb950125ce78543de7ce95345bed Mon Sep 17 00:00:00 2001
From: Juan Franco <91078895+m1lestones@users.noreply.github.com>
Date: Mon, 29 Jun 2026 13:42:26 -0400
Subject: [PATCH 4/4] feat: add password wall and login page
---
apps/web/src/app/api/login/route.ts | 22 +++++++
apps/web/src/app/layout.tsx | 19 +-----
apps/web/src/app/login/page.tsx | 81 ++++++++++++++++++++++++++
apps/web/src/components/ShellGuard.tsx | 36 ++++++++++++
apps/web/src/middleware.ts | 26 +++++++++
5 files changed, 167 insertions(+), 17 deletions(-)
create mode 100644 apps/web/src/app/api/login/route.ts
create mode 100644 apps/web/src/app/login/page.tsx
create mode 100644 apps/web/src/components/ShellGuard.tsx
create mode 100644 apps/web/src/middleware.ts
diff --git a/apps/web/src/app/api/login/route.ts b/apps/web/src/app/api/login/route.ts
new file mode 100644
index 0000000..916a3d5
--- /dev/null
+++ b/apps/web/src/app/api/login/route.ts
@@ -0,0 +1,22 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+const PASSWORD = 'adonis2026';
+const COOKIE_NAME = 'adonis_auth';
+
+export async function POST(req: NextRequest) {
+ const { password } = await req.json();
+
+ if (password !== PASSWORD) {
+ return NextResponse.json({ error: 'Incorrect password' }, { status: 401 });
+ }
+
+ const res = NextResponse.json({ ok: true });
+ res.cookies.set(COOKIE_NAME, PASSWORD, {
+ httpOnly: true,
+ secure: process.env.NODE_ENV === 'production',
+ sameSite: 'lax',
+ maxAge: 60 * 60 * 24 * 30, // 30 days
+ path: '/',
+ });
+ return res;
+}
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
index 9962c9a..ad3ea82 100644
--- a/apps/web/src/app/layout.tsx
+++ b/apps/web/src/app/layout.tsx
@@ -1,12 +1,8 @@
import './globals.css';
-import { Suspense } from 'react';
import type { Metadata } from 'next';
import Nav from '@/components/Nav';
-import CoPilot from '@/components/CoPilot';
-import MobileNav from '@/components/MobileNav';
-import DigestTracker from '@/components/DigestTracker';
-import UserProvider from '@/components/UserProvider';
import SidebarUser from '@/components/SidebarUser';
+import ShellGuard from '@/components/ShellGuard';
export const metadata: Metadata = {
title: 'Adonis Account Intelligence',
@@ -17,18 +13,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
return (
- {/* Mobile top bar */}
-
-
-
-
- {children}
-
-
-
-
-
-
+ }>{children}
);
diff --git a/apps/web/src/app/login/page.tsx b/apps/web/src/app/login/page.tsx
new file mode 100644
index 0000000..2782a32
--- /dev/null
+++ b/apps/web/src/app/login/page.tsx
@@ -0,0 +1,81 @@
+'use client';
+
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+
+export default function LoginPage() {
+ const [password, setPassword] = useState('');
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false);
+ const router = useRouter();
+
+ async function handleSubmit(e: React.FormEvent) {
+ e.preventDefault();
+ setLoading(true);
+ setError('');
+
+ const res = await fetch('/api/login', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ password }),
+ });
+
+ if (res.ok) {
+ router.push('/');
+ router.refresh();
+ } else {
+ setError('Incorrect password.');
+ setLoading(false);
+ }
+ }
+
+ return (
+
+
+
+
+ Account Intel
+
+
+ for Adonis · Healthcare Revenue-Cycle Software
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/ShellGuard.tsx b/apps/web/src/components/ShellGuard.tsx
new file mode 100644
index 0000000..a322bea
--- /dev/null
+++ b/apps/web/src/components/ShellGuard.tsx
@@ -0,0 +1,36 @@
+'use client';
+
+import { usePathname } from 'next/navigation';
+import { Suspense } from 'react';
+import CoPilot from '@/components/CoPilot';
+import MobileNav from '@/components/MobileNav';
+import DigestTracker from '@/components/DigestTracker';
+import UserProvider from '@/components/UserProvider';
+
+export default function ShellGuard({
+ children,
+ sidebar,
+}: {
+ children: React.ReactNode;
+ sidebar: React.ReactNode;
+}) {
+ const pathname = usePathname();
+
+ if (pathname === '/login') {
+ return <>{children}>;
+ }
+
+ return (
+
+
+
+ {sidebar}
+ {children}
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts
new file mode 100644
index 0000000..60b176b
--- /dev/null
+++ b/apps/web/src/middleware.ts
@@ -0,0 +1,26 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+const PASSWORD = 'adonis2026';
+const COOKIE_NAME = 'adonis_auth';
+
+export function middleware(req: NextRequest) {
+ const { pathname } = req.nextUrl;
+
+ // Allow login page and its API route through
+ if (pathname === '/login' || pathname === '/api/login') {
+ return NextResponse.next();
+ }
+
+ const cookie = req.cookies.get(COOKIE_NAME);
+ if (cookie?.value === PASSWORD) {
+ return NextResponse.next();
+ }
+
+ const loginUrl = req.nextUrl.clone();
+ loginUrl.pathname = '/login';
+ return NextResponse.redirect(loginUrl);
+}
+
+export const config = {
+ matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
+};