Docs / Raw

System Review 2025 11 22

Sourced from docs/SYSTEM_REVIEW_2025-11-22.md

Edit on GitHub

VoiceAssist System Review - 2025-11-22

Reviewer: Claude (AI Assistant) Date: November 22, 2025 Branch: fix/system-review-and-testing Scope: Chat interface, conversation management, WebSocket integration


Executive Summary

This document provides a comprehensive review of the VoiceAssist web application's current implementation, focusing on the chat interface, conversation management, and WebSocket integrations. The review identifies the current state, potential issues, and recommendations for improvements.

Overall Assessment

Strengths:

  • Well-structured monorepo architecture with clear separation of concerns
  • Comprehensive type safety with TypeScript across frontend and shared packages
  • Good WebSocket integration with error handling and reconnection logic
  • Solid conversation management with CRUD operations
  • Existing test coverage for core components

⚠️ Areas for Improvement:

  • WebSocket protocol mismatch between frontend and backend
  • Missing last message preview functionality
  • No transcription/voice mode implementation yet
  • Some error handling gaps in conversation operations
  • Limited integration tests for WebSocket flows

1. Architecture Review

1.1 Frontend Structure

Location: /apps/web-app/

The frontend is built with:

  • React with TypeScript
  • Vite as build tool
  • Zustand for state management
  • React Router for routing
  • Vitest for testing
  • React Query could be integrated for better data fetching

Key Components:

  • ChatPage.tsx - Main chat interface with conversation validation
  • ConversationList.tsx - Conversation sidebar with create, rename, archive, delete
  • ConversationListItem.tsx - Individual conversation item with action menu
  • MessageList.tsx - Virtualized message display
  • MessageInput.tsx - Message composition
  • useChatSession.ts - WebSocket hook for real-time chat

Shared Packages:

  • @voiceassist/types - TypeScript type definitions
  • @voiceassist/api-client - HTTP client with authentication
  • @voiceassist/utils - Utility functions
  • @voiceassist/ui - Shared React components
  • @voiceassist/design-tokens - Design system tokens

1.2 Backend Structure

Location: /services/api-gateway/

The backend is built with:

  • FastAPI framework
  • WebSocket support for real-time communication
  • PostgreSQL for data persistence
  • Redis for caching
  • Qdrant for vector search

Key Endpoints:

  • /api/realtime/ws - WebSocket endpoint for chat streaming
  • /conversations - REST API for conversation CRUD
  • /conversations/{id}/messages - REST API for message history

2. Conversation Management Review

2.1 Implementation Status ✅

File: apps/web-app/src/components/conversations/ConversationList.tsx

Features Implemented:

  1. Create Conversation

    • Method: handleCreateNew()
    • API: POST /conversations
    • Default title: "New Conversation"
    • Auto-navigates to new conversation
    • Shows loading state during creation
  2. Rename Conversation

    • Method: handleRename(id, newTitle)
    • API: PATCH /conversations/{id}
    • Inline editing with Enter/Escape keyboard support
    • Auto-saves on blur
  3. Archive Conversation

    • Method: handleArchive(id)
    • API: PATCH /conversations/{id} with { archived: true }
    • Removes from active list immediately
    • Navigates away if archiving active conversation
  4. Delete Conversation

    • Method: handleDelete(id)
    • API: DELETE /conversations/{id}
    • Confirmation dialog with loading state
    • Removes from list immediately
    • Navigates away if deleting active conversation
  5. List Conversations

    • API: GET /conversations?page=1&pageSize=50
    • Filters by archived status
    • Sorts by most recently updated first
    • Shows loading and error states

API Client Methods:

File: packages/api-client/src/index.ts

getConversations(page, pageSize): Promise<PaginatedResponse<Conversation>> getConversation(id): Promise<Conversation> createConversation(title): Promise<Conversation> updateConversation(id, updates): Promise<Conversation> archiveConversation(id): Promise<Conversation> unarchiveConversation(id): Promise<Conversation> deleteConversation(id): Promise<void>

2.2 Potential Issues & Recommendations

Issue 1: No Optimistic Updates

Severity: Medium Location: ConversationList.tsx

Current Behavior:

  • All operations wait for server response before updating UI
  • User experiences delay, especially on slow connections

Recommendation:

// Add optimistic update for rename const handleRename = async (id: string, newTitle: string) => { // Optimistically update UI setConversations((prev) => prev.map((c) => (c.id === id ? { ...c, title: newTitle } : c))); try { const updated = await apiClient.updateConversation(id, { title: newTitle }); setConversations((prev) => prev.map((c) => (c.id === id ? updated : c))); } catch (err) { // Revert on error setConversations((prev) => prev.map((c) => (c.id === id ? { ...c, title: conversation.title } : c))); throw err; } };

Issue 2: No Error Recovery

Severity: Medium Location: ConversationList.tsx

Current Behavior:

  • Errors are logged to console
  • No user-facing error messages for failed operations
  • No retry mechanism

Recommendation:

  • Add toast notifications for errors
  • Implement retry logic for transient failures
  • Show inline error states in conversation items

Issue 3: No Pagination

Severity: Low Location: ConversationList.tsx

Current Behavior:

  • Loads first 50 conversations only
  • No infinite scroll or "load more" functionality

Recommendation:

  • Implement infinite scroll using Intersection Observer
  • Or add "Load More" button at bottom of list

3. Last Message Preview Logic

3.1 Current Status ⚠️

File: apps/web-app/src/components/conversations/ConversationListItem.tsx

Current Implementation:

const preview = conversation.lastMessagePreview || "No messages yet";

Backend Type:

// packages/types/src/index.ts export interface Conversation { id: string; userId: string; title: string; createdAt: string; updatedAt: string; messageCount: number; archived?: boolean; lastMessagePreview?: string; // ✅ Field exists }

3.2 Issues Identified

Issue 1: Backend May Not Populate lastMessagePreview

Severity: Medium Impact: Users see "No messages yet" even for conversations with messages

Investigation Needed:

  • Check if backend API populates this field
  • Verify database schema includes this column
  • Check if field is updated when messages are sent

Recommendation:

  1. Verify backend implementation:

    # In backend, when returning conversations: conversation.lastMessagePreview = ( db.query(Message) .filter(Message.conversation_id == conversation.id) .order_by(Message.timestamp.desc()) .first() .content[:100] # First 100 chars )
  2. Add database migration if column doesn't exist

  3. Update preview when new messages arrive via WebSocket

Issue 2: No Truncation Logic

Severity: Low Location: ConversationListItem.tsx

Current Behavior:

  • Relies on CSS truncate class
  • No character limit enforcement

Recommendation:

const preview = conversation.lastMessagePreview ? truncateText(conversation.lastMessagePreview, 60) : "No messages yet"; function truncateText(text: string, maxLength: number): string { if (text.length <= maxLength) return text; return text.substring(0, maxLength) + "..."; }

4. Active Conversation Handling

4.1 Implementation Review ✅

File: apps/web-app/src/pages/ChatPage.tsx

Flow:

  1. URL-based routing: /chat/:conversationId
  2. Auto-create: If no conversationId in URL, creates new conversation
  3. Validation: Checks if conversation exists via API
  4. History loading: Fetches message history
  5. WebSocket connection: Connects after validation

State Machine:

No ID → Creating → Redirect → Validating → Loading History → Connected
  ↓                                ↓                             ↓
Error                           Not Found                    Chat Ready

4.2 Strengths

Robust Error Handling:

  • Separate error states for create, load, not found, websocket
  • User-friendly error messages
  • Navigation fallbacks

Loading States:

  • Visual feedback for each step
  • Prevents duplicate operations with state checks

Conversation Validation:

  • 404 handling for deleted conversations
  • Auto-redirect on invalid IDs

4.3 Potential Issues

Issue 1: Race Condition in useEffect

Severity: Low Location: ChatPage.tsx:32-89

Current Behavior:

useEffect(() => { const initializeConversation = async () => { if (!conversationId) { if (loadingState === "creating") return; // Guards against re-entry // ... create logic } // ... }; initializeConversation(); }, [conversationId, activeConversationId, apiClient, navigate, loadingState]);

Issue:

  • loadingState is in dependency array
  • State changes can trigger re-initialization
  • Potential for multiple API calls

Recommendation:

// Use useRef to track in-flight operations const initializingRef = useRef(false); useEffect(() => { if (initializingRef.current) return; const initializeConversation = async () => { initializingRef.current = true; try { // ... initialization logic } finally { initializingRef.current = false; } }; initializeConversation(); }, [conversationId]); // Remove loadingState from deps

Issue 2: No Abort Controller for API Calls

Severity: Medium Location: ChatPage.tsx

Current Behavior:

  • API calls continue even if user navigates away
  • Potential memory leaks and race conditions

Recommendation:

useEffect(() => { const abortController = new AbortController(); const initializeConversation = async () => { try { const conv = await apiClient.getConversation(conversationId, { signal: abortController.signal, }); // ... } catch (err) { if (err.name === "AbortError") return; // handle error } }; initializeConversation(); return () => { abortController.abort(); }; }, [conversationId]);

5. WebSocket Integration Review

5.1 Frontend Implementation

File: apps/web-app/src/hooks/useChatSession.ts

Features Implemented ✅

  1. Connection Management:

    • Automatic connection on mount
    • Heartbeat (ping/pong) every 30 seconds
    • Automatic reconnection with exponential backoff
    • Max 5 reconnection attempts
    • Clean disconnect on unmount
  2. Message Protocol:

    • delta - Incremental updates
    • chunk - Complete chunks
    • message.done - Message finalization
    • error - Error handling
    • pong - Heartbeat response
  3. State Management:

    • Connection status tracking
    • Typing indicator
    • Streaming message accumulation
    • Message deduplication
  4. Error Handling:

    • Fatal errors (AUTH_FAILED, QUOTA_EXCEEDED) → disconnect
    • Transient errors (RATE_LIMITED, BACKEND_ERROR) → notify user
    • Connection drops → auto-reconnect

5.2 Backend Implementation

File: services/api-gateway/app/api/realtime.py

Protocol Differences ⚠️

Frontend expects:

{ "type": "delta", "delta": "partial text...", "messageId": "uuid" }

Backend sends:

{ "type": "message_chunk", "message_id": "uuid", "content": "partial text...", "chunk_index": 0 }

5.3 Critical Issues

Issue 1: WebSocket Protocol Mismatch 🔴

Severity: CRITICAL Impact: Frontend cannot parse backend messages correctly

Frontend code:

switch (data.type) { case 'delta': // Frontend expects 'delta' if (data.delta) { ... } break; case 'chunk': // Frontend expects 'chunk' if (data.content) { ... } break; case 'message.done': // Frontend expects 'message.done' if (data.message) { ... } break; }

Backend code:

# Backend sends 'message_start' await websocket.send_json({ "type": "message_start", "message_id": message_id, ... }) # Backend sends 'message_chunk' await websocket.send_json({ "type": "message_chunk", "message_id": message_id, "content": chunk, "chunk_index": i // chunk_size }) # Backend sends 'message_complete' await websocket.send_json({ "type": "message_complete", "message_id": message_id, ... })

Required Fix:

Option A: Update Backend to Match Frontend

# Change backend to send 'chunk' instead of 'message_chunk' await websocket.send_json({ "type": "chunk", "messageId": message_id, # Also change snake_case to camelCase "content": chunk, }) # Change 'message_complete' to 'message.done' await websocket.send_json({ "type": "message.done", "messageId": message_id, "message": { "id": message_id, "role": "assistant", "content": response_text, "citations": citations, ... } })

Option B: Update Frontend to Match Backend

switch (data.type) { case "message_start": // Handle message start break; case "message_chunk": if (data.content) { // Handle chunk } break; case "message_complete": if (data.message) { // Handle completion } break; }

Recommendation: Option A (update backend) is better because:

  • Frontend convention is more concise ('chunk' vs 'message_chunk')
  • camelCase is standard for JSON in JavaScript ecosystem
  • Less refactoring needed in frontend

Issue 2: Missing Message ID in Client Messages

Severity: Medium Location: useChatSession.ts:278-300

Current Frontend Code:

const sendMessage = useCallback( (content: string, attachments?: string[]) => { const userMessage: Message = { id: `msg-${Date.now()}`, // Client-generated ID role: "user", content, attachments, timestamp: Date.now(), }; setMessages((prev) => [...prev, userMessage]); wsRef.current.send( JSON.stringify({ type: "message.send", // Frontend sends 'message.send' message: userMessage, }), ); }, [handleError], );

Backend Expects:

# Backend expects 'message' type, not 'message.send' if message_type == "message": await handle_chat_message(websocket, client_id, data, db)

Fix Required:

wsRef.current.send( JSON.stringify({ type: "message", // Change to 'message' content: content, session_id: conversationId, // ... other fields }), );

Issue 3: No Authentication in WebSocket Connection

Severity: HIGH Location: useChatSession.ts:196-210

Current Implementation:

const url = new URL(WS_URL); url.searchParams.append("conversationId", conversationId); if (tokens?.accessToken) { url.searchParams.append("token", tokens.accessToken); }

Backend Implementation:

# Backend doesn't validate token! @router.websocket("/ws") async def websocket_endpoint( websocket: WebSocket, db: Session = Depends(get_db) ): # No authentication check client_id = str(uuid.uuid4()) await manager.connect(websocket, client_id)

Fix Required:

from app.core.dependencies import get_current_user_ws @router.websocket("/ws") async def websocket_endpoint( websocket: WebSocket, token: str = Query(...), db: Session = Depends(get_db) ): # Validate token try: user = await get_current_user_ws(token, db) except Exception: await websocket.close(code=1008, reason="Unauthorized") return client_id = user.id await manager.connect(websocket, client_id) # ...

Issue 4: Hard-coded WebSocket URL

Severity: Medium Location: useChatSession.ts:37

const WS_URL = "wss://assist.asimo.io/api/realtime";

Issue:

  • Won't work in development
  • Not configurable per environment

Fix:

const WS_URL = import.meta.env.VITE_WS_URL || (import.meta.env.DEV ? "ws://localhost:8000/api/realtime/ws" : "wss://assist.asimo.io/api/realtime/ws");

Add to .env:

VITE_WS_URL=ws://localhost:8000/api/realtime/ws

6. Voice/Transcription Integration

6.1 Current Status ❌

Status: Not implemented in web-app

Backend API Exists:

// packages/api-client/src/index.ts async transcribeAudio(audioBlob: Blob): Promise<string> async synthesizeSpeech(text: string, voiceId?: string): Promise<Blob>

Backend Endpoints:

  • POST /voice/transcribe
  • POST /voice/synthesize

6.2 Recommendations

Phase 1: Basic Voice Input

  1. Add microphone button to MessageInput
  2. Record audio using MediaRecorder API
  3. Send audio blob to /voice/transcribe
  4. Insert transcribed text into input

Phase 2: Streaming Voice

  1. Integrate with WebSocket for real-time transcription
  2. Add VAD (Voice Activity Detection)
  3. Stream audio chunks instead of recording entire message

Phase 3: Voice Output

  1. Synthesize assistant responses
  2. Add audio player controls
  3. Auto-play option in settings

7. Testing Status

7.1 Existing Tests ✅

Unit Tests:

  • MessageList.test.tsx - Comprehensive (314 lines)
  • MessageBubble.test.tsx - Component rendering
  • MessageInput.test.tsx - Input validation
  • CitationDisplay.test.tsx - Citation rendering
  • useChatSession.test.ts - WebSocket hook
  • authStore.test.ts - Authentication state

Integration Tests:

  • ChatFlow.test.tsx - End-to-end chat flow
  • LoginFlow.test.tsx - Authentication flow
  • RegisterFlow.test.tsx - Registration flow
  • ProtectedRoute.test.tsx - Route protection

7.2 Missing Tests ⚠️

  1. Conversation Management:

    • No tests for ConversationList component
    • No tests for ConversationListItem actions
    • No tests for conversation CRUD operations
  2. WebSocket Integration:

    • No tests for protocol compliance
    • No tests for error scenarios
    • No tests for reconnection logic
  3. Error Boundaries:

    • No tests for ChatErrorBoundary
    • No tests for global error handling

File: apps/web-app/src/components/conversations/__tests__/ConversationList.test.tsx

describe("ConversationList", () => { describe("CRUD Operations", () => { it("should create new conversation"); it("should rename conversation"); it("should archive conversation"); it("should delete conversation with confirmation"); it("should handle operation errors"); }); describe("Filtering", () => { it("should filter archived conversations"); it("should sort by most recent"); }); describe("Navigation", () => { it("should navigate to conversation on click"); it("should navigate away when deleting active conversation"); }); });

File: apps/web-app/src/hooks/__tests__/useChatSession.integration.test.ts

describe("useChatSession Integration", () => { it("should connect to WebSocket"); it("should send and receive messages"); it("should handle streaming responses"); it("should reconnect on disconnect"); it("should handle authentication errors"); it("should clean up on unmount"); });

8. Browser Compatibility

8.1 Requirements

WebSocket Support:

  • ✅ Chrome 89+
  • ✅ Firefox 88+
  • ✅ Safari 14+
  • ✅ Edge 89+

MediaRecorder API (for voice):

  • ✅ Chrome 89+
  • ✅ Firefox 88+
  • ⚠️ Safari 14.1+ (limited codec support)
  • ✅ Edge 89+

8.2 Recommendations

  1. Add Polyfills:

    • web-streams-polyfill for older browsers
    • audio-recorder-polyfill for Safari
  2. Feature Detection:

const hasWebSocketSupport = "WebSocket" in window; const hasMediaRecorder = "MediaRecorder" in window; if (!hasWebSocketSupport) { // Show fallback UI or error }
  1. Progressive Enhancement:
    • Core chat works without voice
    • Voice features are optional enhancements

9. Performance Considerations

9.1 Strengths ✅

  1. Message Virtualization:

    • Uses react-virtuoso for efficient rendering
    • Handles 1000+ messages without performance issues
  2. WebSocket Efficiency:

    • Heartbeat prevents unnecessary reconnections
    • Exponential backoff reduces server load
  3. State Management:

    • Functional state updates prevent stale closures
    • Memoized callbacks reduce re-renders

9.2 Potential Improvements

  1. Debounce Rename Input:
const debouncedRename = useDebouncedCallback((id: string, title: string) => onRename(id, title), 500);
  1. Lazy Load Initial Messages:
// Load last 20 messages, then load more on scroll const { items: initialMessages } = await apiClient.getMessages(conversationId, 1, 20);
  1. Message Caching:
// Cache messages in IndexedDB for offline access await messageCache.set(conversationId, messages);

10. Security Considerations

10.1 Issues Identified

Issue 1: No CSRF Protection for WebSocket

Severity: Medium Impact: Potential cross-site WebSocket hijacking

Recommendation:

  • Use cryptographically random tokens
  • Validate Origin header on server
  • Implement Same-Site cookies

Issue 2: XSS Risk in Message Rendering

Severity: LOW (mitigated by react-markdown) Impact: Potential script injection in messages

Current Protection:

  • react-markdown sanitizes HTML by default
  • No dangerouslySetInnerHTML usage

Recommendation:

  • Keep using react-markdown
  • Add DOMPurify as additional layer
  • Validate message content on backend

Issue 3: No Rate Limiting in UI

Severity: Low Impact: User can spam messages

Recommendation:

const sendMessage = useRateLimited( (content: string) => { // ... send logic }, { maxCalls: 10, windowMs: 60000, // 10 messages per minute }, );

11. Accessibility (a11y) Review

11.1 Strengths ✅

  1. Semantic HTML:

    • Proper heading hierarchy
    • ARIA labels on interactive elements
    • Role attributes
  2. Keyboard Navigation:

    • Enter/Escape for rename operations
    • Tab navigation through conversations
    • Space/Enter to select conversations
  3. Screen Reader Support:

    • Descriptive labels
    • Status announcements (typing indicator)
    • Error messages are associated with inputs

11.2 Improvements Needed

  1. Live Regions for Messages:
<div role="log" aria-live="polite" aria-relevant="additions"> <MessageList messages={messages} /> </div>
  1. Skip Links:
<a href="#main-chat" className="sr-only focus:not-sr-only"> Skip to chat </a>
  1. Focus Management:
// Focus message input after sending useEffect(() => { if (connectionStatus === "connected") { inputRef.current?.focus(); } }, [connectionStatus]);

12. Documentation Review

12.1 Existing Documentation ✅

  • README.md - Comprehensive project overview
  • ARCHITECTURE_V2.md - System architecture
  • USER_GUIDE.md - End-user documentation
  • API_REFERENCE.md - API documentation
  • Test README files in test directories

12.2 Missing Documentation ⚠️

  1. WebSocket Protocol Specification:

    • Message format documentation
    • Error codes reference
    • Connection lifecycle
  2. Conversation Management API:

    • Endpoint documentation
    • Request/response examples
    • Error scenarios
  3. Development Guide:

    • Setup instructions for frontend
    • Environment variables reference
    • Testing guide

13. Priority Action Items

Critical (P0) 🔴

  1. Fix WebSocket Protocol Mismatch

    • Update backend to send 'chunk' instead of 'message_chunk'
    • Change message_id to messageId (camelCase)
    • Update 'message_complete' to 'message.done'
    • Estimated Effort: 2 hours
    • Files to Update:
      • /services/api-gateway/app/api/realtime.py
      • Update event types and field names
  2. Fix Client Message Type

    • Change 'message.send' to 'message'
    • Estimated Effort: 15 minutes
    • Files to Update:
      • /apps/web-app/src/hooks/useChatSession.ts
  3. Add WebSocket Authentication

    • Validate JWT token on WebSocket connection
    • Reject unauthorized connections
    • Estimated Effort: 1 hour
    • Files to Update:
      • /services/api-gateway/app/api/realtime.py
      • /services/api-gateway/app/core/dependencies.py

High (P1) 🟠

  1. Fix Last Message Preview

    • Verify backend populates field
    • Add database migration if needed
    • Update preview on new messages
    • Estimated Effort: 2 hours
  2. Fix Hardcoded WebSocket URL

    • Use environment variables
    • Add development/production configs
    • Estimated Effort: 30 minutes
  3. Add Error Recovery

    • Toast notifications for errors
    • Retry logic for transient failures
    • Estimated Effort: 2 hours

Medium (P2) 🟡

  1. Add Optimistic Updates

    • Implement for rename, archive, delete
    • Estimated Effort: 3 hours
  2. Add AbortController for API Calls

    • Cancel in-flight requests on navigation
    • Estimated Effort: 1 hour
  3. Add Conversation Management Tests

    • Unit tests for components
    • Integration tests for flows
    • Estimated Effort: 4 hours
  4. Add WebSocket Integration Tests

    • Protocol compliance tests
    • Error scenario tests
    • Estimated Effort: 4 hours

Low (P3) ⚪

  1. Add Pagination

    • Infinite scroll for conversations
    • Estimated Effort: 2 hours
  2. Add Rate Limiting UI

    • Prevent message spam
    • Estimated Effort: 1 hour
  3. Improve Accessibility

    • Live regions, focus management
    • Estimated Effort: 3 hours
  4. Add Documentation

    • WebSocket protocol spec
    • Development guide
    • Estimated Effort: 4 hours

14. Next Steps

Immediate Actions

  1. ✅ Create review document (this file)
  2. ⏳ Create git branch fix/system-review-and-testing
  3. ⏳ Fix critical WebSocket issues (P0)
  4. ⏳ Add WebSocket integration tests
  5. ⏳ Manual testing in browser
  6. ⏳ Document test results
  7. ⏳ Create pull request

Testing Plan

Manual Testing Checklist:

  • Create new conversation
  • Send messages and verify streaming
  • Rename conversation
  • Archive conversation
  • Delete conversation
  • Navigate between conversations
  • Test WebSocket reconnection (disable network)
  • Test error scenarios (invalid conversation ID)
  • Test on multiple browsers (Chrome, Firefox, Safari)
  • Test keyboard navigation
  • Test screen reader compatibility

Automated Testing Plan:

  • Write ConversationList tests
  • Write WebSocket integration tests
  • Add E2E tests for full chat flow
  • Run all existing tests
  • Achieve >90% code coverage

Documentation Plan

  • Document WebSocket protocol
  • Update API reference
  • Create development setup guide
  • Document known issues and workarounds

15. Conclusion

The VoiceAssist web application has a solid foundation with good architecture, type safety, and separation of concerns. However, there are critical issues with the WebSocket protocol implementation that prevent the chat from functioning correctly.

Key Findings:

  • ✅ Conversation management is well-implemented
  • ⚠️ WebSocket protocol mismatch between frontend/backend
  • ❌ No WebSocket authentication
  • ⚠️ Last message preview may not be populated
  • ✅ Good test coverage for components
  • ⚠️ Missing integration tests for WebSocket

Recommendation: Fix critical WebSocket issues immediately (P0 items) to enable basic chat functionality, then proceed with testing and validation.


Review Completed: 2025-11-22 Next Review: After P0 fixes are implemented

Beginning of guide
End of guide