Files
TJWaterServerBinary/QUICK_START_GUIDE.md
T

7.5 KiB

TJWater ServerBinary - Quick Reference for Secondary Development

1️⃣ Adding a New API Endpoint (30 seconds)

File: app/api/v1/endpoints/my_feature.py

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)

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

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)

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

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

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

from app.core.encryption import get_encryptor

encryptor = get_encryptor()

encrypted = encryptor.encrypt("secret_password")
decrypted = encryptor.decrypt(encrypted)

Verify Password

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

SECRET_KEY=your-secret-key
ENCRYPTION_KEY=your-fernet-key
DB_HOST=localhost
DB_PORT=5432

Use in Code

from app.core.config import settings

db_url = settings.SQLALCHEMY_DATABASE_URI
token_minutes = settings.ACCESS_TOKEN_EXPIRE_MINUTES

7️⃣ Testing

# 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

# 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

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

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

from app.services.simulation import run_simulation

result = await run_simulation(
    project_name="szh",
    duration=3600,
    time_step=60
)

Audit Operation

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

    # ✅ 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

    # ✅ 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

    # ✅ 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

    # 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