mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
update
This commit is contained in:
parent
8bc092e40e
commit
f60ba3d01f
5 changed files with 885 additions and 0 deletions
328
_bmad-output/implementation-artifacts/1-6-settings-sync.md
Normal file
328
_bmad-output/implementation-artifacts/1-6-settings-sync.md
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
# Story 1.6: Đồng bộ Cài đặt (Settings Sync) với Frontend
|
||||
|
||||
Status: ready-for-dev
|
||||
|
||||
## Story
|
||||
|
||||
**Là một** SurfSense user,
|
||||
**Tôi muốn** extension sử dụng cùng model và search space như web dashboard,
|
||||
**Để** tôi không phải cấu hình lại.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **REQUIRES:** Story 1.0 (Authentication System) - Must be completed first
|
||||
- Extension must have valid JWT token to call backend APIs
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### AC 1.6.1: Hiển thị Dropdown Cài đặt
|
||||
- **Given** user đã đăng nhập
|
||||
- **When** user click icon ⚙️ trong header
|
||||
- **Then** settings dropdown mở ra
|
||||
- **And** dropdown hiển thị:
|
||||
- Current model: "GPT-4 Turbo" (chỉ xem, bị mờ)
|
||||
- Current search space: "Crypto Research" (chỉ xem, bị mờ)
|
||||
- Links đến web dashboard:
|
||||
- "🔗 Manage Connectors"
|
||||
- "💬 View All Chats"
|
||||
- "⚙️ Full Settings"
|
||||
- Nút "🚪 Logout"
|
||||
|
||||
### AC 1.6.2: Đồng bộ Cài đặt khi Đăng nhập
|
||||
- **Given** user hoàn tất đăng nhập
|
||||
- **When** nhận được JWT token
|
||||
- **Then** extension gọi `GET /api/v1/searchspaces` để lấy danh sách search spaces
|
||||
- **And** extension gọi `GET /api/v1/search-spaces/{id}/llm-preferences` để lấy LLM config
|
||||
- **And** settings được lưu trong Plasmo Storage
|
||||
- **And** settings hiển thị trong dropdown
|
||||
|
||||
**Response Format (từ backend):**
|
||||
```json
|
||||
// GET /api/v1/searchspaces
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Crypto Research",
|
||||
"description": "...",
|
||||
"agent_llm_id": 0,
|
||||
"document_summary_llm_id": 0
|
||||
}
|
||||
]
|
||||
|
||||
// GET /api/v1/search-spaces/{id}/llm-preferences
|
||||
{
|
||||
"agent_llm_id": 0,
|
||||
"document_summary_llm_id": 0,
|
||||
"agent_llm": {
|
||||
"id": 0,
|
||||
"name": "Auto (Load Balanced)",
|
||||
"provider": "AUTO",
|
||||
"model_name": "auto"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AC 1.6.3: Tự động cập nhật Cài đặt
|
||||
- **Given** user thay đổi model trên web dashboard
|
||||
- **When** extension phát hiện thay đổi (qua polling)
|
||||
- **Then** extension lấy settings đã cập nhật
|
||||
- **And** dropdown phản ánh model mới
|
||||
- **And** các cuộc chat tiếp theo sử dụng model mới
|
||||
|
||||
**Polling:**
|
||||
- **Given** extension đang hoạt động
|
||||
- **When** mỗi 5 phút
|
||||
- **Then** extension polls `GET /api/v1/searchspaces` và LLM preferences
|
||||
|
||||
### AC 1.6.4: Search Space Selector
|
||||
- **Given** user có nhiều search spaces
|
||||
- **When** user click vào search space selector trong header
|
||||
- **Then** dropdown hiển thị tất cả search spaces của user
|
||||
- **And** user có thể chọn search space khác
|
||||
- **And** extension lưu selection vào Plasmo Storage
|
||||
- **And** các API calls tiếp theo sử dụng search_space_id mới
|
||||
|
||||
### AC 1.6.5: Offline Handling
|
||||
- **Given** user đã đăng nhập và có settings đã cache
|
||||
- **When** user mất kết nối internet
|
||||
- **Then** extension sử dụng settings đã cache
|
||||
- **And** hiển thị indicator "Using cached settings"
|
||||
- **When** kết nối được khôi phục
|
||||
- **Then** extension sync settings mới từ backend
|
||||
|
||||
## Tasks / Subtasks
|
||||
|
||||
- [ ] Task 1: Settings Service (AC: 1.6.2, 1.6.3)
|
||||
- [ ] 1.1 Tạo `lib/settings/settings-service.ts` - API calls cho settings
|
||||
- [ ] 1.2 Implement `fetchSearchSpaces()` - GET /api/v1/searchspaces
|
||||
- [ ] 1.3 Implement `fetchLLMPreferences(spaceId)` - GET LLM config
|
||||
- [ ] 1.4 Implement polling mechanism (5 phút interval)
|
||||
- [ ] 1.5 Implement settings caching trong Plasmo Storage
|
||||
|
||||
- [ ] Task 2: Settings State Management (AC: 1.6.1, 1.6.4)
|
||||
- [ ] 2.1 Tạo `lib/settings/settings-store.ts` - Zustand/Context store
|
||||
- [ ] 2.2 Define settings types và interfaces
|
||||
- [ ] 2.3 Implement search space selection logic
|
||||
- [ ] 2.4 Implement settings sync on login
|
||||
|
||||
- [ ] Task 3: Settings UI Components (AC: 1.6.1, 1.6.4)
|
||||
- [ ] 3.1 Update `sidepanel/chat/ChatHeader.tsx` - Integrate real settings
|
||||
- [ ] 3.2 Tạo `sidepanel/settings/SettingsDropdown.tsx` - Enhanced dropdown
|
||||
- [ ] 3.3 Tạo `sidepanel/settings/SearchSpaceSelector.tsx` - Space picker
|
||||
- [ ] 3.4 Tạo `sidepanel/settings/ModelDisplay.tsx` - Read-only model info
|
||||
|
||||
- [ ] Task 4: Integration với Auth (AC: 1.6.2, 1.6.5)
|
||||
- [ ] 4.1 Hook settings fetch vào auth flow (sau login thành công)
|
||||
- [ ] 4.2 Implement offline detection và fallback
|
||||
- [ ] 4.3 Clear settings on logout
|
||||
- [ ] 4.4 Handle 401 errors (redirect to login)
|
||||
|
||||
- [ ] Task 5: Testing
|
||||
- [ ] 5.1 Test settings sync sau login
|
||||
- [ ] 5.2 Test polling mechanism
|
||||
- [ ] 5.3 Test search space switching
|
||||
- [ ] 5.4 Test offline mode với cached settings
|
||||
|
||||
## Dev Notes
|
||||
|
||||
### Backend APIs (ALREADY EXISTS)
|
||||
|
||||
Backend đã có đầy đủ APIs cho settings:
|
||||
|
||||
**Search Spaces:**
|
||||
```
|
||||
GET /api/v1/searchspaces - List all user's search spaces
|
||||
POST /api/v1/searchspaces - Create new search space
|
||||
GET /api/v1/searchspaces/{id} - Get single search space
|
||||
PUT /api/v1/searchspaces/{id} - Update search space
|
||||
DELETE /api/v1/searchspaces/{id} - Delete search space
|
||||
```
|
||||
|
||||
**LLM Preferences:**
|
||||
```
|
||||
GET /api/v1/search-spaces/{id}/llm-preferences - Get LLM config for space
|
||||
PUT /api/v1/search-spaces/{id}/llm-preferences - Update LLM config
|
||||
```
|
||||
|
||||
**Global LLM Configs:**
|
||||
```
|
||||
GET /api/v1/global-new-llm-configs - List available LLM models
|
||||
```
|
||||
|
||||
### Existing Extension Code
|
||||
|
||||
**ChatHeader.tsx (đã có UI cơ bản):**
|
||||
- Search space selector dropdown (hardcoded data)
|
||||
- Settings dropdown với menu items
|
||||
- User avatar với logout
|
||||
- Token search bar
|
||||
|
||||
**Cần update:**
|
||||
- Replace hardcoded search spaces với real data từ API
|
||||
- Add model display trong settings dropdown
|
||||
- Connect logout button với auth service
|
||||
|
||||
### Data Types
|
||||
|
||||
**SearchSpace (từ backend):**
|
||||
```typescript
|
||||
interface SearchSpace {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
user_id: string;
|
||||
agent_llm_id: number;
|
||||
document_summary_llm_id: number;
|
||||
created_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
**LLMPreferences (từ backend):**
|
||||
```typescript
|
||||
interface LLMPreferences {
|
||||
agent_llm_id: number;
|
||||
document_summary_llm_id: number;
|
||||
agent_llm?: LLMConfig;
|
||||
document_summary_llm?: LLMConfig;
|
||||
}
|
||||
|
||||
interface LLMConfig {
|
||||
id: number;
|
||||
name: string;
|
||||
provider: string;
|
||||
model_name: string;
|
||||
is_global?: boolean;
|
||||
is_auto_mode?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Project Structure Notes
|
||||
|
||||
**Files cần tạo mới:**
|
||||
```
|
||||
surfsense_browser_extension/
|
||||
├── lib/
|
||||
│ └── settings/
|
||||
│ ├── settings-service.ts # API calls
|
||||
│ ├── settings-store.ts # State management
|
||||
│ └── types.ts # TypeScript interfaces
|
||||
└── sidepanel/
|
||||
└── settings/
|
||||
├── SettingsDropdown.tsx # Enhanced dropdown
|
||||
├── SearchSpaceSelector.tsx # Space picker
|
||||
└── ModelDisplay.tsx # Read-only model info
|
||||
```
|
||||
|
||||
**Files cần modify:**
|
||||
- `sidepanel/chat/ChatHeader.tsx` - Integrate real settings data
|
||||
- `sidepanel/index.tsx` - Add SettingsProvider
|
||||
- `lib/auth/api-client.ts` - Add settings endpoints (từ Story 1.0)
|
||||
|
||||
### Implementation Pattern
|
||||
|
||||
**Settings Service:**
|
||||
```typescript
|
||||
// lib/settings/settings-service.ts
|
||||
import { apiClient } from '../auth/api-client';
|
||||
|
||||
export const settingsService = {
|
||||
async fetchSearchSpaces(): Promise<SearchSpace[]> {
|
||||
return apiClient.get('/api/v1/searchspaces');
|
||||
},
|
||||
|
||||
async fetchLLMPreferences(spaceId: number): Promise<LLMPreferences> {
|
||||
return apiClient.get(`/api/v1/search-spaces/${spaceId}/llm-preferences`);
|
||||
},
|
||||
|
||||
async fetchGlobalLLMConfigs(): Promise<LLMConfig[]> {
|
||||
return apiClient.get('/api/v1/global-new-llm-configs');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Settings Store (Plasmo Storage):**
|
||||
```typescript
|
||||
// lib/settings/settings-store.ts
|
||||
import { Storage } from "@plasmohq/storage";
|
||||
|
||||
const storage = new Storage({ area: "local" });
|
||||
|
||||
export const settingsStore = {
|
||||
async saveSearchSpaces(spaces: SearchSpace[]) {
|
||||
await storage.set('searchSpaces', spaces);
|
||||
},
|
||||
|
||||
async getSearchSpaces(): Promise<SearchSpace[] | null> {
|
||||
return storage.get('searchSpaces');
|
||||
},
|
||||
|
||||
async saveSelectedSpaceId(id: number) {
|
||||
await storage.set('selectedSearchSpaceId', id);
|
||||
},
|
||||
|
||||
async getSelectedSpaceId(): Promise<number | null> {
|
||||
return storage.get('selectedSearchSpaceId');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Polling Implementation
|
||||
|
||||
```typescript
|
||||
// Polling every 5 minutes
|
||||
const POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
useEffect(() => {
|
||||
const pollSettings = async () => {
|
||||
try {
|
||||
const spaces = await settingsService.fetchSearchSpaces();
|
||||
await settingsStore.saveSearchSpaces(spaces);
|
||||
|
||||
const selectedId = await settingsStore.getSelectedSpaceId();
|
||||
if (selectedId) {
|
||||
const prefs = await settingsService.fetchLLMPreferences(selectedId);
|
||||
await settingsStore.saveLLMPreferences(prefs);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Settings poll failed:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const interval = setInterval(pollSettings, POLLING_INTERVAL);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
```
|
||||
|
||||
### Security Considerations
|
||||
|
||||
1. Settings API calls require valid JWT (handled by api-client)
|
||||
2. Cache settings locally for offline access
|
||||
3. Clear cached settings on logout
|
||||
4. Handle 401 errors gracefully (redirect to login)
|
||||
|
||||
### References
|
||||
|
||||
- [Source: surfsense_backend/app/routes/search_spaces_routes.py] - Search space APIs
|
||||
- [Source: surfsense_backend/app/routes/new_llm_config_routes.py] - LLM config APIs
|
||||
- [Source: surfsense_browser_extension/sidepanel/chat/ChatHeader.tsx] - Existing UI
|
||||
- [Source: _bmad-epics/epic-1-ai-powered-crypto-assistant.md#Story-1.6] - Full requirements
|
||||
- [Source: _bmad-output/implementation-artifacts/1-0-authentication-system.md] - Auth dependency
|
||||
|
||||
## Dev Agent Record
|
||||
|
||||
### Agent Model Used
|
||||
{{agent_model_name_version}}
|
||||
|
||||
### Completion Notes List
|
||||
- Story created: 2026-02-04
|
||||
- Backend APIs already exist and are fully functional
|
||||
- Extension UI partially exists (ChatHeader.tsx has basic structure)
|
||||
- DEPENDS ON Story 1.0 (Authentication) - must complete auth first
|
||||
- Settings are read-only in extension (changes made via web dashboard)
|
||||
|
||||
### Debug Log References
|
||||
(To be filled during implementation)
|
||||
|
||||
### File List
|
||||
(To be filled during implementation)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue