docs: add shared module map to CLAUDE.md, SECURITY.md, planning artifacts
- CLAUDE.md: add Code Standards section with backend and frontend shared module maps, component architecture rules, duplication checklist, and no-dead-code enforcement rule - SECURITY.md: Phase 02 + 03 security audit results (all threats CLOSED) - .planning: update milestone audit, config, and add plan/UAT files for phases 01, 02-06, and 06.2-05 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,73 @@ DocuVault is a multi-user SaaS document management platform built on FastAPI (Py
|
||||
- Every document/folder endpoint asserts `resource.user_id == current_user.id`
|
||||
- All DB queries via ORM / parameterized statements — zero raw string interpolation
|
||||
|
||||
## Code Standards (Non-Negotiable)
|
||||
|
||||
### Core principle
|
||||
|
||||
**Things that look the same to the user are the same in code.** Local file navigation and cloud file navigation share one component. Sidebar folder trees and cloud trees share one component. Format helpers exist once. If you are about to write the same logic a second time, extract it first.
|
||||
|
||||
### Backend: shared module map
|
||||
|
||||
Before adding a helper, check if it belongs in an existing shared module:
|
||||
|
||||
| Module | What lives here |
|
||||
|---|---|
|
||||
| `backend/deps/utils.py` | `get_client_ip(request)`, `parse_uuid(value)` — request-parsing helpers used across all routers |
|
||||
| `backend/storage/exceptions.py` | `CloudConnectionError` — single canonical definition; all files import from here |
|
||||
| `backend/ai/utils.py` | `strip_code_fences`, `parse_classification`, `parse_suggestions` — AI response parsing shared by all providers |
|
||||
| `backend/services/auth.py` | `validate_password_strength(password)` — raises `ValueError`; routers catch and re-raise as `HTTPException` |
|
||||
|
||||
**Rules:**
|
||||
- No router may define `_ip()`, `_get_ip()`, or any other local variant of `get_client_ip`. Import from `deps.utils`.
|
||||
- No router may define its own `CloudConnectionError`. Import from `storage.exceptions`.
|
||||
- No AI provider may define its own `_strip_code_fences` or `_parse_*`. Import from `ai.utils`.
|
||||
- No API file may define `_validate_password_strength`. Import from `services.auth`.
|
||||
- Service layer raises `ValueError` (or domain exceptions), never `HTTPException`. Only the router layer raises `HTTPException`.
|
||||
|
||||
### Frontend: shared module map
|
||||
|
||||
| Module | What lives here |
|
||||
|---|---|
|
||||
| `src/utils/formatters.js` | `formatDate`, `formatSize`, `providerColor`, `providerBg`, `providerLabel` |
|
||||
| `src/components/ui/TreeItem.vue` | Generic expand/collapse tree node — all sidebar tree items wrap this |
|
||||
| `src/components/storage/StorageBrowser.vue` | Unified file browser grid — used by both `FileManagerView` and `CloudFolderView` |
|
||||
|
||||
**Rules:**
|
||||
- No component may define its own `formatDate` or `formatSize`. Always import from `utils/formatters.js`.
|
||||
- No component may define its own `providerColor` or `providerBg`. Always import from `utils/formatters.js`.
|
||||
- No new tree sidebar component may implement its own expand/collapse state. It must wrap `TreeItem.vue`.
|
||||
- `StorageBrowser.vue` is the single file browser. Do not create a parallel file grid anywhere.
|
||||
- `FileManagerView` and `CloudFolderView` are thin data-providers: they feed props into `StorageBrowser` and handle emitted events. They contain no layout or grid logic of their own.
|
||||
|
||||
### Component architecture
|
||||
|
||||
```
|
||||
View (thin data-provider)
|
||||
└── Smart component (StorageBrowser, AdminUsersTab, etc.)
|
||||
└── Dumb/presentational components (DocumentCard, FolderTreeItem, etc.)
|
||||
```
|
||||
|
||||
- Views own stores and route params. They pass data down as props and handle emitted events.
|
||||
- Smart components own layout, interactions, and internal state. They emit events upward; they do not call stores directly (exception: read-only lookups like topic color).
|
||||
- Presentational components receive everything as props and emit actions.
|
||||
- Props that are passed from parent to child are never mutated with `v-model` — use `:model-value` + `@update:modelValue` and emit upward.
|
||||
|
||||
### No dead code
|
||||
|
||||
- Files with no active route and no active import are deleted immediately — not commented out, not kept "just in case".
|
||||
- `HomeView.vue` and `FolderView.vue` are deleted. Do not recreate them.
|
||||
- Any file that becomes unreferenced after a refactor must be deleted in the same commit.
|
||||
|
||||
### Duplication checklist (run before writing new code)
|
||||
|
||||
1. Does a shared utility already exist for this logic? (Check the module map above.)
|
||||
2. Does this component already exist? (Search `components/` before creating.)
|
||||
3. Is this logic already in a Pinia store? (Check `stores/` before duplicating in a view.)
|
||||
4. If none of the above: create the shared module first, then use it everywhere that needs it.
|
||||
|
||||
---
|
||||
|
||||
## GSD Workflow
|
||||
|
||||
This project uses the GSD (Get Shit Done) planning workflow. Planning artifacts live in `.planning/`.
|
||||
|
||||
Reference in New Issue
Block a user