# rules.md

**必须强制执行的约束。违反时立即终止并报错。**

---

## Code Style - Imports

### Python
```python
# Group order: stdlib → third-party → local
import json
from datetime import datetime
from typing import List, Optional

import redis
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session

from app.core.config import settings
from app.models.user import User
from app.schemas.user import UserCreate
```

### TypeScript
```typescript
// Group order: React → Third-party → Local
import React, { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

import { useAuthStore } from '@/stores/auth';
import { api } from '@/services/api';
```

**Rules:**
- Sort alphabetically within groups
- Use absolute imports for external packages, relative for local modules
- **NEVER** use wildcard imports (`from module import *`)

---

## Code Style - Formatting

- **Python:** 4-space indentation, Black formatter, max line 100
- **TypeScript:** 2-space indentation, Prettier, max line 100
- Run formatter **before committing**
- No trailing whitespace
- Empty line at end of file

---

## Code Style - Type Hints

```python
# Use strict typing - NO Any
from typing import List, Dict, Optional, Union
from datetime import datetime

def get_gpu_clusters(
    country: Optional[str] = None,
    min_gpu_count: int = 0,
) -> List[Dict[str, Union[str, int, float]]]:
    ...
```

**Rules:**
- Use type hints throughout
- **NEVER** use `Any` - use `unknown` or specific unions
- Define interfaces/types for all data structures
- Generic types preferred over type casting

---

## Code Style - Naming Conventions

| Pattern | Usage | Example |
|---------|-------|---------|
| `camelCase` | Variables, functions, methods | `gpuCluster`, `getData()` |
| `PascalCase` | Classes, components, types | `GPUCluster`, `DataSourceConfig` |
| `SCREAMING_SNAKE_CASE` | Constants, env vars | `API_KEY`, `DATABASE_URL` |
| `kebab-case` | File names, CSS | `data-source-config.css` |

**Rules:**
- Descriptive names - avoid abbreviations except well-known ones (id, ok, err)
- Max function length: 50 lines
- Max file length: 500 lines

---

## Code Style - Error Handling

```python
# Use custom exceptions
class DataSourceError(Exception):
    """Raised when data source fetch fails"""
    pass

# Proper error handling with logging
try:
    data = await fetch_data(source)
except requests.RequestException as e:
    logger.error(f"Failed to fetch from {source}: {e}")
    raise DataSourceError(f"Source {source} unavailable") from e
```

**Rules:**
- **NEVER swallow errors silently**
- Use custom exceptions for domain errors
-区分可恢复错误和不可恢复错误
- Log errors with appropriate level (warn/error)
- Include context in all error messages
- Propagate errors to caller unless explicitly handled

---

## Security - NON-NEGOTIABLE

- **NEVER** commit `.env`, secrets, keys, or credentials
- Use environment variables for all credentials
- Validate and sanitize all user inputs
- Use parameterized queries for database operations (SQL injection prevention)
- JWT tokens with short expiration (15 min)
- Redis for token blacklist (logout support)
- Hash passwords with bcrypt/argon2 - **NEVER** store plain text

---

## Git Workflow

```bash
# Create feature branch
git checkout -b feature/data-collector-huggingface

# Commit message format
git commit -m "feat: add Hugging Face data collector"
git commit -m "fix: resolve WebSocket heartbeat timeout"
git commit -m "docs: update API documentation"

# Before opening PR
git fetch origin && git rebase origin/main
pytest && npm run lint
```

**Rules:**
- Feature branches from main
- Clear commit messages - "Add user authentication", not "fix"
- **NEVER** force push to main
- Run tests and lint **before** committing

---

## Dependencies

**Rules:**
- Verify package legitimacy before adding
- Prefer well-maintained, widely-used libraries
- Pin dependency versions in `requirements.txt` and `package.json`
- Review security advisories with `pip-audit` and `npm audit`
- **NEVER** add unknown packages

---

## Data Collector Pattern - MANDATORY

```python
class BaseCollector:
    async def fetch(self) -> List[Dict]:
        """Fetch data from source"""
        ...

    def transform(self, raw_data: Dict) -> NormalizedData:
        """Transform to internal format"""
        ...

    async def run(self):
        """Full pipeline: fetch -> transform -> save"""
        raw = await self.fetch()
        data = self.transform(raw)
        await self.save(data)
```

**Rules:**
- Each data source has its own collector class
- Collectors **MUST** inherit from `BaseCollector`
- Implement `fetch()` and `transform()` methods
- Support incremental and full sync modes

---

## WebSocket Communication - MANDATORY

```python
# Data frame format
{
    "timestamp": "2024-01-15T10:30:00Z",
    "type": "update",  # or "full"
    "payload": {
        "gpu_clusters": [...],
        "submarine_cables": [...],
        "ixp_nodes": [...]
    }
}

# Heartbeat every 30 seconds
```

**Rules:**
- UE5 communicates via WebSocket (not REST)
- Send data frames at configured intervals (default: 5 minutes)
- Include camera position in control frames
- Support auto-cruise and manual interaction modes

---

## General Guidelines

- Keep functions small and focused (single responsibility)
- Write self-documenting code; comment **why**, not what
- One concern per file/module
- Dependency injection for testability
- Feature flags for incomplete features
- Use config files for environment-specific settings
