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
+27-19Lines changed: 27 additions & 19 deletions
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,14 @@ If you are using VSCode or Cursor as your IDE, you will need to select the `uv`-
22
22
23
23
If your IDE does not automatically detect and display this option, you can manually select the interpreter by selecting "Enter interpreter path" and then navigating to the `.venv/bin/python` subfolder in your project directory.
24
24
25
+
### Extending the template
26
+
27
+
The `routers/core/` and `utils/core/` directories contain the core backend logic for the template.
28
+
29
+
Your custom Python backend code should go primarily in the `routers/app/` and `utils/app/` directories.
30
+
31
+
For the frontend, you will also need to develop custom Jinja2 templates in the `templates/` folder and add custom static assets in `static/`.
32
+
25
33
### Testing
26
34
27
35
The project uses Pytest for unit testing. It's highly recommended to write and run tests before committing code to ensure nothing is broken!
@@ -57,11 +65,7 @@ We find that mypy is an enormous time-saver, catching many errors early and grea
57
65
58
66
### Developing with LLMs
59
67
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.
68
+
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
69
66
70
## Application architecture
67
71
@@ -71,45 +75,48 @@ In this template, we use FastAPI to define the "API endpoints" of our applicatio
71
75
72
76
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
77
74
-
#### Customizable folders and files
78
+
#### File structure
75
79
76
80
- FastAPI application entry point and homepage GET route: `main.py`
77
-
- FastAPI routes: `routers/`
81
+
-Template FastAPI routes: `routers/core/`
78
82
- Account and authentication endpoints: `account.py`
- Custom FastAPI routes for your app: `routers/app/`
84
89
- Jinja2 templates: `templates/`
85
90
- Static assets: `static/`
86
91
- Unit tests: `tests/`
87
92
- Test database configuration: `docker-compose.yml`
88
-
-Helper functions: `utils/`
93
+
-Template helper functions: `utils/core/`
89
94
- Auth helpers: `auth.py`
90
95
- Database helpers: `db.py`
91
96
- FastAPI dependencies: `dependencies.py`
92
97
- Enums: `enums.py`
93
98
- Image helpers: `images.py`
94
99
- Database models: `models.py`
100
+
- Custom template helper functions for your app: `utils/app/`
95
101
- Exceptions: `exceptions/`
96
102
- HTTP exceptions: `http_exceptions.py`
97
103
- Other custom exceptions: `exceptions.py`
98
-
- Environment variables: `.env.example`
104
+
- Environment variables: `.env.example`, `.env`
99
105
- CI/CD configuration: `.github/`
100
106
- Project configuration: `pyproject.toml`
101
107
- Quarto documentation:
102
108
- README source: `index.qmd`
103
109
- Website source: `index.qmd` + `docs/`
104
-
- Configuration: `_quarto.yml`
110
+
- Configuration: `_quarto.yml` + `_environment`
111
+
- Rules for developing with LLMs in Cursor IDE: `.cursor/rules/`
105
112
106
113
Most everything else is auto-generated and should not be manually modified.
107
114
108
115
## Backend
109
116
110
117
### Code conventions
111
118
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.
119
+
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
120
114
121
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
122
@@ -177,7 +184,7 @@ SQLModel is an Object-Relational Mapping (ORM) library that allows us to interac
177
184
178
185
### Models and relationships
179
186
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:
187
+
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
188
182
189
-`Account`: Represents a user account with email and password hash
183
190
-`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 +199,15 @@ Two additional models are used by SQLModel to manage many-to-many relationships;
192
199
-`UserRoleLink`: Maps users to their roles (many-to-many relationship)
193
200
-`RolePermissionLink`: Maps roles to their permissions (many-to-many relationship)
194
201
195
-
Here's an entity-relationship diagram (ERD) of the current database schema, automatically generated from our SQLModel definitions:
202
+
Here's an entity-relationship diagram (ERD) of the current core database schema, automatically generated from our SQLModel definitions:
196
203
197
204
```{python}
198
205
#| echo: false
199
206
#| warning: false
200
207
import sys
201
208
sys.path.append("..")
202
-
from utils.models import *
203
-
from utils.db import engine
209
+
from utils.core.models import *
210
+
from utils.core.db import engine
204
211
from sqlalchemy import MetaData
205
212
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
231
224
232
### Database helpers
225
233
226
-
Database operations are facilitated by helper functions in `utils/db.py`. Key functions include:
234
+
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
235
228
236
-`set_up_db()`: Initializes the database schema and default data (which we do on every application start in `main.py`)
229
237
-`get_connection_url()`: Creates a database connection URL from environment variables in `.env`
230
238
-`get_session()`: Provides a database session for performing operations
231
239
232
-
To perform database operations in route handlers, inject the database session as a dependency:
240
+
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
250
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:
251
+
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.
260
+
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