7a34807fa0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
95 lines
3.6 KiB
Markdown
95 lines
3.6 KiB
Markdown
# CONVENTIONS — document-scanner
|
|
|
|
_Last updated: 2026-05-21_
|
|
|
|
## Summary
|
|
|
|
The codebase follows standard Python and Vue 3 conventions without heavy tooling enforcement. Backend uses async/await throughout with type hints on public interfaces. Frontend uses Vue Options API with Pinia stores as the data layer. No linter or formatter configuration is committed.
|
|
|
|
---
|
|
|
|
## Python Conventions (Backend)
|
|
|
|
### Naming
|
|
- Files: `snake_case.py`
|
|
- Classes: `PascalCase` (e.g., `AnthropicProvider`, `ClassificationResult`)
|
|
- Functions/variables: `snake_case`
|
|
- Constants: `UPPER_SNAKE_CASE` (e.g., `MAX_STORED_CHARS`, `DATA_DIR`)
|
|
- Private helpers: leading underscore (e.g., `_extract_pdf`, `_parse_classification`)
|
|
|
|
### Async
|
|
- All API endpoint functions are `async def`
|
|
- All `AIProvider` methods are `async def`
|
|
- `pytest-asyncio` with `asyncio_mode=auto` (set in `pytest.ini`)
|
|
|
|
### Type Hints
|
|
- Used on public function signatures in `ai/` layer and `services/`
|
|
- Dataclass used for `ClassificationResult` (`@dataclass` with `field(default_factory=...)`)
|
|
- Not used consistently in `api/` routers (rely on FastAPI/Pydantic implicit validation)
|
|
|
|
### Error Handling
|
|
- `extractor.py` wraps all extraction in `try/except Exception` and returns error strings (never raises)
|
|
- AI providers raise on hard failures; caller (`classifier.py`) is responsible for propagating
|
|
- No global exception handler registered in `main.py`
|
|
|
|
### Imports
|
|
- Standard library first, then third-party, then local — not enforced by isort
|
|
- Heavy library imports (`fitz`, `pytesseract`, `docx`) are deferred inside functions to avoid import-time cost when unused
|
|
|
|
### Module Docstrings
|
|
- Present on `extractor.py` and `test_classifier.py`; absent elsewhere
|
|
|
|
---
|
|
|
|
## JavaScript / Vue Conventions (Frontend)
|
|
|
|
### Naming
|
|
- Vue files: `PascalCase.vue` (e.g., `DocumentCard.vue`, `AppSidebar.vue`)
|
|
- Pinia stores: `camelCase` filename matching store ID (e.g., `documents.js` → `useDocumentsStore`)
|
|
- Views: `<Name>View.vue` suffix
|
|
- Components grouped by domain in subdirectories: `documents/`, `topics/`, `upload/`, `layout/`
|
|
|
|
### Vue Style
|
|
- Options API used throughout (not Composition API)
|
|
- Props defined with type and default; no `defineProps` (Options API syntax)
|
|
- `v-model`, `v-for`, `v-if` used directly in templates
|
|
|
|
### Pinia Pattern
|
|
- Each store encapsulates `state`, `getters`, and `actions`
|
|
- Actions call `src/api/client.js` — components never import `client.js` directly
|
|
- Stores are the single source of truth; views read from store state
|
|
|
|
### API Client
|
|
- `src/api/client.js` is the sole HTTP adapter
|
|
- All paths are prefixed `/api/` (proxied to backend in dev via Vite config)
|
|
|
|
### Styling
|
|
- Tailwind CSS utility classes used directly in templates
|
|
- No scoped `<style>` blocks observed in component list
|
|
- Global styles in `src/style.css`
|
|
|
|
---
|
|
|
|
## API Design Conventions (Backend)
|
|
|
|
- All endpoints prefixed `/api/` (set per router)
|
|
- JSON responses; multipart for file upload
|
|
- HTTP verbs follow REST: GET list, GET by ID, POST create, PUT/PATCH update, DELETE remove
|
|
- No versioning (`/api/v1/`) — flat namespace
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
- Runtime paths controlled entirely by `DATA_DIR` env var (defaults to `/app/data`)
|
|
- AI settings persisted in `data/settings.json` — no env var overrides at runtime for provider config (except `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` noted in `.env.example`)
|
|
- No `.env` loading in backend code — env vars passed via Docker Compose `environment:` block
|
|
|
|
---
|
|
|
|
## Gaps / Unknowns
|
|
|
|
- No ESLint, Prettier, Black, or Ruff configuration committed
|
|
- No pre-commit hooks
|
|
- No consistent JSDoc or Python docstring coverage
|