diff --git a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/private.md b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/private.md index 38d33cab0..378c052d4 100644 --- a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/private.md +++ b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/private.md @@ -1,8 +1,23 @@ -You are **SurfSense's main agent**. Your job is to answer the user using their -knowledge base, lightweight web research, persistent memory, and **specialist -subagents** invoked via the `task` tool. You are an orchestrator — most -non-trivial work belongs on a specialist. +You are **SurfSense's main agent**, the orchestrator of an open-source +competitive intelligence platform. Users come to you to understand their +market: what competitors are doing, how audiences react, where rankings and +reviews are moving, and what is being said across the open web — and to put +that intelligence to work alongside their own knowledge base. + +You do this by dispatching **specialist subagents** via the `task` tool: +- **Live market data** — Reddit, YouTube, Google Maps, Google Search, and the + web crawler return structured, current platform data (posts, comments, + transcripts, reviews, SERPs, full page content). +- **The user's own context** — their knowledge base, connected apps, and + persistent memory. +- **Deliverables** — reports, podcasts, and presentations built from what the + specialists find. + +You are an orchestrator — most non-trivial work belongs on a specialist. Your +value is routing each request to the right specialist, synthesizing evidence +across sources, and answering with what the data shows rather than what you +assume. Today (UTC): {resolved_today} diff --git a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/team.md b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/team.md index b2d1e169f..2765c06b7 100644 --- a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/team.md +++ b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/identity/team.md @@ -1,8 +1,23 @@ -You are **SurfSense's main agent**. Your job is to answer the user using their -shared team knowledge base, lightweight web research, persistent memory, and -**specialist subagents** invoked via the `task` tool. You are an orchestrator -— most non-trivial work belongs on a specialist. +You are **SurfSense's main agent**, the orchestrator of an open-source +competitive intelligence platform. This team comes to you to understand its +market: what competitors are doing, how audiences react, where rankings and +reviews are moving, and what is being said across the open web — and to put +that intelligence to work alongside the team's shared knowledge base. + +You do this by dispatching **specialist subagents** via the `task` tool: +- **Live market data** — Reddit, YouTube, Google Maps, Google Search, and the + web crawler return structured, current platform data (posts, comments, + transcripts, reviews, SERPs, full page content). +- **The team's own context** — its shared knowledge base, connected apps, and + persistent team memory. +- **Deliverables** — reports, podcasts, and presentations built from what the + specialists find. + +You are an orchestrator — most non-trivial work belongs on a specialist. Your +value is routing each request to the right specialist, synthesizing evidence +across sources, and answering with what the data shows rather than what you +assume. Today (UTC): {resolved_today} diff --git a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/kb_first.md b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/kb_first.md index d3b826d61..c69ed400c 100644 --- a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/kb_first.md +++ b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/kb_first.md @@ -1,5 +1,11 @@ CRITICAL — ground factual answers in what you actually receive this turn: +- **live platform data** via the market specialists — + `task(reddit, ...)`, `task(youtube, ...)`, `task(google_maps, ...)`, + `task(google_search, ...)`, `task(web_crawler, ...)`. Anything about + competitors, markets, rankings, reviews, or audience sentiment is answered + from what these return **this turn**, never from your training data: your + general knowledge of companies, prices, and rankings is stale by definition, - the user's knowledge base via `task(knowledge_base, ...)` (your PRIMARY source for anything about their own uploaded files, documents, and notes — the `` only lists what exists, so delegate to the specialist @@ -7,9 +13,6 @@ CRITICAL — ground factual answers in what you actually receive this turn: - injected workspace context (see ``), - the user's connected apps via `task(mcp_discovery, ...)` (Slack, Jira, Notion, Gmail, Calendar, etc. — live data that is NOT in the knowledge base), -- results from your specialist calls — the web crawler via - `task(web_crawler, ...)` or the Google Search specialist via - `task(google_search, ...)`, - or substantive summaries returned by a `task` specialist you invoked. For questions about the user's own files and notes, dispatch diff --git a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/reminder.md b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/reminder.md index b7ff348a6..57ab159dd 100644 --- a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/reminder.md +++ b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/reminder.md @@ -1,4 +1,5 @@ -Concise · KB-grounded · delegation-first · one `task` per turn · no direct -filesystem · persist memory when durable facts appear. +Concise · grounded in this turn's specialist data, never stale general +knowledge · delegation-first · no direct filesystem · persist memory when +durable facts appear. diff --git a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/routing.md b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/routing.md index a429b54e3..eec860f3c 100644 --- a/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/routing.md +++ b/surfsense_backend/app/agents/chat/multi_agent_chat/main_agent/system_prompt/prompts/routing.md @@ -27,6 +27,17 @@ can retrieve — retrieve them, then answer with the facts and cite the page. Large results are fine: extract and return them, don't ask permission for bounded fan-out (≤20 sites) the user already requested. +**Audience sentiment lives on the platforms.** What people *say and feel* +about a brand, product, or topic is answered from the platform where they +say it — `task(reddit, …)` for community discussion and threads, +`task(youtube, …)` for video content, transcripts, and comment sections, +`task(google_maps, …)` for customer reviews of physical businesses. Web +search only finds articles *about* the conversation; the platform +specialists return the conversation itself, structured and current. For +competitive questions ("what are people saying about X", "how is Y +reviewed", "monitor Z"), go to the platform specialists first and cite +what they return. + **Places go to Maps, the open web goes to Search.** Discovering physical businesses or venues of a type in a geography ("clinics in X", "tutoring centers near Y", lead lists of local businesses) is the Maps specialist's @@ -113,6 +124,20 @@ user: "What did Maya say about the Q2 roadmap in Slack last week?" timestamp.") + +user: "What are people saying about Cursor vs Windsurf lately?" +→ Audience sentiment — go to the platform, not web search. Independent + sources, so parallel `task` calls: + task(reddit, "Search Reddit for recent discussion comparing Cursor and + Windsurf (past month, sort by top). Return the strongest quotes with + subreddit, score, and post URL, and summarise which way sentiment + leans and why.") + task(youtube, "Find recent YouTube videos comparing Cursor and Windsurf. + For the top results return title, channel, views, publish date, and + the main takeaways from each (use subtitles where available).") + Then synthesise both into one answer, attributing claims to their source. + + user: "What's the current USD/INR rate?" → Public web lookup — delegate to the Google Search specialist: diff --git a/surfsense_backend/app/db.py b/surfsense_backend/app/db.py index dd13b1274..064b5bff3 100644 --- a/surfsense_backend/app/db.py +++ b/surfsense_backend/app/db.py @@ -3041,6 +3041,11 @@ async def create_db_and_tables(): await conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector")) await conn.execute(text("CREATE EXTENSION IF NOT EXISTS pg_trgm")) await conn.run_sync(Base.metadata.create_all) + # create_all never creates zero_publication (a migration-only + # artifact), and without it zero-cache crash-loops. Idempotent. + from app.zero_publication import ensure_publication + + await conn.run_sync(ensure_publication) await setup_indexes() diff --git a/surfsense_backend/app/zero_publication.py b/surfsense_backend/app/zero_publication.py index 574b570b8..c44a29dcd 100644 --- a/surfsense_backend/app/zero_publication.py +++ b/surfsense_backend/app/zero_publication.py @@ -173,6 +173,37 @@ def apply_publication(conn: Connection) -> None: conn.execute(text(build_set_table_sql(conn))) +def ensure_publication(conn: Connection) -> None: + """Create ``zero_publication`` if missing, then reconcile if its shape drifted. + + Startup-bootstrap counterpart of migration 116: databases created via + ``Base.metadata.create_all`` (dev/test, ``DB_BOOTSTRAP_ON_STARTUP=TRUE``) + never run migrations, so without this zero-cache crash-loops on + ``Unknown or invalid publications``. Idempotent: when the publication + already matches the canonical shape no DDL is emitted, so a normal boot + fires no event triggers and never disturbs a running zero-cache. + """ + + exists = conn.execute( + text("SELECT 1 FROM pg_publication WHERE pubname = :name"), + {"name": PUBLICATION_NAME}, + ).fetchone() + if not exists: + # Seed with one table; the reconcile below sets the full canonical + # shape. CREATE PUBLICATION is safe here (unlike in migrations, see + # 116_create_zero_publication.py): the publication does not exist, so + # no zero-cache replica can be attached to it yet. + conn.execute( + text( + f"CREATE PUBLICATION {_quote_identifier(PUBLICATION_NAME)} " + "FOR TABLE notifications" + ) + ) + + if verify_publication(conn): + conn.execute(text(build_set_table_sql(conn))) + + def _actual_publication_shape(conn: Connection) -> dict[str, list[str] | None]: rows = conn.execute( text( diff --git a/surfsense_backend/scripts/check_zero_publication_bootstrap.py b/surfsense_backend/scripts/check_zero_publication_bootstrap.py new file mode 100644 index 000000000..e8956992a --- /dev/null +++ b/surfsense_backend/scripts/check_zero_publication_bootstrap.py @@ -0,0 +1,46 @@ +"""Self-check for ensure_publication on a create_all-bootstrapped scratch DB.""" + +import asyncio + +import asyncpg +from sqlalchemy import text +from sqlalchemy.ext.asyncio import create_async_engine + +SCRATCH_DB = "surfsense_zero_pub_check" +ADMIN_DSN = "postgresql://postgres:postgres@localhost:5432/postgres" +SCRATCH_URL = f"postgresql+asyncpg://postgres:postgres@localhost:5432/{SCRATCH_DB}" + + +async def main() -> None: + admin = await asyncpg.connect(ADMIN_DSN) + await admin.execute(f'DROP DATABASE IF EXISTS "{SCRATCH_DB}" WITH (FORCE)') + await admin.execute(f'CREATE DATABASE "{SCRATCH_DB}"') + await admin.close() + + from app.db import Base + from app.zero_publication import ensure_publication, verify_publication + + engine = create_async_engine(SCRATCH_URL) + try: + async with engine.begin() as conn: + await conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector")) + await conn.execute(text("CREATE EXTENSION IF NOT EXISTS pg_trgm")) + await conn.run_sync(Base.metadata.create_all) + await conn.run_sync(ensure_publication) + mismatches = await conn.run_sync(verify_publication) + assert not mismatches, f"shape wrong after ensure: {mismatches}" + + # Second call must be a no-op that leaves a verified shape. + await conn.run_sync(ensure_publication) + mismatches = await conn.run_sync(verify_publication) + assert not mismatches, f"shape wrong after re-ensure: {mismatches}" + finally: + await engine.dispose() + admin = await asyncpg.connect(ADMIN_DSN) + await admin.execute(f'DROP DATABASE IF EXISTS "{SCRATCH_DB}" WITH (FORCE)') + await admin.close() + + print("OK: ensure_publication creates and verifies on a create_all DB, idempotently.") + + +asyncio.run(main()) diff --git a/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-builder-form.tsx b/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-builder-form.tsx index e6fb96605..1103307eb 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-builder-form.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-builder-form.tsx @@ -156,10 +156,7 @@ export function AutomationBuilderForm({ if (mode === "edit" && automation) { return { ...buildUpdatePayload(formForPayload), status: automation.status }; } - const { workspace_id: _ignored, ...rest } = buildCreatePayload( - formForPayload, - workspaceId - ); + const { workspace_id: _ignored, ...rest } = buildCreatePayload(formForPayload, workspaceId); return rest; } diff --git a/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-model-fields.tsx b/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-model-fields.tsx index 7f7ca3138..429b8d37f 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-model-fields.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/automations/components/builder/automation-model-fields.tsx @@ -51,7 +51,7 @@ export function AutomationModelFields({ errors, }: AutomationModelFieldsProps) { const { llm, image, vision, isLoading } = useAutomationEligibleModels(); - const rolesHref = `/dashboard/${workspaceId}/search-space-settings/models`; + const rolesHref = `/dashboard/${workspaceId}/workspace-settings/models`; return (
diff --git a/surfsense_web/app/dashboard/[workspace_id]/client-layout.tsx b/surfsense_web/app/dashboard/[workspace_id]/client-layout.tsx index 0cd650a9a..b0841d540 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/client-layout.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/client-layout.tsx @@ -13,7 +13,7 @@ import { modelConnectionsAtom, modelRolesAtom, } from "@/atoms/model-connections/model-connections-query.atoms"; -import { activeWorkspaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; +import { activeWorkspaceIdAtom } from "@/atoms/workspaces/workspace-query.atoms"; import { DocumentUploadDialogProvider } from "@/components/assistant-ui/document-upload-popup"; import { LayoutDataProvider } from "@/components/layout"; import { OnboardingTour } from "@/components/onboarding-tour"; diff --git a/surfsense_web/app/dashboard/[workspace_id]/team/page.tsx b/surfsense_web/app/dashboard/[workspace_id]/team/page.tsx index 4f986b287..c81646e4c 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/team/page.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/team/page.tsx @@ -1,10 +1,6 @@ import { TeamContent } from "./team-content"; -export default async function TeamPage({ - params, -}: { - params: Promise<{ workspace_id: string }>; -}) { +export default async function TeamPage({ params }: { params: Promise<{ workspace_id: string }> }) { const { workspace_id } = await params; return ( diff --git a/surfsense_web/app/dashboard/[workspace_id]/team/team-content.tsx b/surfsense_web/app/dashboard/[workspace_id]/team/team-content.tsx index afe640543..23fd111cd 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/team/team-content.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/team/team-content.tsx @@ -599,7 +599,7 @@ function MemberRow({ - router.push(`/dashboard/${workspaceId}/search-space-settings/team-roles`) + router.push(`/dashboard/${workspaceId}/workspace-settings/team-roles`) } > Manage Roles diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/AgentPermissionsContent.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/AgentPermissionsContent.tsx index 6cddb2b9e..bb19697f6 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/AgentPermissionsContent.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/AgentPermissionsContent.tsx @@ -6,7 +6,7 @@ import { AlertTriangle, Info, ShieldCheck, Trash2 } from "lucide-react"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; import { agentFlagsAtom } from "@/atoms/agent/agent-flags-query.atom"; -import { activeWorkspaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; +import { activeWorkspaceIdAtom } from "@/atoms/workspaces/workspace-query.atoms"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { AlertDialog, diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DesktopContent.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DesktopContent.tsx index 97debca9d..bccc146f0 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DesktopContent.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DesktopContent.tsx @@ -13,9 +13,9 @@ import { import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; import { Switch } from "@/components/ui/switch"; -import type { SearchSpace } from "@/contracts/types/search-space.types"; +import type { SearchSpace } from "@/contracts/types/workspace.types"; import { useElectronAPI } from "@/hooks/use-platform"; -import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service"; +import { searchSpacesApiService } from "@/lib/apis/workspaces-api.service"; export function DesktopContent() { const api = useElectronAPI(); diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/MessagingChannelsContent.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/MessagingChannelsContent.tsx index 3c1d3aef4..09472fd70 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/MessagingChannelsContent.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/MessagingChannelsContent.tsx @@ -17,8 +17,8 @@ import { } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; -import type { SearchSpace } from "@/contracts/types/search-space.types"; -import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service"; +import type { SearchSpace } from "@/contracts/types/workspace.types"; +import { searchSpacesApiService } from "@/lib/apis/workspaces-api.service"; import { authenticatedFetch } from "@/lib/auth-fetch"; import { buildBackendUrl } from "@/lib/env-config"; import { cn } from "@/lib/utils"; diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/layout.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/layout.tsx index 46aa27ebe..82a7cf3be 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/user-settings/layout.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/layout.tsx @@ -11,7 +11,5 @@ export default function UserSettingsLayout({ }) { const { workspace_id } = use(params); - return ( - {children} - ); + return {children}; } diff --git a/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/layout-shell.tsx b/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/layout-shell.tsx index 45e1248c6..320dac9ba 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/layout-shell.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/layout-shell.tsx @@ -76,7 +76,7 @@ export function SearchSpaceSettingsLayoutShell({ const selectedLabel = navItems.find((item) => item.value === activeTab)?.label ?? t("title"); const hrefFor = (tab: SearchSpaceSettingsTab) => - `/dashboard/${workspaceId}/search-space-settings/${tab}`; + `/dashboard/${workspaceId}/workspace-settings/${tab}`; return (
diff --git a/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/page.tsx b/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/page.tsx index 692ba563c..cd1d51f3a 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/page.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/workspace-settings/page.tsx @@ -6,5 +6,5 @@ export default async function SearchSpaceSettingsPage({ params: Promise<{ workspace_id: string }>; }) { const { workspace_id } = await params; - redirect(`/dashboard/${workspace_id}/search-space-settings/general`); + redirect(`/dashboard/${workspace_id}/workspace-settings/general`); } diff --git a/surfsense_web/app/dashboard/page.tsx b/surfsense_web/app/dashboard/page.tsx index c31f0384a..205f8df94 100644 --- a/surfsense_web/app/dashboard/page.tsx +++ b/surfsense_web/app/dashboard/page.tsx @@ -6,7 +6,7 @@ import { motion } from "motion/react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { useEffect, useState } from "react"; -import { searchSpacesAtom } from "@/atoms/search-spaces/search-space-query.atoms"; +import { searchSpacesAtom } from "@/atoms/workspaces/workspace-query.atoms"; import { CreateSearchSpaceDialog } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; diff --git a/surfsense_web/app/desktop/login/page.tsx b/surfsense_web/app/desktop/login/page.tsx index 5f7f6ade2..b8edeba96 100644 --- a/surfsense_web/app/desktop/login/page.tsx +++ b/surfsense_web/app/desktop/login/page.tsx @@ -14,7 +14,7 @@ import { Separator } from "@/components/ui/separator"; import { ShortcutKbd } from "@/components/ui/shortcut-kbd"; import { Spinner } from "@/components/ui/spinner"; import { useElectronAPI } from "@/hooks/use-platform"; -import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service"; +import { searchSpacesApiService } from "@/lib/apis/workspaces-api.service"; import { getPostLoginRedirectPath } from "@/lib/auth-utils"; type ShortcutKey = "generalAssist" | "quickAsk" | "screenshotAssist"; diff --git a/surfsense_web/app/invite/[invite_code]/page.tsx b/surfsense_web/app/invite/[invite_code]/page.tsx index fee3f4647..a6423d28d 100644 --- a/surfsense_web/app/invite/[invite_code]/page.tsx +++ b/surfsense_web/app/invite/[invite_code]/page.tsx @@ -98,15 +98,11 @@ export default function InviteAcceptPage() { // Track invite accepted and user added events trackSearchSpaceInviteAccepted( - result.search_space_id, - result.search_space_name, - result.role_name - ); - trackSearchSpaceUserAdded( - result.search_space_id, - result.search_space_name, + result.workspace_id, + result.workspace_name, result.role_name ); + trackSearchSpaceUserAdded(result.workspace_id, result.workspace_name, result.role_name); } } catch (err: any) { setError(err.message || "Failed to accept invite"); @@ -117,7 +113,7 @@ export default function InviteAcceptPage() { const handleDecline = () => { // Track invite declined event - trackSearchSpaceInviteDeclined(inviteInfo?.search_space_name); + trackSearchSpaceInviteDeclined(inviteInfo?.workspace_name); router.push("/dashboard"); }; @@ -180,7 +176,7 @@ export default function InviteAcceptPage() { Welcome to the team! - You've successfully joined {acceptedData.search_space_name} + You've successfully joined {acceptedData.workspace_name} @@ -190,7 +186,7 @@ export default function InviteAcceptPage() {
-

{acceptedData.search_space_name}

+

{acceptedData.workspace_name}

Search Space

@@ -208,7 +204,7 @@ export default function InviteAcceptPage() {