This commit is contained in:
John Lancaster
2026-06-16 23:39:45 -05:00
parent 8ada18b7fd
commit c8906cef7b
5 changed files with 269 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
---
icon: simple/markdown
---
# Markdown in 5min
## Headers
```
# H1 Header
## H2 Header
### H3 Header
#### H4 Header
##### H5 Header
###### H6 Header
```
## Text formatting
```
**bold text**
*italic text*
***bold and italic***
~~strikethrough~~
`inline code`
```
## Links and images
```
[Link text](https://example.com)
[Link with title](https://example.com "Hover title")
![Alt text](image.jpg)
![Image with title](image.jpg "Image title")
```
## Lists
```
Unordered:
- Item 1
- Item 2
- Nested item
Ordered:
1. First item
2. Second item
3. Third item
```
## Blockquotes
```
> This is a blockquote
> Multiple lines
>> Nested quote
```
## Code blocks
````
```javascript
function hello() {
console.log("Hello, world!");
}
```
````
## Tables
```
| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Row 1 | Data | Data |
| Row 2 | Data | Data |
```
## Horizontal rule
```
---
or
***
or
___
```
## Task lists
```
- [x] Completed task
- [ ] Incomplete task
- [ ] Another task
```
## Escaping characters
```
Use backslash to escape: \* \_ \# \`
```
## Line breaks
```
End a line with two spaces
to create a line break.
Or use a blank line for a new paragraph.
```
-349
View File
@@ -1,349 +0,0 @@
---
name: nicegui-ui-customization
description: Style, customize, and build interactive UIs in a production-ready NiceGUI app.
---
# NiceGUI UI Customization & Component Patterns
Customize, style, and build interactive user interfaces in a production-ready NiceGUI application. This skill covers component architecture, styling systems, event-driven interactions, and practical troubleshooting for production deployments.
## Goal
Create a well-architected, responsive, accessible UI that:
- Separates structure (Python layout) from cosmetics (CSS styling)
- Handles user interactions via event-driven patterns, not polling
- Composes reusable components with clear responsibilities
- Integrates custom styling and assets cleanly
- Troubleshoots common failures (race conditions, asset caching, upload errors)
## Project Structure & Conceptual Boundaries
This skill assumes a project organized with clear, modular boundaries:
```text
src/app/
├─ ui/
│ ├─ pages/ # Page-level UI modules (route handlers)
│ │ ├─ __init__.py
│ │ ├─ home.py
│ │ ├─ dashboard.py
│ │ └─ about.py
│ ├─ components/ # Reusable presentation components
│ │ ├─ __init__.py
│ │ ├─ nav.py
│ │ ├─ card_section.py
│ │ └─ form_section.py
│ └─ static/ # Static assets (CSS, JS, images)
│ ├─ css/
│ │ ├─ base.css
│ │ ├─ theme.css
│ │ └─ components.css
│ ├─ js/
│ └─ images/
├─ services/ # Business logic layer
│ ├─ __init__.py
│ ├─ file_service.py
│ ├─ user_service.py
│ └─ ...
├─ api/ # HTTP endpoints
│ ├─ __init__.py
│ ├─ health.py
│ └─ routes.py
├─ bootstrap.py # App composition, CSS/asset setup
├─ config.py # Settings and configuration
└─ ...
```
**Key boundaries**:
- **`ui/pages/`**: Route-level adapters that call `services/`
- **`ui/components/`**: Reusable presentation components (no business logic)
- **`ui/static/`**: Assets loaded at startup in `bootstrap.py`
- **`services/`**: Business logic (independent of UI)
- **`api/`**: HTTP endpoints
**Dependency flow**: `pages/``components/` + `services/` (no reverse imports)
---
## UI Component Patterns
Components are the building blocks of reusable UI. They live in `ui/components/` and are consumed by pages in `ui/pages/`. Each component maps to [NiceGUI elements](https://nicegui.io/documentation/element), which expose a consistent API for structure, styling, and event handling.
### Reusable Components
Extract to `ui/components/` when patterns repeat across pages. Keep in-page layouts unique to that page.
```python
# ui/components/card_section.py
def card_section(title: str, content: str) -> ui.card:
with ui.card().classes("w-full max-w-md") as card:
ui.label(title).classes("text-lg font-bold")
ui.label(content).classes("text-gray-600")
return card
```
### Layout Patterns
Use Tailwind for all structural styling. Reserve `.style()` for computed values.
```python
with ui.column().classes("w-full"):
with ui.row().classes("w-full gap-4 flex-wrap sm:flex-nowrap"):
ui.card().classes("flex-1 min-w-64")
ui.card().classes("flex-1 min-w-64")
```
### State Management
Use [bindable dataclasses](https://nicegui.io/documentation/section_binding_properties) for automatic two-way binding.
```python
from nicegui import binding, ui
from dataclasses import field
@binding.bindable_dataclass
class PageState:
selected_id: int | None = None
items: list = field(default_factory=list)
state = PageState()
detail_label = ui.label().bind_text_from(state, 'selected_id')
def on_select(item_id):
state.selected_id = item_id # Auto-updates UI
state.bind_on_change(lambda: load_detail(), 'selected_id')
```
---
## Styling
Use Tailwind for all styling. Use breakpoint prefixes (`sm:`, `md:`, `lg:`) for responsive design.
### Custom CSS Injection ⚠️ Avoid This Pattern
**Avoid injecting custom CSS** via `ui.add_css()` at app startup. Custom CSS injection creates maintenance burden, breaks IDE autocomplete, and makes styling harder to reason about. Instead:
**✅ Prefer these approaches**:
1. **Use [Tailwind utility classes](https://tailwindcss.com/docs/utility-first)** — covers 95% of styling needs with zero CSS overhead.
```python
with ui.column().classes("w-full bg-gradient-to-br from-gray-100 to-gray-200"):
with ui.card().classes("rounded-lg border border-gray-300 shadow-md hover:shadow-lg transition-shadow"):
ui.label("Content")
```
2. **Use [Quasar props](https://quasar.dev/vue-components)** — high-level component theming built into NiceGUI elements.
```python
ui.button("Submit").props("color=primary size=lg")
```
3. **Extract reusable components** — encapsulate styling patterns in Python functions rather than CSS classes.
```python
def styled_card(title: str, content: str) -> ui.card:
with ui.card().classes("rounded-lg border border-gray-300 shadow-md") as card:
ui.label(title).classes("text-lg font-bold")
ui.label(content).classes("text-gray-600")
return card
```
**If you absolutely must inject CSS** (rare edge cases only):
- Store CSS in `src/app/static/css/` files
- Load via `ui.add_css(open('src/app/static/css/custom.css').read())` in `bootstrap.py`
- Keep injected CSS minimal and well-documented
- Avoid hardcoding colors or spacing; use CSS variables instead
### Static Assets
Load CSS files at app startup in `bootstrap.py`:
```python
from fastapi.staticfiles import StaticFiles
app.mount("/static", StaticFiles(directory="src/app/static"), name="static")
ui.add_css(open('src/app/static/css/base.css').read())
```
Use CSS variables for design tokens:
```css
:root {
--color-primary: #3b82f6;
--spacing-unit: 1rem;
}
```
### JS Injection (Rare)
Use `ui.run_javascript()` only for unsupported interactions. Prefer [NiceGUI APIs](https://nicegui.io/documentation/section_action_events) first.
---
## Event-Driven Patterns
NiceGUI provides event-driven APIs for [actions and events](https://nicegui.io/documentation/section_action_events). This section covers common patterns: file uploads, form submissions, WebSocket/SSE for real-time updates, and background tasks.
### File Upload
Validate and notify; delegate storage to service layer.
```python
async def handle_upload(e: ui.events.UploadEventArguments):
try:
if e.size > 10 * 1024 * 1024:
raise ValueError("File too large")
if not e.name.endswith('.pdf'):
raise ValueError("Only PDF allowed")
await file_service.store(e.content.read(), e.name)
ui.notify(f"Uploaded: {e.name}", type="positive")
except ValueError as err:
ui.notify(str(err), type="negative")
ui.upload(on_upload=handle_upload, auto_upload=True)
```
### Form Submission
Bind form inputs to dataclass; validate in service.
```python
@binding.bindable_dataclass
class FormData:
name: str = ""
email: str = ""
data = FormData()
ui.input("Name").bind_value(data, 'name')
ui.input("Email").bind_value(data, 'email')
async def on_submit():
try:
await user_service.create_user(name=data.name, email=data.email)
ui.notify("User created", type="positive")
data.name = data.email = ""
except ValueError as err:
ui.notify(str(err), type="negative")
ui.button("Submit").on_click(on_submit)
```
### Real-Time Updates (WebSocket / SSE)
For streaming updates, use [SSE](https://fastapi.tiangolo.com/advanced/server-sent-events/) (one-way) or [WebSocket](https://fastapi.tiangolo.com/advanced/websockets/) (bidirectional).
```python
# api/events.py
@app.get("/events/status")
async def status_stream():
async def gen():
while True:
yield f"data: {await get_status()}\\n\\n"
await asyncio.sleep(1)
return StreamingResponse(gen(), media_type="text/event-stream")
# Page
status_label = ui.label()
async def listen():
async with aiohttp.ClientSession() as s:
async with s.get("/api/events/status") as r:
async for line in r.content:
if line.startswith(b"data:"):
status_label.set_text(line.decode().replace("data:", "").strip())
ui.timer(0.1, lambda: asyncio.create_task(listen()))
```
### Background Tasks
Delegate long-running work to background tasks; signal UI via polling or WebSocket.
```python
# API
@app.post("/process")
async def process(background_tasks: BackgroundTasks):
background_tasks.add_task(long_job)
return {"status": "processing"}
# Page
async def on_start():
await client.post("/api/process")
ui.notify("Started")
async def check():
status = await client.get("/api/process/status")
if status == "done":
ui.notify("Complete", type="positive")
ui.button("Start").on_click(on_start)
ui.timer(1, check)
```
### Reactive Refresh
Use `@ui.refreshable` with explicit refresh triggers; avoid polling everything.
```python
@ui.refreshable
async def item_list():
items = await service.list()
for item in items:
ui.label(item.name)
ui.button("Refresh").on_click(lambda: item_list.refresh())
```
---
## Advanced Interactions
### Dialogs
```python
dialog = ui.dialog()
async def show_confirm():
with dialog:
ui.label("Are you sure?")
ui.button("Yes").on_click(lambda: (confirm_action(), dialog.close()))
ui.button("No").on_click(dialog.close)
dialog.open()
ui.button("Delete").on_click(show_confirm)
```
### Progress
```python
progress = ui.linear_progress(value=0).classes("w-full")
async def handle_upload(e):
for chunk in read_chunks(e.content):
progress.set_value(uploaded / total)
ui.notify("Complete", type="positive")
```
### Drag & Drop
Use [Quasar q-sortable](https://quasar.dev/vue-components/sortable) for native drag-and-drop support via `.props()`.
---
## Troubleshooting
### Upload Validation & Errors
- Validate file size/extension before storage
- Catch exceptions and emit `ui.notify()` with type "negative"
- Log errors for debugging
### Race Conditions
- Serialize updates: `await service.get_data()` before UI update
- Avoid multiple timers on same component
- Use `button.enabled = False/True` to prevent duplicate submissions
### Asset Caching
- Inject CSS in `bootstrap.py` at startup, not per-page
- Clear browser cache (Ctrl+Shift+Del) or use cache-busting query params: `?v=hash`
- Verify `/static/` mount path and nginx proxy rewrites
### Navigation & State
- Don't store state in globals; keep in `services/` or request-scoped
- Use `ui.navigate.to()` to switch pages
- Reload data in destination page's `@ui.page()` decorator
-387
View File
@@ -1,387 +0,0 @@
---
name: nicegui
description: Build and scaffold production-ready NiceGUI + FastAPI app architecture.
---
# NiceGUI
Build a production-ready, multi-page NiceGUI application that follows modern FastAPI project layout and architecture practices.
## Goal
Create a clean, maintainable app structure where:
- FastAPI is the underlying ASGI app.
- NiceGUI is mounted/initialized in a way that aligns with FastAPI best practices.
- Each page is implemented as a separate module in `pages/`.
- The project is easy to test, extend, and deploy.
## Requirements
- Prefer Pydantic settings with a `.env` example.
- Consider adding structured logging configuration.
- Use a `src/`-style layout with clear package boundaries.
- Use an app factory (`create_app`) and avoid global side effects at import time.
- Register NiceGUI pages from modules in `pages/`.
- Keep UI logic in page modules and shared UI helpers/components in a separate package.
- Include at least these pages:
- Home (`/`)
- Dashboard (`/dashboard`)
- About (`/about`)
- Include a health endpoint (`/healthz`) on the FastAPI side.
- Provide minimal test examples for FastAPI routes and page registration.
- Use FastAPI lifespan for startup/shutdown resource management.
## Recommendations
- Consider a shared navigation/header component and left drawer used by all pages.
- Consider including dev tooling basics (formatting/lint/test commands).
- Prefer clear separation of concerns:
- `db/` for engine/session/base/models/repositories (if needed)
- `api/` for HTTP endpoints
- `ui/` for NiceGUI pages/components
- `services/` for business logic
- If you need database access, a solid pattern is to use FastAPI + SQLAlchemy best practices:
- Use one engine per application process (do not create per request).
- Prefer a request-scoped session dependency using `yield`.
- Keep transaction boundaries explicit (commit/rollback) in service/repository flows.
- Avoid sharing a session across concurrent tasks.
- 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.
### Recommended architecture shape
- Keep LangGraph logic out of `ui/pages/` and out of HTTP route handlers.
- Add an `ai/` package (or similar) and keep graph definition, state schema, tools, and orchestration there.
- Call the graph from `services/` so your UI and API both use the same orchestration entry points.
- Continue using FastAPI lifespan for shared resources (models, clients, stores/checkpointers).
### Suggested project extension
```text
.
└─ src/
└─ app/
├─ ai/
│ ├─ __init__.py
│ ├─ state.py # TypedDict / Pydantic state schemas + reducers
│ ├─ nodes/
│ │ ├─ __init__.py
│ │ ├─ llm.py
│ │ ├─ tools.py
│ │ └─ review.py # optional interrupt/human-review nodes
│ ├─ graphs/
│ │ ├─ __init__.py
│ │ └─ assistant_graph.py
│ ├─ runtime.py # compile() + checkpointer/store wiring
│ └─ contracts.py # input/output DTOs between services and graph
├─ services/
│ └─ ai_service.py # invoke/stream/resume wrappers
└─ api/
└─ ai.py # optional HTTP endpoints for run/stream/resume
```
### Idiomatic LangGraph practices to request
- Define explicit graph state schema (`TypedDict` or Pydantic) and use reducers for append/merge behavior where needed.
- Compile graphs with persistence primitives appropriate to environment:
- dev/testing: in-memory checkpointer/store
- production: durable checkpointer/store
- Always pass a stable `thread_id` in `configurable` for resumable sessions and conversation continuity.
- For interactive UX, prefer event streaming APIs and project-specific streaming adapters in service code.
- Use `interrupt()` for human approvals/reviews; resume with `Command(resume=...)` using the same `thread_id`.
- Keep interrupt payloads JSON-serializable.
- Place non-idempotent side effects after interrupts (or isolate them in separate nodes), because interrupted nodes re-run from the start.
- If using tools, prefer LangGraphs `ToolNode` (or an equivalent centralized tool-execution node) for consistent execution/error handling.
- Keep graph nodes deterministic and narrow in scope (single responsibility per node).
- Add observability with LangSmith tracing for graph runs, transitions, and latency debugging.
### Integration guidance for NiceGUI + FastAPI
- UI pages should call `ai_service` methods, not graph internals.
- If the UX needs live token/progress updates, expose streaming from service -> UI in a transport-appropriate way.
- For approval workflows, surface interrupt payloads in UI, collect user response, then resume via service with `Command(resume=...)`.
- Keep graph invocation boundaries typed (request/response contracts) so changes in graph internals do not leak into page modules.
### Testing recommendations for LangGraph additions
- Unit test node functions as pure transformations where possible.
- Integration test graph routes (happy path, tool path, interrupt/resume path).
- Add tests ensuring `thread_id` reuse resumes correctly and new IDs start fresh sessions.
- Add regression tests for state-schema evolution and serialization compatibility.
## Extending This Pattern with a Static Docs Site via Zensical (Optional)
If the app should also host a static documentation site, mount the generated docs output directory under a configurable route (default: `/docs`).
### Recommended docs workflow
- Initialize docs in the project root:
- `uv run zensical new .`
- Keep source markdown in Zensical's `docs_dir` (default: `docs/`).
- Build docs as part of release or startup pipeline:
- `uv run zensical build`
- Serve the generated static output from Zensical's `site_dir` (default: `site/`).
### Config to include in app settings
- `docs_enabled: bool = true`
- `docs_mount_path: str = "/docs"`
- `docs_site_dir: str = "site"`
- Optional for local/dev convenience:
- `docs_require_build: bool = false` (if true, fail startup when `site/` is missing)
### FastAPI/NiceGUI integration pattern
- Keep docs mounting in the app composition layer (`bootstrap.py`), not in page modules.
- Use FastAPI static serving to mount the built directory (for example via `StaticFiles(..., html=True)`).
- Ensure `docs_mount_path` is normalized (leading slash, no trailing slash) and does not conflict with app/API routes.
- If docs are disabled or build artifacts are missing, log a clear warning and continue (unless `docs_require_build=true`).
### Suggested project additions
```text
.
├─ zensical.toml
├─ docs/
│ ├─ index.md
│ └─ ...
├─ site/ # generated by `uv run zensical build`
└─ src/
└─ app/
├─ config.py # docs_enabled/docs_mount_path/docs_site_dir
└─ bootstrap.py # mount static docs route
```
### Deployment notes for docs mounting
- In CI/CD, run `uv run zensical build` before packaging/deploying the app image.
- If `project.site_dir` in `zensical.toml` is changed, keep `docs_site_dir` in app settings aligned.
- If hosting behind a reverse proxy with a path prefix, verify docs links and static assets with the final external base path.
- Add a test asserting requests to `docs_mount_path` return the built index page when docs are enabled.
## Implementation Notes
- Prefer an explicit page registration function pattern, for example:
- `register_pages()` in `ui/pages/__init__.py`
- Each page module exports `register_page()`
- Keep imports one-way to avoid circular dependencies.
- Keep page modules cohesive: route declaration + page layout for that route.
- Prefer FastAPI lifespan hooks where appropriate for startup/shutdown behavior.
- Prefer type hints throughout.
### Styling architecture notes
- Prefer class-first UI composition for structure and layout using normal NiceGUI mechanics (`.classes(...)` on containers/components).
- Keep structural concerns in Python page/component modules (layout grids, spacing systems, responsive breakpoints, alignment).
- Keep cosmetic concerns in static CSS files (colors, gradients, shadows, border polish, typography fine-tuning, transitions).
- Avoid large inline `style(...)` strings except for one-off dynamic values that must be computed at runtime.
- Centralize CSS entrypoints in a small, predictable set (for example `ui/static/css/base.css`, `ui/static/css/theme.css`, `ui/static/css/components.css`).
- Include CSS once at app bootstrap/startup so pages share the same style contract; avoid per-page ad hoc includes.
- Prefer semantic class names for reusable patterns (`app-shell`, `page-section`, `card-surface`) and utility classes only for local layout tweaks.
- If using design tokens, define them as CSS custom properties in `:root` and reference them from component classes.
- Keep page modules focused on structure and behavior; reusable visual patterns should live in shared UI components plus shared CSS.
### Database-specific notes (only if your app needs a DB)
- Prefer settings via `pydantic-settings` and read `DATABASE_URL` from environment/dotenv.
- Configure the SQLAlchemy engine once at app setup level; avoid creating engine/sessionmaker in endpoint functions.
- Provide `get_db_session()` via `yield` so sessions are consistently closed.
- Prefer a repository/service boundary to keep SQL details out of page modules.
- Prefer Alembic for schema changes and include commands for `revision --autogenerate` and `upgrade head`.
- Avoid `metadata.create_all()` in production startup flow; reserve it for optional local/dev bootstrap paths.
- Consider a light DB readiness check in health reporting (or a dedicated `/readyz`) when relevant.
- Ensure logs do not leak secrets (for example, avoid unsafe SQL echo in production).
## Output Format
The goal of the output is to produce an output
Return:
- A concise, high-level architecture explanation.
- An explanation of how the different parts of the concept will fit into this structure
- What are the core services?
- What are the main ui pages?
- What are the main ui components?
- Whether a database will be involved and whether the app owns the database
- Whether any AI will be used and what the workflow looks like
- A concrete implementation plan in the form of a checklist, organized into sections by concept which should roughly mirror the structure of sub-packages.
- Key functions/classes
- Configuration/settings available
- Migration or rollout notes (if relevant)
## Guardrails
- Do not put all pages in a single file.
- Never use globals, implicit or otherwise.
- Keep code minimal but production-minded.
- Being clear and concise is a higher priority than being verbose.
- Prefer clarity and maintainability over clever abstractions.
## Source Documentation (recommended references)
- FastAPI lifespan events:
- https://fastapi.tiangolo.com/advanced/events/
- FastAPI settings and environment variables:
- https://fastapi.tiangolo.com/advanced/settings/
- FastAPI dependencies with `yield` (session lifecycle pattern):
- https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/
- FastAPI SQL databases tutorial (when using a DB):
- https://fastapi.tiangolo.com/tutorial/sql-databases/
- SQLAlchemy engine configuration and pooling (when using a DB):
- https://docs.sqlalchemy.org/en/20/core/engines.html
- SQLAlchemy session basics and lifecycle guidance (when using a DB):
- https://docs.sqlalchemy.org/en/20/orm/session_basics.html
- Alembic tutorial and migration environment (when using a DB):
- https://alembic.sqlalchemy.org/en/latest/tutorial.html
- Pydantic settings management:
- https://pydantic.dev/docs/validation/latest/concepts/pydantic_settings/
- NiceGUI pages/routing and FastAPI integration:
- https://www.nicegui.io/documentation/section_pages_routing
- NiceGUI security best practices:
- https://www.nicegui.io/documentation/section_security
- LangGraph overview:
- https://docs.langchain.com/oss/python/langgraph/overview
- LangGraph quickstart:
- https://docs.langchain.com/oss/python/langgraph/quickstart
- LangGraph workflows and agents:
- https://docs.langchain.com/oss/python/langgraph/workflows-agents
- LangGraph persistence (checkpointer vs store):
- https://docs.langchain.com/oss/python/langgraph/persistence
- LangGraph memory concepts:
- https://docs.langchain.com/oss/python/concepts/memory
- LangGraph streaming:
- https://docs.langchain.com/oss/python/langgraph/streaming
- LangGraph interrupts / human-in-the-loop:
- https://docs.langchain.com/oss/python/langgraph/interrupts