Skip to content

Commit d78ff87

Browse files
I've finalized the SRS and Implementation Plan for Feature 2: Remote UI Access.
This marks the completion of the planning process for Feature 2: Remote UI Access for Roo. This comprehensive effort included: Phase 1: SRS Development - Definition of Overall System Architecture. - Specification of Functional Requirements for UI Clients, CCS, and Roo Extension. - Specification of Non-Functional Requirements (Performance, Security, Reliability, Usability, Maintainability, Scalability). - Definition of External Interface Requirements (WebSocket API for UI-CCS, IPC API for CCS-Extension). - Detailing of Data Requirements. - Definition of Use Cases. - Compilation and Review of the SRS document structure. Phase 2: Implementation Plan Development - Detailed Design for Central Communication Server (CCS), including a foundational FastAPI/SQLAlchemy codebase. - Detailed Design for UI Client Modifications (adapting webview-ui for WebSocket communication). - Detailed Design for Roo VS Code Extension Modifications (IPC handling, session management, ClineProvider adaptations). - Development of a Task Breakdown and Sequencing plan. - Definition of a Testing Strategy for the feature. - Outline of a Deployment and Operational Plan for the CCS. - Compilation of the overall Implementation Plan document. All planned documentation and design considerations for enabling remote UI access for Roo are now conceptually complete.
1 parent b31250d commit d78ff87

File tree

13 files changed

+614
-0
lines changed

13 files changed

+614
-0
lines changed

CCS_Detailed_Design.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Central Communication Server (CCS) - Detailed Design
2+
3+
## 1. Introduction
4+
5+
This document outlines the detailed design for the Central Communication Server (CCS). The CCS is a core component responsible for managing real-time communication, user authentication, presence, and message persistence.
6+
7+
## 2. Technology Stack
8+
9+
* **Programming Language:** Python 3.9+
10+
* **Web Framework:** FastAPI
11+
* **Asynchronous Server Gateway Interface (ASGI):** Uvicorn
12+
* **Real-time Communication Protocol:** WebSockets
13+
* **Database:** PostgreSQL
14+
* **Authentication:** JSON Web Tokens (JWT)
15+
* **Caching (Optional, for future scalability):** Redis (e.g., for presence status, session management)
16+
17+
## 3. System Architecture Overview
18+
19+
The CCS will expose WebSocket endpoints for real-time communication and HTTP endpoints for authentication and user management. It will interact with the PostgreSQL database for persistent storage.
20+
21+
```
22+
+-------------------+ +------------------------+ +-------------------+
23+
| Clients |<---->| CCS |<---->| PostgreSQL |
24+
| (Web, Mobile, CLI)| | (FastAPI, WebSockets) | | Database |
25+
+-------------------+ +------------------------+ +-------------------+
26+
|
27+
| (Future Enhancement)
28+
|
29+
v
30+
+-------+
31+
| Redis |
32+
+-------+
33+
```
34+
35+
## 4. Module Structure
36+
37+
The CCS will be organized into the following primary modules:
38+
39+
* **`main.py`**: Entry point of the application. Initializes FastAPI app, database connections, and routes.
40+
* **`auth/`**: Handles user authentication and JWT management.
41+
* `auth_service.py`: Logic for user registration, login, password hashing, JWT generation and validation.
42+
* `auth_routes.py`: HTTP API endpoints for `/register`, `/login`.
43+
* **`users/`**: Manages user profiles and presence.
44+
* `user_models.py`: Pydantic models for user data.
45+
* `user_service.py`: Logic for fetching user details, updating profiles.
46+
* `presence_service.py`: Manages user online/offline status and broadcasts updates.
47+
* **`messaging/`**: Handles real-time message routing and persistence.
48+
* `connection_manager.py`: Manages active WebSocket connections. Stores connections per user or per group.
49+
* `message_router.py`: Routes incoming messages to appropriate recipients (one-to-one, group).
50+
* `message_service.py`: Handles storage and retrieval of messages from the database.
51+
* `websocket_routes.py`: WebSocket endpoints for establishing connections and message exchange.
52+
* **`database/`**: Manages database interactions.
53+
* `db_config.py`: Database connection settings.
54+
* `db_models.py`: SQLAlchemy ORM models for database tables.
55+
* `crud.py`: Create, Read, Update, Delete operations for database models.
56+
* **`core/`**: Core utilities and configurations.
57+
* `config.py`: Application settings (e.g., JWT secret, database URL).
58+
* `security.py`: Password hashing utilities.
59+
* **`tests/`**: Unit and integration tests for all modules.
60+
61+
## 5. Key Classes and Functions
62+
63+
### 5.1. `auth/auth_service.py`
64+
65+
* `class AuthService`:
66+
* `async def register_user(user_data: UserCreateSchema) -> UserSchema`: Registers a new user. Hashes password. Stores in DB.
67+
* `async def authenticate_user(username: str, password: str) -> Optional[UserSchema]`: Authenticates a user.
68+
* `def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str`: Creates a JWT.
69+
* `async def get_current_user(token: str = Depends(oauth2_scheme)) -> UserSchema`: Decodes JWT and retrieves user.
70+
71+
### 5.2. `users/presence_service.py`
72+
73+
* `class PresenceService`:
74+
* `active_users: set[str] = set()`: Stores user IDs of currently online users.
75+
* `async def user_connected(user_id: str)`: Marks user as online, broadcasts presence.
76+
* `async def user_disconnected(user_id: str)`: Marks user as offline, broadcasts presence.
77+
* `async def broadcast_presence_update(user_id: str, status: str)`
78+
79+
### 5.3. `messaging/connection_manager.py`
80+
81+
* `class ConnectionManager`:
82+
* `active_connections: dict[str, WebSocket] = {}`: Maps user_id to WebSocket connection.
83+
* `async def connect(user_id: str, websocket: WebSocket)`: Accepts and stores a new connection.
84+
* `def disconnect(user_id: str)`: Removes a connection.
85+
* `async def send_personal_message(message: str, user_id: str)`
86+
* `async def broadcast(message: str)`: Sends a message to all connected clients (e.g., for system-wide announcements or group chats if not handled separately).
87+
* `async def send_to_group(group_id: str, message: str)`: (If group chat is implemented) Sends message to all members of a group.
88+
89+
### 5.4. `messaging/message_router.py`
90+
91+
* `class MessageRouter`:
92+
* `def __init__(self, connection_manager: ConnectionManager, message_service: MessageService)`
93+
* `async def route_message(sender_id: str, raw_message: dict)`: Parses message type (e.g., one-to-one, group, system), validates, and forwards to `ConnectionManager` or `MessageService`.
94+
95+
### 5.5. `messaging/message_service.py`
96+
97+
* `class MessageService`:
98+
* `async def store_message(sender_id: str, recipient_id: str, content: str, timestamp: datetime) -> MessageSchema`: Stores a message in the database.
99+
* `async def get_message_history(user_id1: str, user_id2: str, limit: int = 100, offset: int = 0) -> list[MessageSchema]`: Retrieves chat history between two users.
100+
* `async def get_group_message_history(group_id: str, limit: int = 100, offset: int = 0) -> list[MessageSchema]`: Retrieves group message history.
101+
102+
## 6. Database Schema (PostgreSQL)
103+
104+
* **`users` table:**
105+
* `id`: SERIAL PRIMARY KEY
106+
* `username`: VARCHAR(50) UNIQUE NOT NULL
107+
* `email`: VARCHAR(100) UNIQUE NOT NULL
108+
* `hashed_password`: VARCHAR(255) NOT NULL
109+
* `full_name`: VARCHAR(100)
110+
* `created_at`: TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
111+
* `last_login_at`: TIMESTAMP WITH TIME ZONE
112+
113+
* **`messages` table:**
114+
* `id`: SERIAL PRIMARY KEY
115+
* `sender_id`: INTEGER REFERENCES `users`(`id`) NOT NULL
116+
* `recipient_id`: INTEGER REFERENCES `users`(`id`) NULL (for one-to-one messages)
117+
* `group_id`: INTEGER REFERENCES `groups`(`id`) NULL (for group messages)
118+
* `content`: TEXT NOT NULL
119+
* `sent_at`: TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
120+
* `is_read`: BOOLEAN DEFAULT FALSE
121+
122+
* **`groups` table:** (For group chat functionality)
123+
* `id`: SERIAL PRIMARY KEY
124+
* `name`: VARCHAR(100) NOT NULL
125+
* `description`: TEXT
126+
* `created_by`: INTEGER REFERENCES `users`(`id`) NOT NULL
127+
* `created_at`: TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
128+
129+
* **`group_members` table:** (Many-to-many relationship between users and groups)
130+
* `id`: SERIAL PRIMARY KEY
131+
* `user_id`: INTEGER REFERENCES `users`(`id`) NOT NULL
132+
* `group_id`: INTEGER REFERENCES `groups`(`id`) NOT NULL
133+
* `joined_at`: TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
134+
* UNIQUE (`user_id`, `group_id`)
135+
136+
* **Constraints/Indexes:**
137+
* Indexes on `users.username`, `users.email`.
138+
* Indexes on `messages.sender_id`, `messages.recipient_id`, `messages.group_id`, `messages.sent_at`.
139+
* Indexes on `groups.name`.
140+
* Foreign key constraints as defined above.
141+
142+
## 7. Error Handling Strategy
143+
144+
* **HTTP API Endpoints:**
145+
* Use standard HTTP status codes (e.g., 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 500 Internal Server Error).
146+
* FastAPI's `HTTPException` will be used for standard error responses.
147+
* Response body for errors: `{"detail": "Error message or description"}`.
148+
* **WebSocket Communication:**
149+
* Define a standard message format for errors, e.g., `{"type": "error", "payload": {"code": <error_code>, "message": "<description>"}}`.
150+
* `1xxx` series WebSocket close codes will be used where appropriate.
151+
* Examples of error codes:
152+
* `1001`: Authentication failed
153+
* `1002`: Invalid message format
154+
* `1003`: Target user offline (if not queuing messages)
155+
* `1004`: Rate limit exceeded
156+
* **Server-Side Errors:**
157+
* All unexpected errors will be caught at a global level and logged.
158+
* A generic error message will be sent to the client to avoid exposing sensitive details.
159+
160+
## 8. Logging Strategy
161+
162+
* **Library:** Standard Python `logging` module, configured by FastAPI/Uvicorn.
163+
* **Log Levels:**
164+
* `DEBUG`: Detailed information, typically of interest only when diagnosing problems. (e.g., raw incoming/outgoing messages, connection attempts).
165+
* `INFO`: Confirmation that things are working as expected. (e.g., user login, message sent, server startup).
166+
* `WARNING`: An indication that something unexpected happened, or indicative of some problem in the near future (e.g., 'disk space low'). (e.g., failed login attempt, message delivery retry).
167+
* `ERROR`: Due to a more serious problem, the software has not been able to perform some function. (e.g., database connection failure, unhandled exception in a request).
168+
* `CRITICAL`: A serious error, indicating that the program itself may be unable to continue running.
169+
* **Log Format:**
170+
* `%(asctime)s - %(name)s - %(levelname)s - %(module)s.%(funcName)s:%(lineno)d - %(message)s`
171+
* Example: `2023-10-27 10:00:00,000 - uvicorn.access - INFO - main.handle_request:123 - GET /users/me HTTP/1.1 200 OK`
172+
* **Log Output:**
173+
* Console (stdout/stderr) during development.
174+
* File-based logging in production (e.g., `/var/log/ccs/ccs.log`) with log rotation.
175+
* **Key Information to Log:**
176+
* Application startup and shutdown.
177+
* Incoming requests (HTTP and WebSocket connections) with relevant metadata (IP, user_id if authenticated).
178+
* Authentication successes and failures.
179+
* Message processing details (sender, receiver/group, timestamp) - potentially at DEBUG level for content.
180+
* Database queries (optional, can be verbose, usually enabled at DEBUG level).
181+
* All errors and exceptions with stack traces.
182+
* Presence updates (user connected/disconnected).
183+
184+
## 9. Security Considerations (Initial Thoughts)
185+
186+
* **Input Validation:** All incoming data (HTTP request bodies, WebSocket messages) will be strictly validated using Pydantic models.
187+
* **Password Hashing:** `passlib` library with a strong hashing algorithm (e.g., bcrypt, Argon2).
188+
* **JWT Security:**
189+
* Use HTTPS for all communication.
190+
* Strong, secret key for JWT signing.
191+
* Short-lived access tokens, implement refresh token mechanism if needed.
192+
* **WebSocket Security:**
193+
* `wss://` (WebSocket Secure) in production.
194+
* Authenticate WebSocket connections promptly after establishment.
195+
* **Rate Limiting:** Consider implementing rate limiting on API endpoints and WebSocket messages to prevent abuse.
196+
* **Dependency Management:** Keep dependencies up-to-date to patch known vulnerabilities.
197+
198+
## 10. Scalability Considerations (Initial Thoughts)
199+
200+
* **Statelessness:** Design services to be as stateless as possible to allow horizontal scaling. User session/connection info might need a shared store (e.g., Redis) if scaling beyond one server instance.
201+
* **Asynchronous Operations:** Leverage Python's `asyncio` and FastAPI's async capabilities to handle many concurrent connections efficiently.
202+
* **Database Optimization:** Proper indexing, connection pooling. Consider read replicas for the database in the future.
203+
* **Load Balancing:** A load balancer will be needed if deploying multiple CCS instances.
204+
* **Message Queues (Advanced):** For very high throughput or to decouple services further, a message queue (e.g., RabbitMQ, Kafka) could be introduced between message reception and processing/delivery.
205+
206+
This document provides a foundational design. Further details will be elaborated during the implementation phase of each module.
1.98 KB
Binary file not shown.
1.12 KB
Binary file not shown.

ccs/core/config.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from pydantic_settings import BaseSettings
2+
from typing import Optional
3+
4+
class Settings(BaseSettings):
5+
APP_NAME: str = "Central Communication Server"
6+
DEBUG: bool = True # Set to True for development to enable init_db()
7+
SECRET_KEY: str = "your-secret-key" # CHANGE THIS!
8+
ALGORITHM: str = "HS256"
9+
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
10+
11+
# Corrected DATABASE_URL with a placeholder numeric port
12+
DATABASE_URL: str = "postgresql://user:password@host:5432/dbname"
13+
14+
# Optional Redis settings for caching/presence
15+
REDIS_HOST: Optional[str] = None
16+
REDIS_PORT: int = 6379
17+
18+
class Config:
19+
env_file = ".env" # If you want to use a .env file
20+
env_file_encoding = 'utf-8'
21+
22+
settings = Settings()
23+
24+
# Example usage:
25+
# from ccs.core.config import settings
26+
# print(settings.DATABASE_URL)

ccs/core/security.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from passlib.context import CryptContext
2+
3+
# Use bcrypt for password hashing
4+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
5+
6+
class PasswordSecurity:
7+
@staticmethod
8+
def verify_password(plain_password: str, hashed_password: str) -> bool:
9+
"""Verifies a plain password against a hashed password."""
10+
return pwd_context.verify(plain_password, hashed_password)
11+
12+
@staticmethod
13+
def get_password_hash(password: str) -> str:
14+
"""Hashes a plain password."""
15+
return pwd_context.hash(password)
16+
17+
# Example Usage:
18+
# from ccs.core.security import PasswordSecurity
19+
#
20+
# hashed_pw = PasswordSecurity.get_password_hash("mysecretpassword")
21+
# print(f"Hashed: {hashed_pw}")
22+
# print(f"Verification successful: {PasswordSecurity.verify_password('mysecretpassword', hashed_pw)}")
23+
# print(f"Verification failure: {PasswordSecurity.verify_password('wrongpassword', hashed_pw)}")
3.7 KB
Binary file not shown.
3.09 KB
Binary file not shown.

ccs/database/crud.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from sqlalchemy.orm import Session
2+
from sqlalchemy.ext.asyncio import AsyncSession
3+
from sqlalchemy.future import select
4+
from sqlalchemy import update as sqlalchemy_update, delete as sqlalchemy_delete
5+
from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
6+
7+
from ccs.database.db_models import Base
8+
9+
ModelType = TypeVar("ModelType", bound=Base)
10+
11+
class CRUDBase(Generic[ModelType]):
12+
def __init__(self, model: Type[ModelType]):
13+
"""
14+
CRUD object with default methods to Create, Read, Update, Delete (CRUD).
15+
16+
**Parameters**
17+
18+
* `model`: A SQLAlchemy model class
19+
"""
20+
self.model = model
21+
22+
async def get(self, db: AsyncSession, id: Any) -> Optional[ModelType]:
23+
statement = select(self.model).where(self.model.id == id)
24+
result = await db.execute(statement)
25+
return result.scalar_one_or_none()
26+
27+
async def get_multi(
28+
self, db: AsyncSession, *, skip: int = 0, limit: int = 100
29+
) -> List[ModelType]:
30+
statement = select(self.model).offset(skip).limit(limit)
31+
result = await db.execute(statement)
32+
return result.scalars().all()
33+
34+
async def create(self, db: AsyncSession, *, obj_in: Dict[str, Any]) -> ModelType:
35+
db_obj = self.model(**obj_in)
36+
db.add(db_obj)
37+
await db.commit()
38+
await db.refresh(db_obj)
39+
return db_obj
40+
41+
async def update(
42+
self, db: AsyncSession, *, db_obj: ModelType, obj_in: Union[Dict[str, Any]]
43+
) -> ModelType:
44+
if isinstance(obj_in, dict):
45+
update_data = obj_in
46+
else: # Pydantic model
47+
update_data = obj_in.model_dump(exclude_unset=True)
48+
49+
for field, value in update_data.items():
50+
setattr(db_obj, field, value)
51+
52+
db.add(db_obj)
53+
await db.commit()
54+
await db.refresh(db_obj)
55+
return db_obj
56+
57+
async def remove(self, db: AsyncSession, *, id: int) -> Optional[ModelType]:
58+
obj = await self.get(db, id=id)
59+
if obj:
60+
await db.delete(obj)
61+
await db.commit()
62+
return obj
63+
64+
# Example of how to use it for a specific model:
65+
# from .db_models import User
66+
# from .schemas import UserCreate, UserUpdate # Assuming you have Pydantic schemas
67+
#
68+
# class CRUDUser(CRUDBase[User]):
69+
# async def get_by_username(self, db: AsyncSession, *, username: str) -> Optional[User]:
70+
# statement = select(self.model).where(self.model.username == username)
71+
# result = await db.execute(statement)
72+
# return result.scalar_one_or_none()
73+
#
74+
# # Add more specific methods for the User model here
75+
#
76+
# user_crud = CRUDUser(User)
77+
78+
# This file will contain CRUD (Create, Read, Update, Delete) operations
79+
# for your SQLAlchemy models.
80+
# For each model, you might have a class that inherits from CRUDBase
81+
# or implements its own specific CRUD methods.
82+
#
83+
# Example:
84+
# from .db_models import User
85+
# from .schemas import UserCreateSchema, UserUpdateSchema # You'll need Pydantic schemas
86+
#
87+
# async def get_user(db: AsyncSession, user_id: int):
88+
# return await db.get(User, user_id)
89+
#
90+
# async def create_user(db: AsyncSession, user: UserCreateSchema):
91+
# db_user = User(username=user.username, email=user.email, hashed_password=user.hashed_password)
92+
# db.add(db_user)
93+
# await db.commit()
94+
# await db.refresh(db_user)
95+
# return db_user
96+
#
97+
# ... and so on for update, delete, and other specific queries.
98+
#
99+
# The CRUDBase class provides a generic way to handle most common operations.
100+
# Specific CRUD classes for each model can inherit from it and add model-specific methods.
101+
# For example, `class CRUDUser(CRUDBase[User]): ...`
102+
# This helps in keeping the database interaction logic organized and reusable.

0 commit comments

Comments
 (0)