diff --git a/.agents/skills/project-overview/SKILL.md b/.agents/skills/project-overview/SKILL.md
index 5e66f997a5..fb1cf125cb 100644
--- a/.agents/skills/project-overview/SKILL.md
+++ b/.agents/skills/project-overview/SKILL.md
@@ -101,13 +101,20 @@ lobe-chat/
│ │ │ ├── oidc/
│ │ │ ├── trpc/
│ │ │ └── webapi/
-│ │ ├── [variants]/
-│ │ │ ├── (auth)/
-│ │ │ ├── (main)/
-│ │ │ ├── (mobile)/
-│ │ │ ├── onboarding/
-│ │ │ └── router/
-│ │ └── desktop/
+│ │ ├── spa/ # SPA HTML template service
+│ │ └── [variants]/
+│ │ └── (auth)/ # Auth pages (SSR required)
+│ ├── routes/ # SPA page components (Vite)
+│ │ ├── (main)/
+│ │ ├── (mobile)/
+│ │ ├── (desktop)/
+│ │ ├── onboarding/
+│ │ └── share/
+│ ├── spa/ # SPA entry points and router config
+│ │ ├── entry.web.tsx
+│ │ ├── entry.mobile.tsx
+│ │ ├── entry.desktop.tsx
+│ │ └── router/
│ ├── business/ # Cloud-only (client/server)
│ │ ├── client/
│ │ ├── locales/
@@ -155,6 +162,8 @@ lobe-chat/
| Layer | Location |
| ---------------- | --------------------------------------------------- |
| UI Components | `src/components`, `src/features` |
+| SPA Pages | `src/routes/` |
+| React Router | `src/spa/router/` |
| Global Providers | `src/layout` |
| Zustand Stores | `src/store` |
| Client Services | `src/services/` |
diff --git a/.agents/skills/react/SKILL.md b/.agents/skills/react/SKILL.md
index 5f1d5cf2fa..ecb9490190 100644
--- a/.agents/skills/react/SKILL.md
+++ b/.agents/skills/react/SKILL.md
@@ -36,9 +36,9 @@ Hybrid routing: Next.js App Router (static pages) + React Router DOM (main SPA).
### Key Files
-- Entry: `src/app/[variants]/page.tsx`
-- Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
-- Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
+- Entry: `src/spa/entry.web.tsx` (web), `src/spa/entry.mobile.tsx`, `src/spa/entry.desktop.tsx`
+- Desktop router: `src/spa/router/desktopRouter.config.tsx`
+- Mobile router: `src/spa/router/mobileRouter.config.tsx`
- Router utilities: `src/utils/router.tsx`
### Router Utilities
diff --git a/.agents/skills/spa-routes/SKILL.md b/.agents/skills/spa-routes/SKILL.md
new file mode 100644
index 0000000000..0cd55f3710
--- /dev/null
+++ b/.agents/skills/spa-routes/SKILL.md
@@ -0,0 +1,145 @@
+---
+name: spa-routes
+description: SPA route and feature structure. Use when adding or modifying SPA routes in src/routes, defining new route segments, or moving route logic into src/features. Covers how to keep routes thin and how to divide files between routes and features.
+---
+
+# SPA Routes and Features Guide
+
+SPA structure:
+
+- **`src/spa/`** – Entry points (`entry.web.tsx`, `entry.mobile.tsx`, `entry.desktop.tsx`) and router config (`router/`). Router lives here to avoid confusion with `src/routes/`.
+- **`src/routes/`** – Page segments only (roots).
+- **`src/features/`** – Business logic and UI by domain.
+
+This project uses a **roots vs features** split: `src/routes/` only holds page segments; business logic and UI live in `src/features/` by domain.
+
+## When to Use This Skill
+
+- Adding a new SPA route or route segment
+- Defining or refactoring layout/page files under `src/routes/`
+- Moving route-specific components or logic into `src/features/`
+- Deciding where to put a new component (route folder vs feature folder)
+
+---
+
+## 1. What Belongs in `src/routes/` (roots)
+
+Each route directory should contain **only**:
+
+| File / folder | Purpose |
+| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `_layout/index.tsx` or `layout.tsx` | Layout for this segment: wrap with ``, optional shell (e.g. sidebar + main). Should be thin: prefer re-exporting or composing from `@/features/*`. |
+| `index.tsx` or `page.tsx` | Page entry for this segment. Only import from features and render; no business logic. |
+| `[param]/index.tsx` (e.g. `[id]`, `[cronId]`) | Dynamic segment page. Same rule: thin, delegate to features. |
+
+**Rule:** Route files should only **import and compose**. No new `features/` folders or heavy components inside `src/routes/`.
+
+---
+
+## 2. What Belongs in `src/features/`
+
+Put **domain-oriented** UI and logic here:
+
+- Layout building blocks: sidebars, headers, body panels, drawers
+- Hooks and store usage for that domain
+- Domain-specific forms, lists, modals, etc.
+
+Organize by **domain** (e.g. `Pages`, `Home`, `Agent`, `PageEditor`), not by route path. One route can use several features; one feature can be used by several routes.
+
+Each feature should:
+
+- Live under `src/features//`
+- Export a clear public API via `index.ts` or `index.tsx`
+- Use `@/features//...` for internal imports when needed
+
+---
+
+## 3. How to Add a New SPA Route
+
+1. **Choose the route group**
+ - `(main)/` – desktop main app
+ - `(mobile)/` – mobile
+ - `(desktop)/` – Electron-specific
+ - `onboarding/`, `share/` – special flows
+
+2. **Create only segment files under `src/routes/`**
+ - e.g. `src/routes/(main)/my-feature/_layout/index.tsx` and `src/routes/(main)/my-feature/index.tsx` (and optional `[id]/index.tsx`).
+
+3. **Implement layout and page content in `src/features/`**
+ - Create or reuse a domain (e.g. `src/features/MyFeature/`).
+ - Put layout (sidebar, header, body) and page UI there; export from the feature’s `index`.
+
+4. **Keep route files thin**
+ - Layout: `export { default } from '@/features/MyFeature/MyLayout'` or compose a few feature components + ``.
+ - Page: import from `@/features/MyFeature` (or a specific subpath) and render; no business logic in the route file.
+
+5. **Register the route**
+ - Add the segment to `src/spa/router/desktopRouter.config.tsx` (or the right router config) with `dynamicElement` / `dynamicLayout` pointing at the new route paths (e.g. `@/routes/(main)/my-feature`).
+
+---
+
+## 4. How to Divide Files (route vs feature)
+
+| Question | Put in `src/routes/` | Put in `src/features/` |
+| -------------------------------------------------------- | -------------------------------------------------------- | ---------------------------- |
+| Is it the route’s layout wrapper or page entry? | Yes – `_layout/index.tsx`, `index.tsx`, `[id]/index.tsx` | No |
+| Does it contain business logic or non-trivial UI? | No | Yes – under the right domain |
+| Is it a reusable layout piece (sidebar, header, body)? | No | Yes |
+| Is it a hook, store usage, or domain logic? | No | Yes |
+| Is it only re-exporting or composing feature components? | Yes | No |
+
+**Examples**
+
+- **Route (thin):**\
+ `src/routes/(main)/page/_layout/index.tsx` → `export { default } from '@/features/Pages/PageLayout'`
+- **Feature (real implementation):**\
+ `src/features/Pages/PageLayout/` → Sidebar, DataSync, Body, Header, styles, etc.
+- **Route (thin):**\
+ `src/routes/(main)/page/index.tsx` → Import `PageTitle`, `PageExplorerPlaceholder` from `@/features/Pages` and `@/features/PageExplorer`; render with `` and placeholder.
+- **Feature:**\
+ Page list, actions, drawers, and hooks live under `src/features/Pages/`.
+
+---
+
+## 5. Progressive Migration (existing code)
+
+We are migrating existing routes to this structure step by step:
+
+- **Phase 1 (done):** `/page` route – segment files in `src/routes/(main)/page/`, implementation in `src/features/Pages/`.
+- **Later phases:** home, settings, agent/group, community/resource/memory, mobile/share/onboarding.
+
+When touching an old route that still has logic or `features/` inside `src/routes/`:
+
+1. Prefer adding **new** code in `src/features//` and importing from routes.
+2. For larger refactors, move existing route-only logic into the right feature and then thin out the route files (re-export or compose from features).
+3. Use `git mv` when moving files so history is preserved.
+
+---
+
+## 6. Reference Structure (after Phase 1)
+
+**Route (thin):**
+
+```
+src/routes/(main)/page/
+├── _layout/index.tsx → re-export or compose from @/features/Pages/PageLayout
+├── index.tsx → import from @/features/Pages, @/features/PageExplorer
+└── [id]/index.tsx → import from @/features/Pages, @/features/PageExplorer
+```
+
+**Feature (implementation):**
+
+```
+src/features/Pages/
+├── index.ts → export PageLayout, PageTitle
+├── PageTitle.tsx
+└── PageLayout/
+ ├── index.tsx → Sidebar + Outlet + DataSync
+ ├── DataSync.tsx
+ ├── Sidebar.tsx
+ ├── style.ts
+ ├── Body/ → list, actions, drawer, etc.
+ └── Header/ → breadcrumb, add button, etc.
+```
+
+Router config continues to point at **route** paths (e.g. `@/routes/(main)/page`, `@/routes/(main)/page/_layout`); route files then delegate to features.
diff --git a/AGENTS.md b/AGENTS.md
index 722c995404..6c265f82a2 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -26,6 +26,9 @@ lobe-chat/
│ └── ...
├── src/
│ ├── app/ # Next.js app router
+│ ├── spa/ # SPA entry points (entry.*.tsx) and router config
+│ ├── routes/ # SPA page components (roots)
+│ ├── features/ # Business components by domain
│ ├── store/ # Zustand stores
│ ├── services/ # Client services
│ ├── server/ # Server services and routers
@@ -87,19 +90,26 @@ cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path
Follow [Linear rules in CLAUDE.md](CLAUDE.md#linear-issue-management-ignore-if-not-installed-linear-mcp) when working with Linear issues.
+## SPA Routes and Features
+
+- **`src/routes/`** holds only page segments (layout + page entry files). Keep route files thin; they should import from `@/features/*` and compose.
+- **`src/features/`** holds business components by domain. Put layout pieces, hooks, and domain UI here.
+- See [CLAUDE.md – SPA Routes and Features](CLAUDE.md#spa-routes-and-features) and the **spa-routes** skill for how to add new routes and how to split files.
+
## Skills (Auto-loaded)
All AI development skills are available in `.agents/skills/` directory:
-| Category | Skills |
-| ----------- | ------------------------------------------ |
-| Frontend | `react`, `typescript`, `i18n`, `microcopy` |
-| State | `zustand` |
-| Backend | `drizzle` |
-| Desktop | `desktop` |
-| Testing | `testing` |
-| UI | `modal`, `hotkey`, `recent-data` |
-| Config | `add-provider-doc`, `add-setting-env` |
-| Workflow | `linear`, `debug` |
-| Performance | `vercel-react-best-practices` |
-| Overview | `project-overview` |
+| Category | Skills |
+| ------------ | ------------------------------------------ |
+| Frontend | `react`, `typescript`, `i18n`, `microcopy` |
+| State | `zustand` |
+| Backend | `drizzle` |
+| Desktop | `desktop` |
+| Testing | `testing` |
+| UI | `modal`, `hotkey`, `recent-data` |
+| Config | `add-provider-doc`, `add-setting-env` |
+| Workflow | `linear`, `debug` |
+| Architecture | `spa-routes` |
+| Performance | `vercel-react-best-practices` |
+| Overview | `project-overview` |
diff --git a/CLAUDE.md b/CLAUDE.md
index 13a27c8fd2..18e6584cbb 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -21,7 +21,21 @@ lobe-chat/
│ ├── agent-runtime/ # Agent runtime
│ └── ...
├── src/
-│ ├── app/ # Next.js app router
+│ ├── app/ # Next.js App Router (backend API + auth)
+│ │ ├── (backend)/ # API routes (trpc, webapi, etc.)
+│ │ ├── spa/ # SPA HTML template service
+│ │ └── [variants]/(auth)/ # Auth pages (SSR required)
+│ ├── routes/ # SPA page components (Vite)
+│ │ ├── (main)/ # Desktop pages
+│ │ ├── (mobile)/ # Mobile pages
+│ │ ├── (desktop)/ # Desktop-specific pages
+│ │ ├── onboarding/ # Onboarding pages
+│ │ └── share/ # Share pages
+│ ├── spa/ # SPA entry points and router config
+│ │ ├── entry.web.tsx # Web entry
+│ │ ├── entry.mobile.tsx
+│ │ ├── entry.desktop.tsx
+│ │ └── router/ # React Router configuration
│ ├── store/ # Zustand stores
│ ├── services/ # Client services
│ ├── server/ # Server services and routers
@@ -29,6 +43,26 @@ lobe-chat/
└── e2e/ # E2E tests (Cucumber + Playwright)
```
+## SPA Routes and Features
+
+SPA-related code is grouped under `src/spa/` (entries + router) and `src/routes/` (page segments). We use a **roots vs features** split: route trees only hold page segments; business logic and UI live in features.
+
+- **`src/spa/`** – SPA entry points (`entry.web.tsx`, `entry.mobile.tsx`, `entry.desktop.tsx`) and React Router config (`router/`). Keeps router config next to entries to avoid confusion with `src/routes/`.
+
+- **`src/routes/` (roots)**\
+ Only page-segment files: `_layout/index.tsx`, `index.tsx` (or `page.tsx`), and dynamic segments like `[id]/index.tsx`. Keep these **thin**: they should only import from `@/features/*` and compose layout/page, with no business logic or heavy UI.
+
+- **`src/features/`**\
+ Business components by **domain** (e.g. `Pages`, `PageEditor`, `Home`). Put layout chunks (sidebar, header, body), hooks, and domain-specific UI here. Each feature exposes an `index.ts` (or `index.tsx`) with clear exports.
+
+When adding or changing SPA routes:
+
+1. In `src/routes/`, add only the route segment files (layout + page) that delegate to features.
+2. Implement layout and page content under `src/features//` and export from there.
+3. In route files, use `import { X } from '@/features/'` (or `import Y from '@/features//...'`). Do not add new `features/` folders inside `src/routes/`.
+
+See the **spa-routes** skill (`.agents/skills/spa-routes/SKILL.md`) for the full convention and file-division rules.
+
## Development
### Starting the Dev Environment
diff --git a/apps/desktop/index.html b/apps/desktop/index.html
index 73d8d12586..b54833c64a 100644
--- a/apps/desktop/index.html
+++ b/apps/desktop/index.html
@@ -85,6 +85,6 @@
-
+