mirror of
https://github.com/wahyd4/hey-search.git
synced 2026-08-08 21:05:14 +10:00
Add justfile
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# Agents
|
||||
|
||||
This file describes the project structure and conventions for AI coding agents working on Hey Search.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Hey Search is a privacy-respecting metasearch engine that aggregates results from multiple upstream search engines (Brave, DuckDuckGo, Google, Bing). It has a Python/FastAPI backend and a React/TypeScript frontend.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
hey-search/
|
||||
├── backend/ # Python FastAPI backend
|
||||
│ ├── pyproject.toml # uv/Python dependencies
|
||||
│ ├── uv.lock # Lockfile
|
||||
│ └── app/
|
||||
│ ├── main.py # FastAPI app entry point, lifespan, CORS, static mount
|
||||
│ ├── models.py # Pydantic models (WebResult, ImageResult, SearchResponse, EngineInfo, etc.)
|
||||
│ ├── search.py # Search orchestrator — concurrent engine queries, retry, dedup
|
||||
│ ├── api/
|
||||
│ │ └── routes.py # REST endpoints: /search, /autocomplete, /engines
|
||||
│ └── engines/
|
||||
│ ├── base.py # Abstract SearchEngine class, shared httpx AsyncClient
|
||||
│ ├── registry.py # Engine registry — load, enable/disable, list
|
||||
│ ├── brave.py # Brave Search (web + images)
|
||||
│ ├── duckduckgo.py# DuckDuckGo (web + images)
|
||||
│ ├── google.py # Google (web + images)
|
||||
│ └── bing.py # Bing (web + images)
|
||||
├── frontend/ # React + Vite + TypeScript frontend
|
||||
│ ├── package.json
|
||||
│ ├── vite.config.ts # Vite config with Tailwind plugin and /api proxy
|
||||
│ ├── index.html
|
||||
│ └── src/
|
||||
│ ├── main.tsx # React entry point
|
||||
│ ├── App.tsx # Main app — home page, results page, routing between them
|
||||
│ ├── index.css # Tailwind CSS with shadcn theme variables
|
||||
│ ├── lib/
|
||||
│ │ ├── api.ts # API client — search, autocomplete, engines CRUD
|
||||
│ │ └── utils.ts # cn() helper (clsx + tailwind-merge)
|
||||
│ ├── hooks/
|
||||
│ │ └── useAutocomplete.ts # Debounced autocomplete hook
|
||||
│ └── components/
|
||||
│ ├── SearchBar.tsx # Search input with autocomplete dropdown
|
||||
│ ├── WebResults.tsx # Web results list (favicons, badges, snippets)
|
||||
│ ├── ImageResults.tsx # Image grid + lightbox viewer
|
||||
│ ├── EngineSettings.tsx # Modal to toggle engines on/off
|
||||
│ └── ErrorToast.tsx # Toast notifications for engine failures
|
||||
├── Dockerfile # Multi-stage: Node frontend build → Python runtime
|
||||
├── .dockerignore
|
||||
├── .gitignore
|
||||
├── README.md
|
||||
├── FEATURES.md
|
||||
└── CHANGELOG.md
|
||||
```
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Layer | Technology |
|
||||
| -------- | ----------------------------------------------- |
|
||||
| Backend | Python 3.12+, FastAPI, uvicorn, httpx, Pydantic |
|
||||
| Retry | tenacity (exponential backoff, 2 attempts) |
|
||||
| Parsing | lxml, BeautifulSoup4 |
|
||||
| Frontend | React 19, TypeScript, Vite |
|
||||
| Styling | Tailwind CSS 4, shadcn theme, lucide-react icons |
|
||||
| Packages | uv (backend), npm (frontend) |
|
||||
| Docker | Multi-stage (node:20-slim → python:3.12-slim) |
|
||||
|
||||
## Key Conventions
|
||||
|
||||
### Backend
|
||||
|
||||
- **Dependency management**: Use `uv` (not pip). Run `uv sync` to install, `uv run` to execute.
|
||||
- **Engine pattern**: Each engine extends `SearchEngine` (in `engines/base.py`) and implements `search_web()`, `search_images()`, and optionally `autocomplete()`.
|
||||
- **Shared HTTP client**: All engines use `get_http_client()` from `base.py` — a single `httpx.AsyncClient` instance with sensible defaults.
|
||||
- **Registry**: Engines are registered in `engines/registry.py`. Add new engines there in `load_default_engines()`.
|
||||
- **Retry**: The search orchestrator in `search.py` wraps engine calls with tenacity retry (2 attempts, exponential backoff). Individual engines should raise on failure rather than swallowing errors.
|
||||
- **Models**: All API request/response shapes are Pydantic models in `models.py`.
|
||||
- **API docs**: FastAPI auto-generates OpenAPI spec. Swagger UI at `/docs`, Redoc at `/redoc`.
|
||||
|
||||
### Frontend
|
||||
|
||||
- **Mobile-first**: All components are designed mobile-first, then scale up with Tailwind responsive breakpoints.
|
||||
- **Path aliases**: Use `@/` to import from `src/` (configured in vite.config.ts and tsconfig.app.json).
|
||||
- **Styling**: Use Tailwind utility classes with `cn()` for conditional classes. Theme colors reference CSS variables from `index.css`.
|
||||
- **API layer**: All backend calls go through `src/lib/api.ts`. Components never call `fetch()` directly.
|
||||
- **State**: App state lives in `App.tsx` via `useState`. No external state management library.
|
||||
|
||||
### Adding a New Search Engine
|
||||
|
||||
1. Create `backend/app/engines/<name>.py` implementing `SearchEngine`
|
||||
2. Register it in `backend/app/engines/registry.py` → `load_default_engines()`
|
||||
3. No frontend changes needed — the engine appears automatically in the settings modal
|
||||
|
||||
## Running Locally
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd backend && uv sync && uv run uvicorn app.main:app --reload --port 8000
|
||||
|
||||
# Frontend (separate terminal)
|
||||
cd frontend && npm install && npm run dev
|
||||
|
||||
# Docker (production)
|
||||
docker build -t hey-search . && docker run -p 8000:8000 hey-search
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | -------------------------- | ------------------------ |
|
||||
| GET | `/api/search` | Metasearch (web/images) |
|
||||
| GET | `/api/autocomplete` | Search suggestions |
|
||||
| GET | `/api/engines` | List engines |
|
||||
| PUT | `/api/engines/{name}` | Toggle engine on/off |
|
||||
| GET | `/docs` | Swagger UI |
|
||||
| GET | `/redoc` | Redoc API docs |
|
||||
@@ -0,0 +1,48 @@
|
||||
# Hey Search — development commands
|
||||
|
||||
set dotenv-load := false
|
||||
|
||||
# List available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Install all dependencies
|
||||
install:
|
||||
cd backend && uv sync
|
||||
cd frontend && npm install
|
||||
|
||||
# Start backend only
|
||||
backend:
|
||||
cd backend && uv run uvicorn app.main:app --reload --port 8000
|
||||
|
||||
# Start frontend only
|
||||
frontend:
|
||||
cd frontend && npm run dev
|
||||
|
||||
# Start both backend and frontend (Ctrl+C stops everything)
|
||||
dev:
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
trap 'echo "Shutting down..."; kill 0; wait' INT TERM
|
||||
cd backend && uv run uvicorn app.main:app --reload --port 8000 &
|
||||
cd frontend && npm run dev &
|
||||
wait
|
||||
|
||||
# Build frontend for production
|
||||
build-frontend:
|
||||
cd frontend && npm run build
|
||||
|
||||
# Type-check frontend
|
||||
check-frontend:
|
||||
cd frontend && npx tsc --noEmit
|
||||
|
||||
# Build Docker image
|
||||
docker-build:
|
||||
docker build -t hey-search .
|
||||
|
||||
# Run Docker image
|
||||
docker-run:
|
||||
docker run -p 8000:8000 hey-search
|
||||
|
||||
# Build and run via Docker
|
||||
docker: docker-build docker-run
|
||||
Reference in New Issue
Block a user