From fc5a761626c2df2f5173857c4d8992d4d4a007e2 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Mon, 16 Feb 2026 16:52:52 -0700 Subject: [PATCH 1/3] chore: setup dev environment, fix auth bypass, and fix hydration errors --- README.md | 97 ++++++++++++++++--- drizzle/{ => seeds}/seed-users.sql | 0 drizzle/{ => seeds}/seed.sql | 0 src/components/nav-user.tsx | 91 +++++++++--------- src/components/org-switcher.tsx | 144 +++++++++++++++-------------- src/middleware.ts | 14 ++- wrangler.jsonc | 2 +- 7 files changed, 216 insertions(+), 132 deletions(-) rename drizzle/{ => seeds}/seed-users.sql (100%) rename drizzle/{ => seeds}/seed.sql (100%) diff --git a/README.md b/README.md index 482ea95..434152c 100755 --- a/README.md +++ b/README.md @@ -4,32 +4,99 @@ An AI-native workspace platform that handles auth, deployment, and real-time collaboration -- so you can focus on building what actually matters. -## Build With Direction :) +## 🛠️ Development Setup -- **AI agent built in** -- every workspace ships with an intelligent - assistant that understands your domain and takes action through - tools you define -- **Modular by design** -- scheduling, financials, file management, - messaging. drop in what you need, leave out what you don't -- **Deploy anywhere** -- self-host, ship to desktop and mobile, - or deploy to the edge with Cloudflare -- **Enterprise auth** -- SSO, directory sync, and role-based access - control out of the box +Follow these steps to set up your local environment. -## Quick Start +### 1. Initial Setup + +Clone the repository and install dependencies: ```bash git clone https://github.com/High-Performance-Structures/compass.git cd compass bun install -cp .env.example .env.local # add your keys -bun run db:generate +``` + +### 2. Environment Variables + +Create `.env.local` and `.dev.vars` in the root directory. + +**`.env.local`** (Local Development): +```ini +# Bypass all auth for local development +BYPASS_AUTH=true + +# WorkOS (Use placeholder values to trigger mock mode) +WORKOS_API_KEY=placeholder_development_mode +WORKOS_CLIENT_ID=placeholder_development_mode +WORKOS_COOKIE_PASSWORD=your_cookie_password_here +NEXT_PUBLIC_WORKOS_REDIRECT_URI=http://localhost:3000/callback + +# AI Agent +OPENROUTER_API_KEY=your_openrouter_key +``` + +**`.dev.vars`** (Cloudflare Worker Environment): +```ini +# Add any required secret keys here +WORKOS_API_KEY=your_real_key_if_needed +``` + +### 3. Database Setup + +Initialize the local D1 database, run migrations, and seed mock data: + +```bash +# 1. Clear any existing local state +rm -rf .wrangler + +# 2. Run migrations (schema setup) bun run db:migrate:local + +# 3. Seed data (Users & Projects) +# Finds the local SQLite file and runs the seed scripts +DB_FILE=$(find .wrangler/state/v3/d1 -name "*.sqlite" | head -1) && \ +sqlite3 "$DB_FILE" ".read drizzle/seeds/seed-users.sql" && \ +sqlite3 "$DB_FILE" ".read drizzle/seeds/seed.sql" + +# 4. Insert mock Dev User (if not in seed) +sqlite3 "$DB_FILE" "INSERT OR IGNORE INTO users (id, email, first_name, last_name, display_name, role, is_active, created_at, updated_at) VALUES ('dev-user-1', 'dev@compass.io', 'Dev', 'User', 'Dev User', 'admin', 1, datetime('now'), datetime('now'));" +``` + +### 4. Running the App + +Start the development server: + +```bash bun dev ``` -See [docs/](docs/README.md) for detailed setup, environment -variables, and deployment options. +- Open **[http://localhost:3000](http://localhost:3000)** +- You will be automatically redirected to `/dashboard` as the **Dev User**. + +--- + +## 📐 Development Guidelines + +### 1. Pulling Changes +Always pull the latest changes before starting work to avoid conflicts: +```bash +git pull origin main +bun install +bun run db:migrate:local +``` + +### 2. Styling (CSS) +- **Do NOT use hardcoded CSS** (e.g., `style={{ width: '500px' }}`). +- Use **Tailwind CSS classes** (e.g., `w-[500px]` or `w-full max-w-lg`). +- Follow the design system tokens in `tailwind.config.ts`. + +### 3. Git Ignore +- Check `.gitignore` before adding new files. +- Never commit `.env` files or local database artifacts (`.wrangler/`). + +--- ## Tech Stack diff --git a/drizzle/seed-users.sql b/drizzle/seeds/seed-users.sql similarity index 100% rename from drizzle/seed-users.sql rename to drizzle/seeds/seed-users.sql diff --git a/drizzle/seed.sql b/drizzle/seeds/seed.sql similarity index 100% rename from drizzle/seed.sql rename to drizzle/seeds/seed.sql diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx index dfaf34a..681e983 100755 --- a/src/components/nav-user.tsx +++ b/src/components/nav-user.tsx @@ -92,51 +92,54 @@ export function NavUser({ - - {user.avatar && ( - - )} - - {initials} - - - - {user.name} - - {/* Voice controls -- replace the old dots icon */} -
- { stopEvent(e); toggleMute() }} - icon={isMuted ? IconMicrophoneOff : IconMicrophone} - label={isMuted ? "Unmute" : "Mute"} - dimmed={isMuted} - devices={inputDevices} - selectedDeviceId={inputDeviceId} - onSelectDevice={setInputDevice} - deviceLabel="Input Device" - /> - { stopEvent(e); toggleDeafen() }} - icon={isDeafened ? IconHeadphonesOff : IconHeadphones} - label={isDeafened ? "Undeafen" : "Deafen"} - dimmed={isDeafened} - devices={outputDevices} - selectedDeviceId={outputDeviceId} - onSelectDevice={setOutputDevice} - deviceLabel="Output Device" - /> - - - +
+ + {user.avatar && ( + + )} + + {initials} + + + + {user.name} + + {/* Voice controls -- replace the old dots icon */} +
+ { stopEvent(e); toggleMute() }} + icon={isMuted ? IconMicrophoneOff : IconMicrophone} + label={isMuted ? "Unmute" : "Mute"} + dimmed={isMuted} + devices={inputDevices} + selectedDeviceId={inputDeviceId} + onSelectDevice={setInputDevice} + deviceLabel="Input Device" + /> + { stopEvent(e); toggleDeafen() }} + icon={isDeafened ? IconHeadphonesOff : IconHeadphones} + label={isDeafened ? "Undeafen" : "Deafen"} + dimmed={isDeafened} + devices={outputDevices} + selectedDeviceId={outputDeviceId} + onSelectDevice={setOutputDevice} + deviceLabel="Output Device" + /> + + + +
diff --git a/src/components/org-switcher.tsx b/src/components/org-switcher.tsx index ce2cc90..d884f27 100644 --- a/src/components/org-switcher.tsx +++ b/src/components/org-switcher.tsx @@ -80,80 +80,82 @@ export function OrgSwitcher({ - - - - - - - - + - {orgs.map((org, i) => { - const isActive = org.id === activeOrgId - const OrgIcon = - org.type === "personal" ? IconUser : IconBuilding + + + + + + + + {orgs.map((org, i) => { + const isActive = org.id === activeOrgId + const OrgIcon = + org.type === "personal" ? IconUser : IconBuilding - return ( - - {i > 0 && } - void handleOrgSwitch(org.id)} - disabled={isLoading} - className="gap-2 px-2 py-1.5" - > - - - {org.name} - - {isActive && ( - - )} - - - ) - })} - - + return ( + + {i > 0 && } + void handleOrgSwitch(org.id)} + disabled={isLoading} + className="gap-2 px-2 py-1.5" + > + + + {org.name} + + {isActive && ( + + )} + + + ) + })} + + +
diff --git a/src/middleware.ts b/src/middleware.ts index c45a86a..36ea4bb 100755 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,4 +1,4 @@ -import { NextRequest } from "next/server" +import { NextRequest, NextResponse } from "next/server" import { authkit, handleAuthkitHeaders } from "@workos-inc/authkit-nextjs" // public routes that don't require authentication @@ -33,6 +33,18 @@ function isPublicPath(pathname: string): boolean { export default async function middleware(request: NextRequest) { const { pathname } = request.nextUrl + // ── dev bypass: skip all auth when BYPASS_AUTH=true ── + // getCurrentUser() in lib/auth.ts returns a mock admin user + // when WorkOS keys contain "placeholder", so server actions + // and page data loaders still work without a real session. + if (process.env.BYPASS_AUTH === "true") { + // redirect landing page straight to dashboard for convenience + if (pathname === "/" || pathname === "/login" || pathname === "/signup") { + return NextResponse.redirect(new URL("/dashboard", request.url)) + } + return NextResponse.next() + } + // get session and headers from authkit (handles token refresh automatically) const { session, headers } = await authkit(request) diff --git a/wrangler.jsonc b/wrangler.jsonc index fb7ecbe..6edde93 100755 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -5,7 +5,7 @@ { "$schema": "node_modules/wrangler/config-schema.json", "name": "compass", - "account_id": "8716137c706ea3d5c209b330084fa9e2", + // "account_id": "8716137c706ea3d5c209b330084fa9e2", "main": ".open-next/worker.js", "compatibility_date": "2025-12-01", "compatibility_flags": [ From 763fdaeec8ffba269da186bccc400f0df8b95152 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Mon, 16 Feb 2026 16:58:11 -0700 Subject: [PATCH 2/3] feat: enable global chat toggle, remove old feedback widget, and improve mobile/desktop responsiveness --- src/app/dashboard/layout.tsx | 110 +++++++++++----------- src/components/agent/chat-panel-shell.tsx | 38 +++++--- 2 files changed, 77 insertions(+), 71 deletions(-) diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index 63a407a..e435e8c 100755 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -5,7 +5,7 @@ import { SiteHeader } from "@/components/site-header" import { MobileBottomNav } from "@/components/mobile-bottom-nav" import { CommandMenuProvider } from "@/components/command-menu-provider" import { SettingsProvider } from "@/components/settings-provider" -import { FeedbackWidget } from "@/components/feedback-widget" + import { PageActionsProvider } from "@/components/page-actions-provider" import { DashboardContextMenu } from "@/components/dashboard-context-menu" import { Toaster } from "@/components/ui/sonner" @@ -54,61 +54,59 @@ export default async function DashboardLayout({ return ( - - - - - - - - - - - - - - - - -
- - {children} - - -
-
- - - -

- Pre-alpha build -

- -
-
-
-
-
-
-
-
-
-
+ + + + + + + + + + + + + + + +
+ + {children} + + +
+
+ + + +

+ Pre-alpha build +

+ +
+
+
+
+
+
+
+
+
) } diff --git a/src/components/agent/chat-panel-shell.tsx b/src/components/agent/chat-panel-shell.tsx index 07539a7..031869f 100755 --- a/src/components/agent/chat-panel-shell.tsx +++ b/src/components/agent/chat-panel-shell.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useCallback } from "react" import { usePathname } from "next/navigation" -import { MessageSquare } from "lucide-react" +import { MessageSquare, XIcon } from "lucide-react" import { Button } from "@/components/ui/button" import { cn } from "@/lib/utils" import { @@ -148,16 +148,16 @@ export function ChatPanelShell() { isDashboard ? "flex-1 bg-background" : [ - "bg-background dark:bg-[oklch(0.255_0_0)]", - "fixed inset-0 z-50", - "md:relative md:inset-auto md:z-auto", - "md:shrink-0 md:overflow-hidden", - "md:rounded-xl md:border md:border-border md:shadow-lg md:my-2 md:mr-2", - isResizing && "transition-none", - isOpen - ? "translate-x-0 md:opacity-100" - : "translate-x-full md:translate-x-0 md:w-0 md:border-transparent md:shadow-none md:opacity-0", - ] + "bg-background dark:bg-[oklch(0.255_0_0)]", + "fixed inset-0 z-50", + "md:relative md:inset-auto md:z-auto", + "md:shrink-0 md:overflow-hidden", + "md:rounded-xl md:border md:border-border md:shadow-lg md:my-2 md:mr-2", + isResizing && "transition-none", + isOpen + ? "translate-x-0 md:opacity-100" + : "translate-x-full md:translate-x-0 md:w-0 md:border-transparent md:shadow-none md:opacity-0", + ] )} style={{ ...panelStyle, ...keyboardStyle }} > @@ -184,14 +184,22 @@ export function ChatPanelShell() { )} {/* Mobile FAB (panel mode only) */} - {!isDashboard && !isOpen && ( + {/* Chat Toggle FAB (visible on specific pages) */} + {!isDashboard && ( )} From dd06d0b54cb1ac7b5aa1b78a9bf7e5c228eb0435 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Mon, 16 Feb 2026 17:33:52 -0700 Subject: [PATCH 3/3] fix(chat): Layout, Navigation, and FAB Improvements - Resolved layout issues on Dashboard and Panel views (Cutoff, Overlap). - Implemented Z-Index fixes for Dropdowns (z-100) and Panel (z-60). - Updated FAB with Compass brand icon and seeking animation. - Implemented Contextual Back Button in Header to reset Active Dashboard Chat. - Corrected Dashboard padding to respect Mobile Bottom Nav. --- src/components/agent/chat-panel-shell.tsx | 65 ++++++++++++++++++----- src/components/site-header.tsx | 27 ++++++++-- src/components/ui/dropdown-menu.tsx | 4 +- src/components/ui/popover.tsx | 2 +- src/components/ui/tooltip.tsx | 4 +- 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/components/agent/chat-panel-shell.tsx b/src/components/agent/chat-panel-shell.tsx index 031869f..0a36806 100755 --- a/src/components/agent/chat-panel-shell.tsx +++ b/src/components/agent/chat-panel-shell.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useCallback } from "react" import { usePathname } from "next/navigation" -import { MessageSquare, XIcon } from "lucide-react" +import { XIcon, ChevronLeft } from "lucide-react" import { Button } from "@/components/ui/button" import { cn } from "@/lib/utils" import { @@ -131,7 +131,7 @@ export function ChatPanelShell() { // container width/style for panel mode const panelStyle = !isDashboard && isOpen - ? { width: panelWidth } + ? ({ "--panel-width": `${panelWidth}px` } as React.CSSProperties) : undefined const keyboardStyle = @@ -146,11 +146,13 @@ export function ChatPanelShell() { "flex flex-col", "transition-[flex,width,border-color,box-shadow,opacity,transform] duration-300 ease-in-out", isDashboard - ? "flex-1 bg-background" + ? "flex-1 bg-background pb-[calc(3.5rem+env(safe-area-inset-bottom))] md:pb-0" : [ "bg-background dark:bg-[oklch(0.255_0_0)]", - "fixed inset-0 z-50", - "md:relative md:inset-auto md:z-auto", + "fixed inset-0 z-[60]", + "pb-[env(safe-area-inset-bottom)]", + "w-full md:w-[var(--panel-width)]", // Use CSS var for responsive width + "md:relative md:inset-auto md:z-auto md:pb-0", "md:shrink-0 md:overflow-hidden", "md:rounded-xl md:border md:border-border md:shadow-lg md:my-2 md:mr-2", isResizing && "transition-none", @@ -161,6 +163,24 @@ export function ChatPanelShell() { )} style={{ ...panelStyle, ...keyboardStyle }} > + {/* Header with Back/Close Button */} + {!isDashboard && isOpen && ( +
+ +
+ )} + {/* Desktop resize handle (panel mode only) */} {!isDashboard && (
)} - + {isDashboard ? ( + + ) : ( +
+ +
+ )}
{/* Mobile backdrop (panel mode only) */} @@ -187,10 +211,11 @@ export function ChatPanelShell() { {/* Chat Toggle FAB (visible on specific pages) */} {!isDashboard && ( )} diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index 566d5f5..bdcabb2 100755 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -5,7 +5,6 @@ import { useTheme } from "next-themes" import { IconLogout, IconMenu2, - IconMessageCircle, IconMoon, IconSearch, IconSparkles, @@ -28,7 +27,9 @@ import { import { SidebarTrigger, useSidebar } from "@/components/ui/sidebar" import { NotificationsPopover } from "@/components/notifications-popover" import { useCommandMenu } from "@/components/command-menu-provider" -import { useAgentOptional } from "@/components/agent/chat-provider" +import { useAgentOptional, useChatState, useRenderState } from "@/components/agent/chat-provider" +import { usePathname } from "next/navigation" +import { ChevronLeft } from "lucide-react" import { AccountModal } from "@/components/account-modal" import { getInitials } from "@/lib/utils" import type { SidebarUser } from "@/lib/auth" @@ -45,6 +46,14 @@ export function SiteHeader({ const agentContext = useAgentOptional() const [accountOpen, setAccountOpen] = React.useState(false) const { toggleSidebar } = useSidebar() + const pathname = usePathname() + const agentState = useChatState() + const renderState = useRenderState() + + // Determine if we are on the main dashboard chat view with active messages + // In this state, we replace the sidebar toggle with a "Back" button to reset the chat + const hasRenderedUI = !!renderState.spec?.root || renderState.isRendering + const isDashboardChatActive = pathname === "/dashboard" && !hasRenderedUI && agentState.messages.length > 0 const initials = user ? getInitials(user.name) : "?" @@ -61,11 +70,19 @@ export function SiteHeader({ type="button" className="flex size-10 shrink-0 items-center justify-center rounded-full -ml-0.5 hover:bg-background/60" onClick={() => { - toggleSidebar() + if (isDashboardChatActive) { + agentState.newChat() + } else { + toggleSidebar() + } }} - aria-label="Open menu" + aria-label={isDashboardChatActive ? "Back to new chat" : "Open menu"} > - + {isDashboardChatActive ? ( + + ) : ( + + )}