better
This commit is contained in:
+128
-61
@@ -43,6 +43,134 @@ Create a clean, maintainable app structure where:
|
||||
- Consider production-minded pool settings (`pool_pre_ping=True` and sensible recycle/timeout values).
|
||||
- Prefer Alembic for schema migrations.
|
||||
|
||||
## Suggested Project Structure
|
||||
|
||||
Base structure (no database required):
|
||||
|
||||
```text
|
||||
.
|
||||
├─ pyproject.toml
|
||||
├─ .env.example
|
||||
├─ README.md
|
||||
├─ src/
|
||||
│ └─ app/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ main.py
|
||||
│ ├─ config.py
|
||||
│ ├─ logging.py
|
||||
│ ├─ api/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ health.py
|
||||
│ ├─ services/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ example_service.py
|
||||
│ ├─ ui/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ ├─ components/
|
||||
│ │ │ ├─ __init__.py
|
||||
│ │ │ └─ nav.py
|
||||
│ │ └─ pages/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ ├─ home.py
|
||||
│ │ ├─ dashboard.py
|
||||
│ │ └─ about.py
|
||||
│ └─ bootstrap.py
|
||||
└─ tests/
|
||||
├─ test_health.py
|
||||
└─ test_pages_registration.py
|
||||
```
|
||||
|
||||
### Conceptual boundaries for the base structure
|
||||
|
||||
- `main.py`: application entrypoint only; wires `create_app()` and process startup concerns.
|
||||
- `bootstrap.py`: app composition layer; owns app factory, router registration, page registration, and lifespan wiring.
|
||||
- `config.py`: configuration boundary; centralizes settings parsing and typed config objects.
|
||||
- `logging.py`: observability boundary; centralizes logging format/levels/handlers so modules do not configure logging ad hoc.
|
||||
- `api/`: transport boundary for HTTP endpoints; validate/shape request-response objects and delegate business work to `services/`.
|
||||
- `services/`: use-case/business boundary; orchestrates domain behavior and dependencies, independent of UI rendering.
|
||||
- `ui/pages/`: route-level UI boundary; one module per page, focused on layout/event handling for that page.
|
||||
- `ui/components/`: reusable presentation boundary; shared UI widgets/composition utilities with no business side effects.
|
||||
- `tests/`: behavior boundary; verify public behavior (health endpoint, page registration, service outcomes), not private implementation details.
|
||||
|
||||
### Dependency direction to keep clear
|
||||
|
||||
- Prefer this dependency flow:
|
||||
- `main/bootstrap` -> `config/logging` + `api` + `ui/pages` + `services`
|
||||
- `api` -> `services`
|
||||
- `ui/pages` -> `ui/components` + `services`
|
||||
- `services` -> pure helpers/clients (and later `db/` if enabled)
|
||||
- Avoid reverse imports (for example, `services` importing from `ui/pages` or `api`).
|
||||
- Keep page modules and API handlers as thin adapters; keep business decisions in `services/`.
|
||||
|
||||
## Extending This Pattern with a Database (Optional)
|
||||
|
||||
If database access is needed, extend with:
|
||||
|
||||
```text
|
||||
.
|
||||
├─ alembic.ini
|
||||
├─ alembic/
|
||||
│ ├─ env.py
|
||||
│ └─ versions/
|
||||
├─ src/
|
||||
│ └─ app/
|
||||
│ └─ db/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ base.py
|
||||
│ ├─ session.py
|
||||
│ ├─ models/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ example.py
|
||||
│ └─ repositories/
|
||||
│ ├─ __init__.py
|
||||
│ └─ example_repo.py
|
||||
└─ tests/
|
||||
└─ test_db_session_dependency.py
|
||||
```
|
||||
|
||||
### Recommended database layering
|
||||
|
||||
- Keep `db/` focused on persistence primitives:
|
||||
- `session.py`: engine + session factory + dependency helpers
|
||||
- `models/`: ORM table mappings only
|
||||
- `repositories/`: query/persistence operations only
|
||||
- Keep transaction orchestration in `services/`, not in UI pages.
|
||||
- Keep `ui/pages/` free of SQLAlchemy details; pages call services.
|
||||
- Keep API handlers thin and delegate data work to services/repositories.
|
||||
|
||||
### Session and transaction pattern to request
|
||||
|
||||
- Use one engine and one sessionmaker per process, initialized at app startup.
|
||||
- Use a `get_db_session()` dependency with `yield` for request-scoped sessions.
|
||||
- In write flows, always use context managers for commit/rollback safety.
|
||||
- In read-only flows, avoid unnecessary transactions and keep queries narrowly scoped.
|
||||
- Do not share a session across concurrent tasks; open a new session per task/unit of work.
|
||||
|
||||
### Migration and schema workflow
|
||||
|
||||
- Treat Alembic migrations as the source of truth for schema evolution.
|
||||
- Prefer:
|
||||
- `alembic revision --autogenerate -m "..."`
|
||||
- review migration script
|
||||
- `alembic upgrade head`
|
||||
- Avoid relying on `metadata.create_all()` for production schema management.
|
||||
- Include a lightweight startup check that logs current migration state (without mutating schema).
|
||||
|
||||
### Configuration and runtime concerns
|
||||
|
||||
- Read `DATABASE_URL` from settings (`pydantic-settings`) and keep secrets out of source control.
|
||||
- Configure pool options appropriate for environment (for example: `pool_pre_ping`, timeout/recycle tuning).
|
||||
- Keep SQL echo/debug logging disabled in production by default.
|
||||
- Consider a readiness probe (`/readyz`) that verifies DB connectivity when your deployment needs it.
|
||||
|
||||
### Testing guidance for DB-enabled projects
|
||||
|
||||
- Unit test repositories against a disposable test database.
|
||||
- Integration test `get_db_session()` lifecycle and rollback behavior on failures.
|
||||
- Add migration tests that validate model changes are represented in Alembic revisions.
|
||||
- Add API/service tests for critical read/write paths (including uniqueness and constraint errors).
|
||||
- Keep DB tests isolated and deterministic (fresh schema + transactional cleanup per test module/session).
|
||||
|
||||
## Extending This Pattern with LangGraph (Optional)
|
||||
|
||||
If your app needs multi-step AI workflows, tool-calling loops, or human-in-the-loop approvals, a clean extension is to add a dedicated LangGraph domain layer.
|
||||
@@ -108,67 +236,6 @@ If your app needs multi-step AI workflows, tool-calling loops, or human-in-the-l
|
||||
- Add tests ensuring `thread_id` reuse resumes correctly and new IDs start fresh sessions.
|
||||
- Add regression tests for state-schema evolution and serialization compatibility.
|
||||
|
||||
## Suggested Project Structure
|
||||
|
||||
Base structure (no database required):
|
||||
|
||||
```text
|
||||
.
|
||||
├─ pyproject.toml
|
||||
├─ .env.example
|
||||
├─ README.md
|
||||
├─ src/
|
||||
│ └─ app/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ main.py
|
||||
│ ├─ config.py
|
||||
│ ├─ logging.py
|
||||
│ ├─ api/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ health.py
|
||||
│ ├─ services/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ example_service.py
|
||||
│ ├─ ui/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ ├─ components/
|
||||
│ │ │ ├─ __init__.py
|
||||
│ │ │ └─ nav.py
|
||||
│ │ └─ pages/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ ├─ home.py
|
||||
│ │ ├─ dashboard.py
|
||||
│ │ └─ about.py
|
||||
│ └─ bootstrap.py
|
||||
└─ tests/
|
||||
├─ test_health.py
|
||||
└─ test_pages_registration.py
|
||||
```
|
||||
|
||||
If database access is needed, extend with:
|
||||
|
||||
```text
|
||||
.
|
||||
├─ alembic.ini
|
||||
├─ alembic/
|
||||
│ ├─ env.py
|
||||
│ └─ versions/
|
||||
├─ src/
|
||||
│ └─ app/
|
||||
│ └─ db/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ base.py
|
||||
│ ├─ session.py
|
||||
│ ├─ models/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ example.py
|
||||
│ └─ repositories/
|
||||
│ ├─ __init__.py
|
||||
│ └─ example_repo.py
|
||||
└─ tests/
|
||||
└─ test_db_session_dependency.py
|
||||
```
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Prefer an explicit page registration function pattern, for example:
|
||||
|
||||
Reference in New Issue
Block a user