Files
TJWaterServerBinary/QUICK_START_GUIDE.md
T

327 lines
7.5 KiB
Markdown

# TJWater ServerBinary - Quick Reference for Secondary Development
## 1️⃣ Adding a New API Endpoint (30 seconds)
### File: `app/api/v1/endpoints/my_feature.py`
```python
from fastapi import APIRouter, Depends
from app.auth.dependencies import get_current_active_user
from app.domain.schemas.user import UserInDB
router = APIRouter()
@router.get("/list")
async def list_items(user: UserInDB = Depends(get_current_active_user)):
return {"items": []}
@router.post("/create")
async def create_item(data: dict, user: UserInDB = Depends(get_current_active_user)):
return {"status": "created"}
```
### File: `app/api/v1/router.py` (Add 2 lines)
```python
from app.api.v1.endpoints import my_feature
api_router.include_router(my_feature.router, prefix="/items", tags=["Items"])
```
**Done!** Endpoint available at `POST /api/v1/items/create`
---
## 2️⃣ Database Query Pattern
### Using Repository
```python
from app.infra.repositories.user_repository import UserRepository
from app.auth.dependencies import get_user_repository
@router.get("/user/{user_id}")
async def get_user(user_id: int, user_repo: UserRepository = Depends(get_user_repository)):
user = await user_repo.get_user_by_id(user_id)
return user
```
### Direct Query (if no repository exists)
```python
async with db.get_connection() as conn:
async with conn.cursor() as cur:
await cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))
row = await cur.fetchone()
return dict(row) if row else None
```
---
## 3️⃣ Role-Based Access Control
```python
from app.auth.permissions import require_admin, require_role
from app.domain.models.role import UserRole
# Admin only
@router.delete("/users/{user_id}")
async def delete_user(user_id: int, admin: UserInDB = Depends(require_admin)):
pass
# Operator or higher
@router.post("/projects/")
async def create_project(user: UserInDB = Depends(require_role(UserRole.OPERATOR))):
pass
# Custom role check
def require_viewer():
return require_role(UserRole.VIEWER)
@router.get("/reports")
async def get_reports(user: UserInDB = Depends(require_viewer)):
pass
```
---
## 4️⃣ Call Native (Binary) Code
```python
from app.native.wndb import get_all_junctions, add_junction, set_junction
# Read network elements
junctions = get_all_junctions()
# Create
add_junction({"id": "J1", "x": 0.0, "y": 0.0, "demand": 100.0})
# Update
set_junction("J1", {"demand": 150.0})
# Get constants
from app.native.wndb import PIPE_STATUS_OPEN, OPTION_UNITS_LPS
```
---
## 5️⃣ Encryption & Security
### Encrypt Sensitive Data
```python
from app.core.encryption import get_encryptor
encryptor = get_encryptor()
encrypted = encryptor.encrypt("secret_password")
decrypted = encryptor.decrypt(encrypted)
```
### Verify Password
```python
from app.core.security import verify_password, get_password_hash
# When creating user
hashed = get_password_hash(user.password)
# When checking login
if verify_password(form_data.password, stored_hash):
# Correct password
pass
```
---
## 6️⃣ Configuration
### In `.env` file
```bash
SECRET_KEY=your-secret-key
ENCRYPTION_KEY=your-fernet-key
DB_HOST=localhost
DB_PORT=5432
```
### Use in Code
```python
from app.core.config import settings
db_url = settings.SQLALCHEMY_DATABASE_URI
token_minutes = settings.ACCESS_TOKEN_EXPIRE_MINUTES
```
---
## 7️⃣ Testing
```python
# tests/unit/test_my_feature.py
import pytest
def test_my_function():
result = my_function()
assert result == expected
# Run tests
pytest tests/ -v
pytest tests/unit/test_my_feature.py::test_my_function -v
```
---
## 🗺️ Directory Quick Map
| Path | What | Use For |
|------|------|---------|
| `app/api/v1/endpoints/` | API routes | Add new endpoints |
| `app/auth/` | Auth logic | Login, permissions |
| `app/domain/` | Models/Schemas | Data structures |
| `app/infra/db/` | DB access | Queries, repositories |
| `app/services/` | Business logic | Complex operations |
| `app/native/wndb/` | Binary functions | Network simulation |
| `app/core/` | Core utilities | Config, security, encryption |
| `tests/` | Tests | Unit & integration tests |
---
## 🔑 Key Imports
```python
# Authentication
from app.auth.dependencies import get_current_active_user, get_user_repository
from app.auth.permissions import require_admin, require_role
# Database
from app.infra.db.postgresql.database import db, get_database_instance
from app.infra.repositories.user_repository import UserRepository
# Schemas & Models
from app.domain.schemas.user import UserInDB, UserCreate, Token
from app.domain.models.role import UserRole
# Security
from app.core.security import create_access_token, verify_password, get_password_hash
from app.core.encryption import get_encryptor
# Config
from app.core.config import settings
# Native API
from app.native.wndb import get_all_junctions, add_junction, open_project
```
---
## 🚀 Common Tasks
### Register New User
```python
from app.infra.repositories.user_repository import UserRepository
from app.domain.schemas.user import UserCreate
from app.domain.models.role import UserRole
user_data = UserCreate(
username="john",
email="john@example.com",
password="securepass",
role=UserRole.USER
)
new_user = await user_repo.create_user(user_data)
```
### Query Database
```python
async with db.get_connection() as conn:
async with conn.cursor() as cur:
await cur.execute("SELECT * FROM users LIMIT 10")
rows = await cur.fetchall()
return [dict(r) for r in rows]
```
### Run Simulation
```python
from app.services.simulation import run_simulation
result = await run_simulation(
project_name="szh",
duration=3600,
time_step=60
)
```
### Audit Operation
```python
from app.core.audit import log_audit_event, AuditAction
await log_audit_event(
action=AuditAction.CREATE,
resource_type="pipe",
resource_id="P1",
actor_id=user.id,
details={"diameter": 100, "material": "PVC"}
)
```
---
## ⚠️ Common Gotchas
1. **Always use `Depends()`** for injecting repositories, users
```python
# ✅ Right
async def endpoint(user: UserInDB = Depends(get_current_active_user)):
# ❌ Wrong
async def endpoint(user: UserInDB):
```
2. **Use parametrized queries** to prevent SQL injection
```python
# ✅ Right
await cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# ❌ Wrong
await cur.execute(f"SELECT * FROM users WHERE id = {user_id}")
```
3. **Async/await** required for database operations
```python
# ✅ Right
user = await user_repo.get_user_by_id(1)
# ❌ Wrong
user = user_repo.get_user_by_id(1) # Missing await
```
4. **Role hierarchy** for permission checks
```python
# All levels include higher permissions
VIEWER (1) < USER (2) < OPERATOR (3) < ADMIN (4)
```
---
## 📞 File Locations Reference
- **Main app entry**: `app/main.py` (83 lines)
- **Central router**: `app/api/v1/router.py` (98 lines)
- **Config**: `app/core/config.py` (82 lines)
- **Auth dependencies**: `app/auth/dependencies.py`
- **Permissions**: `app/auth/permissions.py`
- **Database**: `app/infra/db/postgresql/database.py`
- **Repositories**: `app/infra/repositories/`
- **Schemas**: `app/domain/schemas/`
- **Models**: `app/domain/models/`
---
## 📚 Full Documentation
See **SECONDARY_DEVELOPMENT_GUIDE.md** for comprehensive guide on:
- Architecture overview
- Detailed endpoint creation
- Database patterns
- Native module integration
- Testing setup
- Deployment
---
*Generated for TJWater ServerBinary secondary development team*