You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .cursor/rules/routers.mdc
+3-3Lines changed: 3 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,12 @@
1
1
---
2
2
description: Testing FastAPI routes
3
-
globs: routers/*.py
3
+
globs: routers/**/*.py
4
4
alwaysApply: false
5
5
---
6
6
Here are the five most critical patterns to maintain consistency when adding a new router:
7
7
8
8
1. **Authentication & Dependency Injection**
9
-
- Import `get_authenticated_user` from `utils.dependencies` and include `user: User = Depends(get_authenticated_user)` in the arguments of routes requiring authentication
9
+
- Import `get_authenticated_user` from `utils.core.dependencies` and include `user: User = Depends(get_authenticated_user)` in the arguments of routes requiring authentication
10
10
- Similarly, use the `get_optional_user` dependency for public routes with potential auth status
11
11
12
12
2. **Validation Patterns**
@@ -21,7 +21,7 @@ Here are the five most critical patterns to maintain consistency when adding a n
21
21
- Check permissions at both route and template levels via `user_permissions`
22
22
23
23
4. **Database & Transaction Patterns**
24
-
- Inject session via `Depends(get_session)`
24
+
- Inject session via `Depends(get_session)` from `utils/core/dependencies.py`
25
25
- Commit after writes and refresh objects where needed
26
26
- Use `selectinload` for eager loading relationships
27
27
- Follow PRG pattern with RedirectResponse after mutations
description: Building, running, and debugging tests
3
-
globs: tests/*.py
3
+
globs: tests/**.py
4
4
alwaysApply: false
5
5
---
6
6
This project uses `uv` for dependency management, so tests must be run with `uv run pytest` to ensure they are run in the project's virtual environment.
@@ -9,4 +9,4 @@ The project uses test-driven development, so failing tests are often what we wan
9
9
10
10
Session-wide test setup is performed in `tests/conftest.py`. In that file, you will find fixtures that can and should be reused across the test suite, including fixtures for database setup and teardown. We have intentionally used PostgreSQL, not SQLite, in the test suite to keep the test environment as production-like as possible, and you should never change the database engine unless explicitly told to do so.
11
11
12
-
If you find that the test database is not available, you may need to start Docker Desktop with `systemctl --user start docker-desktop` or the database with `docker compose up`. You may `grep` the `DB_PORT=` line from `.env` if you need to know what port the database is available on. (This environment variable is used for port mapping in `docker-compose.yml` as well as in the `get_connection_url` function defined in `utils/db.py`.) If dropping tables fails during test setup due to changes to the database schema, `docker compose down -v && docker compose up` may resolve the issue.
12
+
If you find that the test database is not available, you may need to start Docker Desktop with `systemctl --user start docker-desktop` or the database with `docker compose up`. You may `grep` the `DB_PORT=` line from `.env` if you need to know what port the database is available on. (This environment variable is used for port mapping in `docker-compose.yml` as well as in the `get_connection_url` function defined in `utils/core/db.py`.) If dropping tables fails during test setup due to changes to the database schema, `docker compose down -v && docker compose up` may resolve the issue.
Copy file name to clipboardExpand all lines: docs/customization.qmd
+19-19Lines changed: 19 additions & 19 deletions
Original file line number
Diff line number
Diff line change
@@ -57,11 +57,7 @@ We find that mypy is an enormous time-saver, catching many errors early and grea
57
57
58
58
### Developing with LLMs
59
59
60
-
In line with the [llms.txt standard](https://llmstxt.org/), we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a text file: [llms.txt](static/llms.txt).
61
-
62
-
One use case for this file, if using the Cursor IDE, is to rename it to `.cursorrules` and place it in your project directory (see the [Cursor docs](https://docs.cursor.com/context/rules-for-ai) on this for more information). Alternatively, you could use it as a custom system prompt in the web interface for ChatGPT, Claude, or the LLM of your choice.
63
-
64
-
We have also exposed the full Markdown-formatted project documentation as a [single text file](static/documentation.txt) for easy downloading and embedding for RAG workflows.
60
+
The `.cursor/rules` folder contains a set of AI rules for working on this codebase in the Cursor IDE. We have also provided an [llms.txt](static/llms.txt) system prompt file for use with other agentic LLM workflows and exposed the full Markdown-formatted project documentation as a [single text file](docs/static/documentation.txt) for easy downloading and embedding for RAG.
65
61
66
62
## Application architecture
67
63
@@ -71,45 +67,48 @@ In this template, we use FastAPI to define the "API endpoints" of our applicatio
71
67
72
68
We also create POST endpoints, which accept form submissions so the user can create, update, and delete data in the database. This template follows the Post-Redirect-Get (PRG) pattern to handle POST requests. When a form is submitted, the server processes the data and then returns a "redirect" response, which sends the user to a GET endpoint to re-render the page with the updated data. (See [Architecture](https://promptlytechnologies.com/fastapi-jinja2-postgres-webapp/docs/architecture.html) for more details.)
73
69
74
-
#### Customizable folders and files
70
+
#### File structure
75
71
76
72
- FastAPI application entry point and homepage GET route: `main.py`
77
-
- FastAPI routes: `routers/`
73
+
-Template FastAPI routes: `routers/core/`
78
74
- Account and authentication endpoints: `account.py`
- Custom FastAPI routes for your app: `routers/app/`
84
81
- Jinja2 templates: `templates/`
85
82
- Static assets: `static/`
86
83
- Unit tests: `tests/`
87
84
- Test database configuration: `docker-compose.yml`
88
-
-Helper functions: `utils/`
85
+
-Template helper functions: `utils/core/`
89
86
- Auth helpers: `auth.py`
90
87
- Database helpers: `db.py`
91
88
- FastAPI dependencies: `dependencies.py`
92
89
- Enums: `enums.py`
93
90
- Image helpers: `images.py`
94
91
- Database models: `models.py`
92
+
- Custom template helper functions for your app: `utils/app/`
95
93
- Exceptions: `exceptions/`
96
94
- HTTP exceptions: `http_exceptions.py`
97
95
- Other custom exceptions: `exceptions.py`
98
-
- Environment variables: `.env.example`
96
+
- Environment variables: `.env.example`, `.env`
99
97
- CI/CD configuration: `.github/`
100
98
- Project configuration: `pyproject.toml`
101
99
- Quarto documentation:
102
100
- README source: `index.qmd`
103
101
- Website source: `index.qmd` + `docs/`
104
-
- Configuration: `_quarto.yml`
102
+
- Configuration: `_quarto.yml` + `_environment`
103
+
- Rules for developing with LLMs in Cursor IDE: `.cursor/rules/`
105
104
106
105
Most everything else is auto-generated and should not be manually modified.
107
106
108
107
## Backend
109
108
110
109
### Code conventions
111
110
112
-
The GET route for the homepage is defined in the main entry point for the application, `main.py`. The entrypoint imports router modules from the `routers/` directory, which contain the other GET and POST routes for the application. In CRUD style, the router modules are named after the resource they manage, e.g., `account.py` for account management.
111
+
The GET route for the homepage is defined in the main entry point for the application, `main.py`. The entrypoint imports router modules from the `routers/core/` directory (for core/template logic) and `routers/app/` directory (for app-specific logic). In CRUD style, the core router modules are named after the resource they manage, e.g., `account.py` for account management. You should place your own endpoints in `routers/app/`.
113
112
114
113
We name our GET routes using the convention `read_<name>`, where `<name>` is the name of the resource, to indicate that they are read-only endpoints that do not modify the database. In POST routes that modify the database, you can use the `get_session` dependency as an argument to get a database session.
115
114
@@ -177,7 +176,7 @@ SQLModel is an Object-Relational Mapping (ORM) library that allows us to interac
177
176
178
177
### Models and relationships
179
178
180
-
Our database models are defined in `utils/models.py`. Each model is a Python class that inherits from `SQLModel` and represents a database table. The key models are:
179
+
Core database models are defined in `utils/core/models.py`. Each model is a Python class that inherits from `SQLModel` and represents a database table. The key core models are:
181
180
182
181
-`Account`: Represents a user account with email and password hash
183
182
-`User`: Represents a user profile with details like name and avatar; the email and password hash are stored in the related `Account` model
@@ -192,15 +191,15 @@ Two additional models are used by SQLModel to manage many-to-many relationships;
192
191
-`UserRoleLink`: Maps users to their roles (many-to-many relationship)
193
192
-`RolePermissionLink`: Maps roles to their permissions (many-to-many relationship)
194
193
195
-
Here's an entity-relationship diagram (ERD) of the current database schema, automatically generated from our SQLModel definitions:
194
+
Here's an entity-relationship diagram (ERD) of the current core database schema, automatically generated from our SQLModel definitions:
196
195
197
196
```{python}
198
197
#| echo: false
199
198
#| warning: false
200
199
import sys
201
200
sys.path.append("..")
202
-
from utils.models import *
203
-
from utils.db import engine
201
+
from utils.core.models import *
202
+
from utils.core.db import engine
204
203
from sqlalchemy import MetaData
205
204
from sqlalchemy_schemadisplay import create_schema_graph
To extend the database schema, define your own models in `utils/app/models.py` and import them in `utils/core/db.py` to make sure they are included in the `metadata` object in the `create_all` function.
223
223
224
224
### Database helpers
225
225
226
-
Database operations are facilitated by helper functions in `utils/db.py`. Key functions include:
226
+
Database operations are facilitated by helper functions in `utils/core/db.py` (for core logic) and `utils/app/` (for app-specific helpers). Key functions in the core utils include:
227
227
228
228
-`set_up_db()`: Initializes the database schema and default data (which we do on every application start in `main.py`)
229
229
-`get_connection_url()`: Creates a database connection URL from environment variables in `.env`
230
230
-`get_session()`: Provides a database session for performing operations
231
231
232
-
To perform database operations in route handlers, inject the database session as a dependency:
232
+
To perform database operations in route handlers, inject the database session as a dependency (from `utils/core/db.py`):
The session automatically handles transaction management, ensuring that database operations are atomic and consistent.
242
242
243
-
There is also a helper method on the `User` model that checks if a user has a specific permission for a given organization. Its first argument must be a `ValidPermissions` enum value (from `utils/models.py`), and its second argument must be an `Organization` object or an `int` representing an organization ID:
243
+
There is also a helper method on the `User` model that checks if a user has a specific permission for a given organization. Its first argument must be a `ValidPermissions` enum value (from `utils/core/models.py`), and its second argument must be an `Organization` object or an `int` representing an organization ID:
You should create custom `ValidPermissions` enum values for your application and validate that users have the necessary permissions before allowing them to modify organization data resources.
252
+
You should create custom `AppPermissions` enum values for your application in `utils/app/` (if needed) and validate that users have the necessary permissions before allowing them to modify organization data resources.
Copy file name to clipboardExpand all lines: index.qmd
+1-5Lines changed: 1 addition & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -207,11 +207,7 @@ with open(output_path, 'w', encoding='utf-8') as f:
207
207
f.write(final_content)
208
208
```
209
209
210
-
In line with the [llms.txt standard](https://llmstxt.org/), we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a text file: [llms.txt](docs/static/llms.txt).
211
-
212
-
One use case for this file, if using the Cursor IDE, is to rename it to `.cursorrules` and place it in your project directory (see the [Cursor docs](https://docs.cursor.com/context/rules-for-ai) on this for more information). Alternatively, you could use it as a custom system prompt in the web interface for ChatGPT, Claude, or the LLM of your choice.
213
-
214
-
We have also exposed the full Markdown-formatted project documentation as a [single text file](docs/static/documentation.txt) for easy downloading and embedding for RAG workflows.
210
+
The `.cursor/rules` folder contains a set of AI rules for working on this codebase in the Cursor IDE. We have also provided an [llms.txt](static/llms.txt) system prompt file for use with other agentic LLM workflows and exposed the full Markdown-formatted project documentation as a [single text file](docs/static/documentation.txt) for easy downloading and embedding for RAG.
0 commit comments