Update documentation and tests for coverage, email integration, and authentication
- **Backend Documentation:** Improve authentication flow details, update token expiry times, and reflect defensive code in test coverage. Add guidance for email service integration with SMTP and third-party providers. - **Test Coverage:** Backend overall coverage increased to **97%** with critical security tests added (JWT attacks, session hijacking, privilege escalation). Justify missing lines and update CI instructions. - **Frontend Updates:** Update E2E worker configuration (`workers: 12` in non-CI mode) and maintain 100% E2E test pass rate. - **Default Implementations:** Enhance email service with templates for registration and password resets. Document integration options for production use cases. - **Consistency Improvements:** Align naming conventions and test configurations across backend and frontend to reflect current system architecture.
This commit is contained in:
133
CLAUDE.md
133
CLAUDE.md
@@ -86,10 +86,10 @@ alembic upgrade head
|
|||||||
|
|
||||||
#### Testing
|
#### Testing
|
||||||
|
|
||||||
**CRITICAL: Coverage Tracking Issue**
|
**Test Coverage: 97%** (743 tests, all passing)
|
||||||
- Pytest-cov has coverage recording issues with FastAPI routes when using xdist parallel execution
|
- Comprehensive test suite with security-focused testing
|
||||||
- Tests pass successfully but coverage data isn't collected for some route files
|
- Includes tests for JWT algorithm attacks (CVE-2015-9235), session hijacking, and privilege escalation
|
||||||
- See `backend/docs/COVERAGE_REPORT.md` for detailed analysis
|
- 84 missing lines are justified (defensive code, error handlers, production-only code)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run all tests (uses pytest-xdist for parallel execution)
|
# Run all tests (uses pytest-xdist for parallel execution)
|
||||||
@@ -107,8 +107,6 @@ IS_TEST=True pytest tests/api/test_auth.py::TestLogin::test_login_success -v
|
|||||||
# Run with HTML coverage report
|
# Run with HTML coverage report
|
||||||
IS_TEST=True pytest --cov=app --cov-report=html -n 0
|
IS_TEST=True pytest --cov=app --cov-report=html -n 0
|
||||||
open htmlcov/index.html
|
open htmlcov/index.html
|
||||||
|
|
||||||
# Coverage target: 90%+ (currently 79%)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Running Locally
|
#### Running Locally
|
||||||
@@ -159,7 +157,7 @@ npx playwright test auth-login.spec.ts # Run specific file
|
|||||||
- Use ID-based selectors for validation errors (e.g., `#email-error`)
|
- Use ID-based selectors for validation errors (e.g., `#email-error`)
|
||||||
- Error IDs use dashes not underscores (`#new-password-error`)
|
- Error IDs use dashes not underscores (`#new-password-error`)
|
||||||
- Target `.border-destructive[role="alert"]` to avoid Next.js route announcer conflicts
|
- Target `.border-destructive[role="alert"]` to avoid Next.js route announcer conflicts
|
||||||
- Use 4 workers max to prevent test interference (`workers: 4` in `playwright.config.ts`)
|
- Uses 12 workers in non-CI mode (`workers: 12` in `playwright.config.ts`)
|
||||||
- URL assertions should use regex to handle query params: `/\/auth\/login/`
|
- URL assertions should use regex to handle query params: `/\/auth\/login/`
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
@@ -180,8 +178,8 @@ docker-compose build frontend
|
|||||||
|
|
||||||
### Authentication Flow
|
### Authentication Flow
|
||||||
1. **Login**: `POST /api/v1/auth/login` returns access + refresh tokens
|
1. **Login**: `POST /api/v1/auth/login` returns access + refresh tokens
|
||||||
- Access token: 1 day expiry (JWT)
|
- Access token: 15 minutes expiry (JWT)
|
||||||
- Refresh token: 60 days expiry (JWT with JTI stored in DB)
|
- Refresh token: 7 days expiry (JWT with JTI stored in DB)
|
||||||
- Session tracking with device info (IP, user agent, device ID)
|
- Session tracking with device info (IP, user agent, device ID)
|
||||||
|
|
||||||
2. **Token Refresh**: `POST /api/v1/auth/refresh` validates refresh token JTI
|
2. **Token Refresh**: `POST /api/v1/auth/refresh` validates refresh token JTI
|
||||||
@@ -190,10 +188,10 @@ docker-compose build frontend
|
|||||||
- Updates session `last_used_at`
|
- Updates session `last_used_at`
|
||||||
|
|
||||||
3. **Authorization**: FastAPI dependencies in `api/dependencies/auth.py`
|
3. **Authorization**: FastAPI dependencies in `api/dependencies/auth.py`
|
||||||
- `get_current_user`: Validates access token, returns User or None
|
- `get_current_user`: Validates access token, returns User (raises 401 if invalid)
|
||||||
- `require_auth`: Requires valid access token
|
- `get_current_active_user`: Requires valid access token + active account
|
||||||
- `optional_auth`: Accepts both authenticated and anonymous users
|
- `get_optional_current_user`: Accepts both authenticated and anonymous users (returns User or None)
|
||||||
- `require_superuser`: Requires superuser flag
|
- `get_current_superuser`: Requires superuser flag
|
||||||
|
|
||||||
### Database Pattern: Async SQLAlchemy
|
### Database Pattern: Async SQLAlchemy
|
||||||
- **Engine**: Created in `core/database.py` with connection pooling
|
- **Engine**: Created in `core/database.py` with connection pooling
|
||||||
@@ -206,7 +204,7 @@ docker-compose build frontend
|
|||||||
- **Zustand stores**: `lib/stores/` (authStore, etc.)
|
- **Zustand stores**: `lib/stores/` (authStore, etc.)
|
||||||
- **TanStack Query**: API data fetching/caching
|
- **TanStack Query**: API data fetching/caching
|
||||||
- **Auto-generated client**: `lib/api/generated/` from OpenAPI spec
|
- **Auto-generated client**: `lib/api/generated/` from OpenAPI spec
|
||||||
- Generate with: `npm run generate-api` (runs `scripts/generate-api-client.sh`)
|
- Generate with: `npm run generate:api` (runs `scripts/generate-api-client.sh`)
|
||||||
|
|
||||||
### Session Management Architecture
|
### Session Management Architecture
|
||||||
**Database-backed session tracking** (not just JWT):
|
**Database-backed session tracking** (not just JWT):
|
||||||
@@ -411,7 +409,7 @@ Automatically applied via middleware in `main.py`:
|
|||||||
6. **Generate frontend client**:
|
6. **Generate frontend client**:
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
npm run generate-api
|
npm run generate:api
|
||||||
```
|
```
|
||||||
|
|
||||||
### Adding a New React Component
|
### Adding a New React Component
|
||||||
@@ -454,32 +452,85 @@ Automatically applied via middleware in `main.py`:
|
|||||||
- ✅ E2E test suite (86 tests, 100% pass rate, zero flaky tests)
|
- ✅ E2E test suite (86 tests, 100% pass rate, zero flaky tests)
|
||||||
|
|
||||||
### Test Coverage
|
### Test Coverage
|
||||||
- **Backend**: 79% overall (target: 90%+)
|
- **Backend**: 97% overall (743 tests, all passing) ✅
|
||||||
- User CRUD: 90%
|
- Comprehensive security testing (JWT attacks, session hijacking, privilege escalation)
|
||||||
|
- User CRUD: 100% ✅
|
||||||
- Session CRUD: 100% ✅
|
- Session CRUD: 100% ✅
|
||||||
- Auth routes: 79%
|
- Auth routes: 99% ✅
|
||||||
- Admin routes: 46% (coverage tracking issue)
|
- Organization routes: 100% ✅
|
||||||
- See `backend/docs/COVERAGE_REPORT.md` for details
|
- Permissions: 100% ✅
|
||||||
|
- 84 missing lines justified (defensive code, error handlers, production-only code)
|
||||||
|
|
||||||
- **Frontend E2E**: 86 tests across 4 files
|
- **Frontend E2E**: 86 tests across 4 files (100% pass rate, zero flaky tests) ✅
|
||||||
- auth-login.spec.ts
|
- auth-login.spec.ts
|
||||||
- auth-register.spec.ts
|
- auth-register.spec.ts
|
||||||
- auth-password-reset.spec.ts
|
- auth-password-reset.spec.ts
|
||||||
- navigation.spec.ts
|
- navigation.spec.ts
|
||||||
|
|
||||||
### Known Issues
|
## Email Service Integration
|
||||||
|
|
||||||
1. **Pytest-cov coverage tracking issue**:
|
The project includes a **placeholder email service** (`backend/app/services/email_service.py`) designed for easy integration with production email providers.
|
||||||
- Tests pass but coverage not recorded for some route files
|
|
||||||
- Suspected: xdist parallel execution interferes with coverage collection
|
|
||||||
- Workaround: Run with `-n 0` for accurate coverage
|
|
||||||
- Investigation needed: HTML coverage report, source vs trace mode
|
|
||||||
|
|
||||||
2. **Dead code in users.py** (lines 150-154, 270-275):
|
### Current Implementation
|
||||||
- Checks for `is_superuser` in `UserUpdate` schema
|
|
||||||
- Field doesn't exist in schema, so code is unreachable
|
**Console Backend (Default)**:
|
||||||
- Marked with `# pragma: no cover`
|
- Logs email content to console/logs instead of sending
|
||||||
- Consider: Remove code or add field to schema
|
- Safe for development and testing
|
||||||
|
- No external dependencies required
|
||||||
|
|
||||||
|
### Production Integration
|
||||||
|
|
||||||
|
To enable email functionality, implement one of these approaches:
|
||||||
|
|
||||||
|
**Option 1: SMTP Integration** (Recommended for most use cases)
|
||||||
|
```python
|
||||||
|
# In app/services/email_service.py, complete the SMTPEmailBackend implementation
|
||||||
|
from aiosmtplib import SMTP
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
|
||||||
|
# Add environment variables to .env:
|
||||||
|
# SMTP_HOST=smtp.gmail.com
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=your-email@gmail.com
|
||||||
|
# SMTP_PASSWORD=your-app-password
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Third-Party Service** (SendGrid, AWS SES, Mailgun, etc.)
|
||||||
|
```python
|
||||||
|
# Create a new backend class, e.g., SendGridEmailBackend
|
||||||
|
class SendGridEmailBackend(EmailBackend):
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
self.api_key = api_key
|
||||||
|
self.client = sendgrid.SendGridAPIClient(api_key)
|
||||||
|
|
||||||
|
async def send_email(self, to, subject, html_content, text_content=None):
|
||||||
|
# Implement SendGrid sending logic
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Update global instance in email_service.py:
|
||||||
|
# email_service = EmailService(SendGridEmailBackend(settings.SENDGRID_API_KEY))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 3: External Microservice**
|
||||||
|
- Use a dedicated email microservice via HTTP API
|
||||||
|
- Implement `HTTPEmailBackend` that makes async HTTP requests
|
||||||
|
|
||||||
|
### Email Templates Included
|
||||||
|
|
||||||
|
The service includes pre-built templates for:
|
||||||
|
- **Password Reset**: `send_password_reset_email()` - 1 hour expiry
|
||||||
|
- **Email Verification**: `send_email_verification()` - 24 hour expiry
|
||||||
|
|
||||||
|
Both include responsive HTML and plain text versions.
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
|
||||||
|
Email sending is called from:
|
||||||
|
- `app/api/routes/auth.py` - Password reset flow (placeholder comments)
|
||||||
|
- Registration flow - Ready for email verification integration
|
||||||
|
|
||||||
|
**Note**: Current auth routes have placeholder comments where email functionality should be integrated. Search for "TODO: Send email" in the codebase.
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
@@ -519,6 +570,20 @@ alembic upgrade head # Re-apply
|
|||||||
|
|
||||||
## Additional Documentation
|
## Additional Documentation
|
||||||
|
|
||||||
- `backend/docs/COVERAGE_REPORT.md`: Detailed coverage analysis and roadmap to 95%
|
- `backend/docs/ARCHITECTURE.md`: System architecture and design patterns
|
||||||
- `backend/docs/ASYNC_MIGRATION_GUIDE.md`: Guide for async SQLAlchemy patterns
|
- `backend/docs/CODING_STANDARDS.md`: Code quality standards and best practices
|
||||||
|
- `backend/docs/COMMON_PITFALLS.md`: Common mistakes and how to avoid them
|
||||||
|
- `backend/docs/FEATURE_EXAMPLE.md`: Step-by-step feature implementation guide
|
||||||
- `frontend/e2e/README.md`: E2E testing setup and guidelines
|
- `frontend/e2e/README.md`: E2E testing setup and guidelines
|
||||||
|
- **`frontend/docs/design-system/`**: Comprehensive design system documentation
|
||||||
|
- `README.md`: Hub with learning paths (start here)
|
||||||
|
- `00-quick-start.md`: 5-minute crash course
|
||||||
|
- `01-foundations.md`: Colors (OKLCH), typography, spacing, shadows
|
||||||
|
- `02-components.md`: shadcn/ui component library guide
|
||||||
|
- `03-layouts.md`: Layout patterns (Grid vs Flex decision trees)
|
||||||
|
- `04-spacing-philosophy.md`: Parent-controlled spacing strategy
|
||||||
|
- `05-component-creation.md`: When to create vs compose components
|
||||||
|
- `06-forms.md`: Form patterns with react-hook-form + Zod
|
||||||
|
- `07-accessibility.md`: WCAG AA compliance, keyboard navigation, screen readers
|
||||||
|
- `08-ai-guidelines.md`: **AI code generation rules (read this!)**
|
||||||
|
- `99-reference.md`: Quick reference cheat sheet (bookmark this)
|
||||||
|
|||||||
Reference in New Issue
Block a user