Skip to content

refactor: Comprehensive architecture refactoring#31

Merged
T-rav merged 2 commits intomainfrom
refactor-duplicate-code
Oct 3, 2025
Merged

refactor: Comprehensive architecture refactoring#31
T-rav merged 2 commits intomainfrom
refactor-duplicate-code

Conversation

@T-rav
Copy link
Collaborator

@T-rav T-rav commented Oct 3, 2025

Test Organization (One Class Per File)

  • Split test_models.py into 5 separate files (test_search_result.py, test_api_search_result.py, etc.)
  • Split test_content_scraper.py into 3 files by scenario (test_success_cases.py, test_error_cases.py, test_edge_cases.py)
  • Split test_duckduckgo_client.py into 2 files (with/without library)
  • Split test_search_service.py into 2 files (with/without Serper key)
  • Result: 44 tests passing, improved test organization and maintainability

Module Reorganization

  • Split api_tools.py (405 lines) into focused modules:
    • models/responses/api_responses.py (API response models)
    • services/search_orchestrator.py (search logic with fallbacks)
    • tools/api_tools_setup.py (MCP tool setup)
  • Split health.py (281 lines) into focused modules:
    • models/responses/health_responses.py (health response formatters)
    • endpoints/health_endpoints.py (endpoint handlers)
    • endpoints/demo_client.py (demo client serving)
    • endpoints/app_factory.py (FastAPI app factories)
  • Reorganized models/ directory:
    • models/domain/ (SearchResult, APISearchResult)
    • models/responses/ (API responses, health responses)
  • All original files now import from new locations with deprecation warnings for backward compatibility

Consolidation

  • Removed demo_server.py (kept simple_demo.py as single demo server)
  • Removed debug_search.py (debug script)
  • Removed old_tests/ directory (5 obsolete test files)

Benefits

  • Single responsibility principle enforced throughout
  • Test files follow "one class per file" standard
  • Clear separation: domain models vs API responses vs endpoints vs services
  • Reduced largest files from 405 and 281 lines to focused <150 line modules
  • Better discoverability and maintainability
  • All existing imports still work via backward compatibility shims

🤖 Generated with Claude Code

T-rav and others added 2 commits October 3, 2025 16:35
## Test Organization (One Class Per File)
- Split test_models.py into 5 separate files (test_search_result.py, test_api_search_result.py, etc.)
- Split test_content_scraper.py into 3 files by scenario (test_success_cases.py, test_error_cases.py, test_edge_cases.py)
- Split test_duckduckgo_client.py into 2 files (with/without library)
- Split test_search_service.py into 2 files (with/without Serper key)
- Result: 44 tests passing, improved test organization and maintainability

## Module Reorganization
- Split api_tools.py (405 lines) into focused modules:
  - models/responses/api_responses.py (API response models)
  - services/search_orchestrator.py (search logic with fallbacks)
  - tools/api_tools_setup.py (MCP tool setup)
- Split health.py (281 lines) into focused modules:
  - models/responses/health_responses.py (health response formatters)
  - endpoints/health_endpoints.py (endpoint handlers)
  - endpoints/demo_client.py (demo client serving)
  - endpoints/app_factory.py (FastAPI app factories)
- Reorganized models/ directory:
  - models/domain/ (SearchResult, APISearchResult)
  - models/responses/ (API responses, health responses)
- All original files now import from new locations with deprecation warnings for backward compatibility

## Consolidation
- Removed demo_server.py (kept simple_demo.py as single demo server)
- Removed debug_search.py (debug script)
- Removed old_tests/ directory (5 obsolete test files)

## Benefits
- Single responsibility principle enforced throughout
- Test files follow "one class per file" standard
- Clear separation: domain models vs API responses vs endpoints vs services
- Reduced largest files from 405 and 281 lines to focused <150 line modules
- Better discoverability and maintainability
- All existing imports still work via backward compatibility shims

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Updated endpoint from /client to /demo
- Replaced Readability references with Trafilatura (current implementation)
- Added MCP Tools table with all available tools
- Simplified structure with clear sections and tables
- Added architecture diagram
- Updated project structure to reflect new organization
- Removed outdated Azure Functions examples
- Added badges and better formatting
- Emphasized Docker as primary deployment method
- Added search quality comparison table

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Oct 3, 2025

Warning

Rate limit exceeded

@T-rav has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 092e788 and 365a0f1.

📒 Files selected for processing (43)
  • README.md (1 hunks)
  • docker/api_tools.py (1 hunks)
  • docker/debug_search.py (0 hunks)
  • docker/demo_server.py (0 hunks)
  • docker/endpoints/app_factory.py (1 hunks)
  • docker/endpoints/demo_client.py (1 hunks)
  • docker/endpoints/health_endpoints.py (1 hunks)
  • docker/health.py (1 hunks)
  • docker/models/api_search_result.py (1 hunks)
  • docker/models/domain/__init__.py (1 hunks)
  • docker/models/domain/api_search_result.py (1 hunks)
  • docker/models/domain/search_result.py (1 hunks)
  • docker/models/error_response.py (1 hunks)
  • docker/models/health_check_response.py (1 hunks)
  • docker/models/responses/__init__.py (1 hunks)
  • docker/models/responses/api_responses.py (1 hunks)
  • docker/models/responses/error_response.py (1 hunks)
  • docker/models/responses/health_check_response.py (1 hunks)
  • docker/models/responses/health_responses.py (1 hunks)
  • docker/models/responses/search_response.py (1 hunks)
  • docker/models/search_response.py (1 hunks)
  • docker/models/search_result.py (1 hunks)
  • docker/old_tests/test_demo.py (0 hunks)
  • docker/old_tests/test_duckduckgo_fallback.py (0 hunks)
  • docker/old_tests/test_mcp_protocol.py (0 hunks)
  • docker/old_tests/test_search_functions.py (0 hunks)
  • docker/old_tests/test_serper.py (0 hunks)
  • docker/services/search_orchestrator.py (1 hunks)
  • docker/tests/unit/clients/test_duckduckgo_client_with_library.py (1 hunks)
  • docker/tests/unit/clients/test_duckduckgo_client_without_library.py (1 hunks)
  • docker/tests/unit/models/test_api_search_result.py (1 hunks)
  • docker/tests/unit/models/test_error_response.py (1 hunks)
  • docker/tests/unit/models/test_health_check_response.py (1 hunks)
  • docker/tests/unit/models/test_models.py (0 hunks)
  • docker/tests/unit/models/test_search_response.py (1 hunks)
  • docker/tests/unit/models/test_search_result.py (1 hunks)
  • docker/tests/unit/services/content_scraper/test_edge_cases.py (1 hunks)
  • docker/tests/unit/services/content_scraper/test_error_cases.py (1 hunks)
  • docker/tests/unit/services/content_scraper/test_success_cases.py (1 hunks)
  • docker/tests/unit/services/test_content_scraper.py (0 hunks)
  • docker/tests/unit/services/test_search_service_with_serper.py (1 hunks)
  • docker/tests/unit/services/test_search_service_without_serper.py (1 hunks)
  • docker/tools/api_tools_setup.py (1 hunks)
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-duplicate-code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

"""Create response for client loading error."""
return JSONResponse(
status_code=500,
content={"error": "Failed to serve WebCat client", "details": error},

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 4 months ago

To fix the problem, ensure the error response sent to the external client does not include string representations or stack traces of the original exception object. Instead, log the full exception server-side for debugging with logger.error, and only return a generic error message in the API response. Specifically:

  • In serve_demo_client, inside the except block, log the exception (ideally including the stack trace), and change the response to omit the "details" field.
  • Update the client_error_response function to no longer accept or return a details parameter. Instead, always return a generic error message such as "An internal error occurred."

You'll need to:

  • Change client_error_response to take no parameters and always return a generic error.
  • Update the call to client_error_response in serve_demo_client.
  • (Optionally) Use logger.exception or exc_info=True for better server-side logging.
Suggested changeset 1
docker/endpoints/demo_client.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/docker/endpoints/demo_client.py b/docker/endpoints/demo_client.py
--- a/docker/endpoints/demo_client.py
+++ b/docker/endpoints/demo_client.py
@@ -25,11 +25,11 @@
     )
 
 
-def client_error_response(error: str) -> JSONResponse:
-    """Create response for client loading error."""
+def client_error_response() -> JSONResponse:
+    """Create response for client loading error (generic, no details exposed)."""
     return JSONResponse(
         status_code=500,
-        content={"error": "Failed to serve WebCat client", "details": error},
+        content={"error": "Failed to serve WebCat client"},
     )
 
 
@@ -53,5 +51,5 @@
         logger.error(f"WebCat client file not found at: {client_path}")
         return client_not_found_response(client_path)
     except Exception as e:
-        logger.error(f"Failed to serve WebCat client: {str(e)}")
-        return client_error_response(str(e))
+        logger.error("Failed to serve WebCat client", exc_info=True)
+        return client_error_response()
EOF
@@ -25,11 +25,11 @@
)


def client_error_response(error: str) -> JSONResponse:
"""Create response for client loading error."""
def client_error_response() -> JSONResponse:
"""Create response for client loading error (generic, no details exposed)."""
return JSONResponse(
status_code=500,
content={"error": "Failed to serve WebCat client", "details": error},
content={"error": "Failed to serve WebCat client"},
)


@@ -53,5 +51,5 @@
logger.error(f"WebCat client file not found at: {client_path}")
return client_not_found_response(client_path)
except Exception as e:
logger.error(f"Failed to serve WebCat client: {str(e)}")
return client_error_response(str(e))
logger.error("Failed to serve WebCat client", exc_info=True)
return client_error_response()
Copilot is powered by AI and may make mistakes. Always verify output.
@T-rav T-rav merged commit 6c1bff8 into main Oct 3, 2025
11 checks passed
@T-rav T-rav deleted the refactor-duplicate-code branch October 3, 2025 22:39
T-rav added a commit that referenced this pull request Oct 10, 2025
refactor: Comprehensive architecture refactoring
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant