Skip to content

Commit c3c543b

Browse files
committed
docs: update claude md with new changes
1 parent 635a78c commit c3c543b

File tree

1 file changed

+175
-5
lines changed

1 file changed

+175
-5
lines changed

CLAUDE.md

Lines changed: 175 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ securechain-auth/
4242
│ │ ├── patterns/ # Regex patterns for validation
4343
│ │ └── validators/ # Custom validators
4444
│ ├── utils/ # Utilities
45-
│ │ ├── jwt_encoder.py # JWT encoding/decoding
46-
│ │ ├── password_encoder.py # Password hashing (bcrypt)
47-
│ │ └── json_encoder.py # Custom JSON encoders
48-
│ └── exceptions/ # Custom exceptions
45+
│ │ ├── jwt_encoder.py # JWT encoding/decoding (JWTBearer class)
46+
│ │ ├── password_encoder.py # Password hashing (PasswordEncoder class)
47+
│ │ └── json_encoder.py # Custom JSON encoder (JSONEncoder class)
48+
│ └── exceptions/ # Custom exceptions (one class per file)
49+
│ ├── not_authenticated_exception.py
50+
│ ├── expired_token_exception.py
51+
│ └── invalid_token_exception.py
4952
├── tests/ # Tests with pytest
5053
│ ├── conftest.py # Pytest configuration
5154
│ ├── controllers/ # Controller tests
@@ -62,6 +65,67 @@ securechain-auth/
6265
6366
```
6467

68+
### Code Organization Pattern
69+
70+
The project follows a **direct instantiation pattern** for services and utilities:
71+
72+
#### Controllers (`app/controllers/`)
73+
Each controller creates module-level instances of services and utilities:
74+
75+
```python
76+
# Example: auth_controller.py
77+
from app.services import AuthService
78+
from app.utils import JWTBearer, JSONEncoder, PasswordEncoder
79+
80+
# Module-level instances (singletons per module)
81+
auth_service = AuthService()
82+
jwt_bearer = JWTBearer()
83+
json_encoder = JSONEncoder()
84+
password_encoder = PasswordEncoder()
85+
86+
@router.post("/endpoint")
87+
async def endpoint():
88+
# Direct usage of instances
89+
user = await auth_service.read_user_by_email(email)
90+
payload = await jwt_bearer.verify_access_token(token)
91+
response = json_encoder.encode(data)
92+
hashed = await password_encoder.hash(password)
93+
```
94+
95+
**Benefits**:
96+
- ✅ Simple and explicit
97+
- ✅ No dependency injection complexity
98+
- ✅ Easy to understand and maintain
99+
- ✅ Consistent pattern across the codebase
100+
101+
#### Services (`app/services/`)
102+
- **AuthService**: Business logic for authentication
103+
- Direct instantiation: `AuthService()`
104+
- Manages Neo4j and MongoDB connections internally
105+
106+
#### Utilities (`app/utils/`)
107+
All utilities are classes that are instantiated directly:
108+
109+
- **JWTBearer**: JWT token operations (create, verify, set cookies)
110+
```python
111+
jwt_bearer = JWTBearer()
112+
token = await jwt_bearer.create_access_token(data)
113+
payload = await jwt_bearer.verify_access_token(token)
114+
```
115+
116+
- **JSONEncoder**: JSON serialization with custom types (ObjectId, datetime)
117+
```python
118+
json_encoder = JSONEncoder()
119+
result = json_encoder.encode(data) # Handles ObjectId and datetime
120+
```
121+
122+
- **PasswordEncoder**: Password hashing and verification (bcrypt)
123+
```python
124+
password_encoder = PasswordEncoder()
125+
hashed = await password_encoder.hash(password)
126+
is_valid = await password_encoder.verify(password, hashed)
127+
```
128+
65129
## 🔧 Technology Stack
66130

67131
### Core Dependencies
@@ -227,6 +291,35 @@ pytest tests --cov=app --cov-report=html
227291
- `tests/models/`: Data model tests
228292
- `conftest.py`: Shared fixtures (HTTP client, DB mocks)
229293

294+
### Testing Strategy
295+
296+
The project uses **patch-based mocking** for testing controllers:
297+
298+
```python
299+
# Example: test_auth_controller.py
300+
@pytest.fixture(scope="session", autouse=True)
301+
def patch_jwt():
302+
# Patch JWT at class level before app import
303+
with patch("app.utils.jwt_encoder.JWTBearer.__call__",
304+
new=AsyncMock(return_value={"user_id": "abc123"})):
305+
yield
306+
307+
@pytest.fixture(autouse=True)
308+
def mock_services():
309+
# Patch service instances
310+
with patch("app.controllers.auth_controller.auth_service") as mock_auth:
311+
mock_auth.read_user_by_email = AsyncMock()
312+
mock_auth.create_user = AsyncMock()
313+
# ... more async methods
314+
yield mock_auth
315+
```
316+
317+
**Key points**:
318+
- Patch `JWTBearer.__call__` at **session scope** before importing `app`
319+
- Patch service instances at **function scope** for each test
320+
- Use `AsyncMock` for all async methods
321+
- Configure return values as needed per test
322+
230323
## 📊 Logging
231324

232325
The system uses structured logging:
@@ -297,6 +390,36 @@ uv sync --upgrade
297390
6. **Logging**: Structured logging with relevant context
298391
7. **Testing**: Tests for new features before merge
299392
8. **Security**: Never commit `.env` files, use `template.env`
393+
9. **Code Organization**: Direct instantiation pattern for services and utilities
394+
10. **No Comments**: Code should be self-documenting (no inline comments)
395+
396+
### Architecture Patterns
397+
398+
#### ✅ Direct Instantiation (Current Pattern)
399+
```python
400+
# In controllers
401+
auth_service = AuthService()
402+
jwt_bearer = JWTBearer()
403+
json_encoder = JSONEncoder()
404+
405+
# Usage
406+
user = await auth_service.read_user_by_email(email)
407+
```
408+
409+
**Why**: Simple, explicit, easy to understand and test
410+
411+
#### ❌ Avoid Dependency Injection
412+
The project intentionally avoids FastAPI's `Depends()` pattern to keep code simple and explicit.
413+
414+
#### ✅ Class-based Utilities
415+
All utilities are classes that encapsulate related functionality:
416+
- `JWTBearer`: JWT operations
417+
- `JSONEncoder`: JSON encoding with custom types
418+
- `PasswordEncoder`: Password hashing and verification
419+
- `AuthService`: Authentication business logic
420+
421+
#### ✅ Module-level Instances
422+
Create instances at module level (singleton per module) for reuse across endpoint handlers.
300423

301424
## 🔗 Important Links
302425

@@ -326,6 +449,53 @@ uv sync --upgrade
326449
- PascalCase for classes
327450
- Docstrings in public functions
328451
- Type hints mandatory
452+
- **No inline comments** - code should be self-documenting
453+
- **Direct instantiation** - avoid dependency injection patterns
454+
- **Class-based utilities** - group related functions in classes
455+
- **One class per file** - following Single Responsibility Principle
456+
457+
### Common Patterns:
458+
459+
#### Creating a new utility class:
460+
```python
461+
# app/utils/my_utility.py
462+
class MyUtility:
463+
def __init__(self):
464+
# Initialize if needed
465+
pass
466+
467+
def method(self, param: str) -> str:
468+
# Implementation
469+
return result
470+
471+
# In controller
472+
from app.utils import MyUtility
473+
474+
my_utility = MyUtility()
475+
```
476+
477+
#### Adding a new endpoint:
478+
```python
479+
# In controller
480+
@router.post("/endpoint")
481+
@limiter.limit("25/minute")
482+
async def endpoint(request: Request, data: Schema) -> JSONResponse:
483+
result = await auth_service.method(data)
484+
return JSONResponse(
485+
status_code=status.HTTP_200_OK,
486+
content=json_encoder.encode({"detail": result})
487+
)
488+
```
489+
490+
#### Testing pattern:
491+
```python
492+
def test_endpoint(mock_services):
493+
mock_auth = mock_services
494+
mock_auth.method.return_value = expected_value
495+
496+
response = client.post("/endpoint", json={"data": "value"})
497+
assert response.status_code == 200
498+
```
329499

330500
### Debugging:
331501
- Logs in `errors.log`
@@ -334,5 +504,5 @@ uv sync --upgrade
334504

335505
---
336506

337-
**Last updated**: October 12, 2025
507+
**Last updated**: October 15, 2025
338508
**Maintained by**: Secure Chain Team

0 commit comments

Comments
 (0)