forked from cardosofelipe/pragma-stack
- Create docs/development/WORKFLOW.md with branch strategy, issue management, testing requirements, and code review process - Create docs/development/CODING_STANDARDS.md with technical patterns, auth DI pattern, testing patterns, and security guidelines - Streamline CLAUDE.md to link to detailed documentation instead of embedding all content - Add branch/issue workflow rules: single branch per feature for both design and implementation phases
7.6 KiB
7.6 KiB
Coding Standards
Technical coding standards and patterns for Syndarix development.
Table of Contents
Backend Standards
Dependency Management
- Use uv (modern Python package manager), not pip
- Always use
uv runprefix for commands - Add dependencies:
uv add <package>oruv add --dev <package>
# Running tests
IS_TEST=True uv run pytest
# Or use Makefile
make test
make install-dev
Database Migrations
- Use the
migrate.pyhelper script, not Alembic directly - Never commit migrations without testing them first
# Generate and apply migration
python migrate.py auto "message"
# Check current state
python migrate.py current
Authentication Testing Fixtures
Backend fixtures in tests/conftest.py:
| Fixture | Purpose |
|---|---|
async_test_db |
Fresh SQLite per test |
async_test_user |
Pre-created regular user |
async_test_superuser |
Pre-created admin user |
user_token |
Access token for regular user |
superuser_token |
Access token for admin |
# Always use these decorators for async tests
@pytest.mark.asyncio
async def test_something():
pass
# Use for async fixtures
@pytest_asyncio.fixture
async def my_fixture():
pass
Database Exception Mocking
from unittest.mock import patch, AsyncMock
async def mock_commit():
raise OperationalError("Connection lost", {}, Exception())
with patch.object(session, 'commit', side_effect=mock_commit):
with patch.object(session, 'rollback', new_callable=AsyncMock) as mock_rollback:
with pytest.raises(OperationalError):
await crud_method(session, obj_in=data)
mock_rollback.assert_called_once()
Security Considerations
- Backend has comprehensive security tests (JWT attacks, session hijacking)
- Never skip security headers in production
- Rate limiting:
@limiter.limit("10/minute") - Session revocation is database-backed, not just JWT expiry
Frontend Standards
Auth Store Dependency Injection
CRITICAL: ALWAYS use useAuth() from AuthContext, NEVER import useAuthStore directly!
// ❌ WRONG - Bypasses dependency injection
import { useAuthStore } from '@/lib/stores/authStore';
const { user, isAuthenticated } = useAuthStore();
// ✅ CORRECT - Uses dependency injection
import { useAuth } from '@/lib/auth/AuthContext';
const { user, isAuthenticated } = useAuth();
Why This Matters:
- E2E tests inject mock stores via
window.__TEST_AUTH_STORE__ - Unit tests inject via
<AuthProvider store={mockStore}> - Direct
useAuthStoreimports bypass this injection → tests fail - ESLint will catch violations
Exceptions:
AuthContext.tsx- DI boundary, legitimately needs real storeclient.ts- Non-React context, uses dynamic import +__TEST_AUTH_STORE__check
API Client Generation
# After backend schema changes
npm run generate:api
- Client is auto-generated from OpenAPI spec
- Located in
frontend/src/lib/api/generated/ - NEVER manually edit generated files
Component Development
- Follow design system docs in
frontend/docs/design-system/ - Read
08-ai-guidelines.mdfor AI code generation rules - Use parent-controlled spacing (see
04-spacing-philosophy.md) - WCAG AA compliance required (see
07-accessibility.md)
Route Groups Structure
src/app/[locale]/
├── (auth)/ # Public auth pages (login, register, password reset)
│ # Uses AuthLayoutClient - redirects authenticated users
├── (authenticated)/ # Protected app pages
│ # Uses AuthGuard + Header/Footer
├── admin/ # Admin pages with sidebar
│ # Uses AuthGuard requireAdmin
├── dev/ # Design system documentation
└── prototypes/ # UI prototypes for approval
Testing Patterns
Frontend Unit Tests
// Mock useAuth correctly
jest.mock('@/lib/auth/AuthContext', () => ({
useAuth: () => ({
user: { id: '1', email: 'test@example.com' },
isAuthenticated: true,
}),
}));
E2E Test Best Practices (Playwright)
Navigation Pattern:
// ✅ CORRECT - Use Promise.all for Next.js Link clicks
await Promise.all([
page.waitForURL('/target', { timeout: 10000 }),
link.click()
]);
Selectors:
- Use ID-based selectors for validation errors:
#email-error - Error IDs use dashes not underscores:
#new-password-error - Target
.border-destructive[role="alert"]to avoid Next.js route announcer conflicts - Avoid generic
[role="alert"]which matches multiple elements
URL Assertions:
// ✅ Use regex to handle query params
await expect(page).toHaveURL(/\/auth\/login/);
// ❌ Don't use exact strings (fails with query params)
await expect(page).toHaveURL('/auth/login');
Configuration:
- Uses 12 workers in non-CI mode
- Reduces to 2 workers in CI for stability
Backend E2E Testing
Requires Docker for Testcontainers.
# Install deps
make install-e2e
# Run all E2E tests
make test-e2e
# Run schema tests only
make test-e2e-schema
# Run all tests (unit + E2E)
make test-all
Uses:
- Testcontainers (real PostgreSQL)
- Schemathesis (OpenAPI contract testing)
Markers:
@pytest.mark.e2e@pytest.mark.postgres@pytest.mark.schemathesis
See: backend/docs/E2E_TESTING.md for complete guide.
Security Guidelines
OWASP Top 10 Compliance
All code must be reviewed for:
- Injection vulnerabilities (SQL, command, XSS)
- Broken authentication
- Sensitive data exposure
- Security misconfiguration
- Insecure deserialization
Rate Limiting
from app.core.limiter import limiter
@router.post("/endpoint")
@limiter.limit("10/minute")
async def endpoint():
pass
JWT Security
- Tokens stored securely (httpOnly cookies preferred)
- Short expiration times
- Refresh token rotation
- Database-backed session revocation
Common Workflows
Adding a New Feature
- Start with backend schema and CRUD
- Implement API route with proper authorization
- Write backend tests (aim for >90% coverage)
- Generate frontend API client:
npm run generate:api - Implement frontend components
- Write frontend unit tests
- Add E2E tests for critical flows
- Update relevant documentation
Fixing Tests
| Layer | Check |
|---|---|
| Backend | Test database isolation, async fixture usage |
| Frontend unit | Mock useAuth() not useAuthStore |
| E2E | Use Promise.all() pattern, regex URL assertions |
Debugging
| Layer | Action |
|---|---|
| Backend | Check IS_TEST=True environment variable |
| Frontend | Run npm run type-check first |
| E2E | Use npm run test:e2e:debug for step-by-step |
| All | Check logs - backend has detailed error logging |
Demo Mode
Frontend-only showcase mode for demos without backend.
# Enable
echo "NEXT_PUBLIC_DEMO_MODE=true" > frontend/.env.local
- Uses MSW (Mock Service Worker) to intercept API calls
- Zero backend required - perfect for Vercel deployments
- MSW handlers auto-generated from OpenAPI spec
- Run
npm run generate:api→ updates both API client AND MSW handlers
Demo Credentials:
- User:
demo@example.com/DemoPass123 - Admin:
admin@example.com/AdminPass123
Safety:
- MSW never runs during tests (Jest or Playwright)
- Mock files excluded from linting and coverage
See: frontend/docs/DEMO_MODE.md for complete guide.