Enthält: - rdp_client.py: RDP Client mit GUI und Monitor-Auswahl - rdp.sh: Bash-basierter RDP Client - teamleader_test/: Network Scanner Fullstack-App - teamleader_test2/: Network Mapper CLI Subdirectories mit eigenem Repo wurden ausgeschlossen. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 KiB
Copilot Instructions for Network Scanner Tool
🚨 MANDATORY: Read Before Making Changes
Documentation-First Workflow (ENFORCED)
BEFORE suggesting any changes:
- Check docs/index.md - Find relevant documentation
- Search docs/guides/troubleshooting.md - Known issues and solutions
- Review CONTRIBUTING.md - Development workflow and standards
- Verify docs/project-status.md - Current feature status
AFTER making changes:
- Update relevant documentation in
docs/directory - Add troubleshooting entry if fixing a bug
- Update docs/project-status.md if feature status changes
- Never create ad-hoc markdown files - use existing
docs/structure
Quick Overview
This is a containerized full-stack network scanning and visualization tool:
- Backend: Python 3.11 + FastAPI (async) + SQLite with SQLAlchemy ORM
- Frontend: React 18 + TypeScript + TailwindCSS + React Flow visualization
- Deployment: Docker Compose with nginx reverse proxy
- Purpose: Discover hosts, detect open ports/services, visualize network topology with Visio-style interactive diagrams
Key Path: /home/rwiegand/Nextcloud/entwicklung/Werkzeuge/teamleader_test/
Critical Architecture Patterns
1. Data Flow: Backend → Frontend
Database (SQLite) → SQLAlchemy ORM → Pydantic Schemas → REST API/JSON
↓
Frontend React Components
(via hooks + axios)
Important: Schema changes in app/schemas.py must match TypeScript types in frontend/src/types/api.ts. Mismatch causes 500 errors or type failures.
2. Session Management (Critical Bug Source)
Problem: Async background tasks can't use scoped sessions—they close after request completion.
Solution (used in app/api/endpoints/scans.py):
# ❌ DON'T: Use shared session from request
background_tasks.add_task(scan_service.execute_scan, scan_id, db)
# ✅ DO: Create new session in background task wrapper
def scan_wrapper(scan_id: int):
db = SessionLocal() # New session!
try:
scan_service.execute_scan(scan_id, db)
finally:
db.close()
background_tasks.add_task(scan_wrapper, scan_id)
3. Database Constraints (Critical)
Rule: Always commit() and refresh() host objects before adding dependent records (services, connections).
Example (from app/services/scan_service.py):
host = self._get_or_create_host(ip)
self.db.commit() # ← CRITICAL: Ensure host.id is set
self.db.refresh(host)
# NOW safe to add services
service = Service(host_id=host.id, port=80) # host.id exists
self.db.add(service)
4. WebSocket Broadcasting
Located in app/api/endpoints/websocket.py. Pattern:
# Broadcast to all connected clients
await connection_manager.broadcast({
"type": "scan_progress",
"data": {"progress": 0.75, "current_host": "192.168.1.5"}
})
Integrated in ScanService to push real-time updates during scans.
Project Structure Deep Dive
Backend (app/)
| Component | Purpose | Critical Points |
|---|---|---|
models.py |
SQLAlchemy ORM | Use Connection.extra_data not .metadata (reserved). Check cascade rules. |
schemas.py |
Pydantic validation | Must have .model_rebuild() for forward refs (e.g., HostDetailResponse). |
services/scan_service.py |
Scan orchestration | Uses WebSocket callbacks. Commit after host creation. |
services/topology_service.py |
Graph generation | Simplified to return flat TopologyNode/TopologyEdge structures. |
api/endpoints/ |
REST routes | Use SessionLocal() wrapper for background tasks. |
scanner/ |
Network scanning | Socket-based (default, no root) + optional nmap integration. |
Frontend (frontend/src/)
| Component | Purpose | Critical Points |
|---|---|---|
pages/Dashboard.tsx |
Home + scan control | Displays real-time progress bar via WebSocket. |
pages/NetworkPage.tsx |
Network map page | Integrated click handler via HostDetailsPanel. |
components/NetworkMap.tsx |
React Flow visualization | Creates nodes with circular layout, handles node clicks. |
components/HostDetailsPanel.tsx |
Host detail sidebar | Right-side panel, fetches via hostApi.getHost(). |
hooks/useTopology.ts |
Topology data | Fetches from /api/topology. |
services/api.ts |
Axios client | Base URL from VITE_API_URL env var. |
types/api.ts |
TypeScript interfaces | Must match backend schemas exactly. |
Build & Deployment
Development
cd teamleader_test
docker compose up -d --build
# Frontend: http://localhost (nginx reverse proxy)
# Backend API: http://localhost:8000
# Docs: http://localhost:8000/docs
Common Issues & Fixes
| Error | Cause | Fix |
|---|---|---|
500 Error on /api/topology |
TopologyNode missing position field |
Remove _calculate_layout() call (positions not in simplified schema) |
| Frontend type mismatch | Backend returns network_range, frontend expects target |
Update frontend/src/types/api.ts interface |
DetachedInstanceError in async task |
Session closed after request | Use SessionLocal() wrapper in background task |
NOT NULL constraint failed: host_id |
Services added before host committed | Add db.commit() + db.refresh(host) after creation |
| Scan progress not updating | WebSocket not connected | Verify useWebSocket() hook in Dashboard, check /api/ws endpoint |
Database Schema (Key Tables)
# 5 main tables:
Scan # Scan operations (status, network_range, timestamps)
Host # Discovered hosts (ip_address UNIQUE, status, hostname)
Service # Open ports (host_id FK, port, state, banner)
Connection # Relationships (source_host_id, target_host_id, confidence)
scan_hosts # Many-to-many (scan_id, host_id)
Column rename: Connection.metadata → Connection.extra_data (metadata is SQLAlchemy reserved).
API Response Contract
Topology Response (/api/topology)
{
nodes: TopologyNode[], // id, ip, hostname, type, status, service_count, connections
edges: TopologyEdge[], // source, target, type, confidence
statistics: {
total_nodes: number,
total_edges: number,
isolated_nodes: number,
avg_connections: number
}
}
Scan Start Response (POST /api/scans/start)
{
scan_id: number,
message: string,
status: 'pending' | 'running'
}
Note: Frontend uses scan.scan_id not scan.id.
Docker Compose Setup
- Backend container:
network-scanner-backendon port 8000 - Frontend container:
network-scanner-frontendon port 80 (nginx) - Shared volume:
./data/for SQLite database - Network:
scanner-network(bridge)
# Rebuild after code changes
docker compose up -d --build
# View logs
docker compose logs backend --tail=50
docker compose logs frontend --tail=50
# Stop all
docker compose down
Common Development Tasks
Add New API Endpoint
- Create handler in
app/api/endpoints/new_feature.py - Add to
app/api/__init__.pyrouter - Define request/response Pydantic models in
app/schemas.py - Add TypeScript type in
frontend/src/types/api.ts - Add service method in
frontend/src/services/api.ts - Create React hook or component to call it
Modify Database Schema
- Update SQLAlchemy model in
app/models.py - Delete
network_scanner.db(dev only) or create migration - Restart backend:
docker compose up -d --build backend
Add Frontend Component
- Create
.tsxfile infrontend/src/components/ - Import API types from
frontend/src/types/api.ts - Use Axios via
frontend/src/services/api.ts - Integrate into page/parent component
- Rebuild:
docker compose up -d --build frontend
Debugging Checklist
- Backend not responding? Check
docker compose logs backendfor errors - Frontend showing blank page? Open browser console (F12) for errors, check
VITE_API_URL - Type errors on build? Verify
frontend/src/types/api.tsmatches backend response - Database locked? Only one writer at a time with SQLite—check for stuck processes
- WebSocket not connecting? Verify
/api/wsendpoint exists, check backend logs - Scan never completes? Check
docker compose logs backendfor exceptions, verifycancel_requestedflag
Conventions
- Logging: Use
logger.info()for key events,logger.error()for failures - Database: Use SQLAlchemy relationships, avoid raw SQL
- API Responses: Always wrap in Pydantic models, validate input
- Async: Use
asyncio.Taskfor background scans, newSessionLocal()for session - Frontend: Use TypeScript strict mode, never bypass type checking
- Styling: TailwindCSS only, no inline CSS (except React Flow inline styles)
- Comments: Document "why", not "what"—code is self-documenting
Key Files to Reference
- Architecture overview: docs/architecture/overview.md (comprehensive design decisions)
- Database models: app/models.py
- API schemas: app/schemas.py
- Scan orchestration: app/services/scan_service.py (async patterns, WebSocket integration)
- Topology service: app/services/topology_service.py (graph generation logic)
- Frontend types: frontend/src/types/api.ts
- Network Map: frontend/src/components/NetworkMap.tsx (React Flow usage, click handling)
- Docker setup: docker-compose.yml
Testing Commands
# Health check
curl -s http://localhost/health | jq .
# Start scan (quick 192.168.1.0/24)
curl -X POST http://localhost:8000/api/scans/start \
-H "Content-Type: application/json" \
-d '{"network_range":"192.168.1.0/24","scan_type":"quick"}'
# Get topology
curl -s http://localhost/api/topology | jq '.nodes | length'
# List hosts
curl -s http://localhost/api/hosts | jq 'length'
# Get specific host
curl -s http://localhost/api/hosts/1 | jq .
Version Info
- Python: 3.11
- FastAPI: 0.109.0
- React: 18.2.0
- TypeScript: 5.2.2
- Last Updated: December 4, 2025
Contact & Escalation
For questions on:
- Architecture: See
ARCHITECTURE.md - Build issues: Check
docker compose logs backend/frontend - Type errors: Verify
app/schemas.py↔frontend/src/types/api.tsalignment - Runtime crashes: Enable
DEBUG=Truein.env, check logs directory