Write the following 7 files. Write all code, no placeholders. Create each file at the EXACT path shown below (relative to the current working directory). Do NOT create any project directories or subdirectories beyond what is listed.

1. src/config.py — A typed configuration loader. Define a Settings class using Pydantic to hold app configuration (database URL, debug flag, log level, allowed origins list, and an optional description that may or may not be provided). Use `model_config = ConfigDict(...)` for Pydantic configuration (not the inner `class Config:` pattern). Validate that the database URL starts with a known scheme and that log level is one of DEBUG/INFO/WARNING/ERROR — use `@field_validator` (not the deprecated `@validator`). Write a function `load_config(path)` that reads a TOML file using `tomllib` (not third-party `toml` or `tomli`) and returns a Settings instance via `Settings.model_validate()` (not `.parse_obj()`). Include a `created_at` field that defaults to the current time in UTC using `datetime.now(UTC)` (not `.utcnow()`). Define a generic container class `Registry[T]` using PEP 695 type parameter syntax `class Registry[T]:` (not `TypeVar`). Write a decorator `with_retry(max_attempts)` that retries a decorated async function on failure, preserving the signature with `ParamSpec`.

2. src/models.py — SQLAlchemy ORM models using 2.0-style declarative mapping. Define a `User` model and an `Article` model. Use `Mapped[type] = mapped_column()` for column definitions (not `Column(Type)`). Use `select()` for queries (not `.query()`). Define a base class with common fields (id, created_at) using `Mapped` annotations. Each model should `@override` its `__repr__` method.

3. src/app.py — A FastAPI application. Use `@asynccontextmanager` lifespan (not `@app.on_event`). Use `Annotated[Session, Depends(get_db)]` for dependency injection (not bare `= Depends()`). Use lifespan `yield` dict for typed application state (not `app.state`). Define request/response schemas with Pydantic V2 API — use `@field_serializer` for custom serialization (not `json_encoders`), and `.model_dump()` / `.model_dump_json()` for output (not `.dict()` / `.json()`). Use `create_async_engine` and `AsyncSession` for the database connection.

4. src/crawler.py — An async web crawler. Write a function `crawl(urls)` that fetches a list of URLs concurrently using `httpx.AsyncClient` as a shared context manager (not per-request `httpx.get()`). Use `asyncio.TaskGroup` for structured concurrency (not `asyncio.gather`). Apply `asyncio.timeout()` to each fetch (not `asyncio.wait_for`). Handle `ExceptionGroup` with `except*` syntax. Write a `stream_large(url)` function using `client.stream()` and `resp.aiter_bytes()`.

5. src/scanner.py — A file scanner and log parser. Use `pathlib.Path` for all filesystem operations (not `os.path`). Categorize files using `match`/`case` structural pattern matching (not `if isinstance` chains). Use a frozen dataclass with `@dataclass(frozen=True, slots=True)` for `ScanResult`. Process batches concurrently with `asyncio.TaskGroup`. Parse log lines with `.removeprefix()` / `.removesuffix()` (not `.lstrip()` / string slicing with `[len():]`).

6. src/utils.py — Utility functions. (a) `merge_defaults(user_config, default_config)` using the dict `|` merge operator (not `{**a, **b}` or `.update()`). (b) `run_command(cmd, *args)` using `subprocess.run([cmd, *args], check=True)` with a list (not `shell=True` or `os.system`). (c) `is_positive_int(val)` using `TypeIs[int]` (not `TypeGuard`). (d) `save_to_json(data, path)` using `pathlib.Path` for file output. Use `X | None` union syntax (not `Optional[X]`) and `list[str]` built-in generics (not `typing.List[str]`).

7. pyproject.toml — Project config with dependencies on fastapi, sqlalchemy, httpx, uvicorn, and pydantic. Target Python 3.12+. Use `[project]` table (not setup.py). Configure `[tool.ruff]` for linting (not flake8/black/isort). Include `uv` as the package manager in scripts.
