Skip to content

Commit 4224b22

Browse files
Re-render database model diagram and update LLMs.txt
1 parent 5ba8044 commit 4224b22

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

docs/static/llms.txt

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ To use password recovery, register a [Resend](https://resend.com/) account, veri
105105

106106
### Start development database
107107

108+
To start the development database, run the following command in your terminal from the root directory:
109+
108110
``` bash
109111
docker compose up -d
110112
```
@@ -515,6 +517,8 @@ If you use VSCode with Docker to develop in a container, the following VSCode De
515517

516518
Simply create a `.devcontainer` folder in the root of the project and add a `devcontainer.json` file in the folder with the above content. VSCode may prompt you to install the Dev Container extension if you haven't already, and/or to open the project in a container. If not, you can manually select "Dev Containers: Reopen in Container" from View > Command Palette.
517519

520+
*IMPORTANT: If using this dev container configuration, you will need to set the `DB_HOST` environment variable to "host.docker.internal" in the `.env` file.*
521+
518522
## Install development dependencies manually
519523

520524
### Python and Docker
@@ -598,15 +602,32 @@ Set your desired database name, username, and password in the .env file.
598602

599603
To use password recovery, register a [Resend](https://resend.com/) account, verify a domain, get an API key, and paste the API key into the .env file.
600604

605+
If using the dev container configuration, you will need to set the `DB_HOST` environment variable to "host.docker.internal" in the .env file. Otherwise, set `DB_HOST` to "localhost" for local development. (In production, `DB_HOST` will be set to the hostname of the database server.)
606+
601607
## Start development database
602608

609+
To start the development database, run the following command in your terminal from the root directory:
610+
603611
``` bash
604612
docker compose up -d
605613
```
606614

615+
If at any point you change the environment variables in the .env file, you will need to stop the database service *and tear down the volume*:
616+
617+
``` bash
618+
# Don't forget the -v flag to tear down the volume!
619+
docker compose down -v
620+
```
621+
622+
You may also need to restart the terminal session to pick up the new environment variables. You can also add the `--force-recreate` and `--build` flags to the startup command to ensure the container is rebuilt:
623+
624+
``` bash
625+
docker compose up -d --force-recreate --build
626+
```
627+
607628
## Run the development server
608629

609-
Make sure the development database is running and tables and default permissions/roles are created first.
630+
Before running the development server, make sure the development database is running and tables and default permissions/roles are created first. Then run the following command in your terminal from the root directory:
610631

611632
``` bash
612633
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
@@ -646,7 +667,8 @@ The following fixtures, defined in `tests/conftest.py`, are available in the tes
646667
- `set_up_database`: Sets up the test database before running the test suite by dropping all tables and recreating them to ensure a clean state.
647668
- `session`: Provides a session for database operations in tests.
648669
- `clean_db`: Cleans up the database tables before each test by deleting all entries in the `PasswordResetToken` and `User` tables.
649-
- `client`: Provides a `TestClient` instance with the session fixture, overriding the `get_session` dependency to use the test session.
670+
- `auth_client`: Provides a `TestClient` instance with access and refresh token cookies set, overriding the `get_session` dependency to use the `session` fixture.
671+
- `unauth_client`: Provides a `TestClient` instance without authentication cookies set, overriding the `get_session` dependency to use the `session` fixture.
650672
- `test_user`: Creates a test user in the database with a predefined name, email, and hashed password.
651673

652674
To run the tests, use these commands:
@@ -661,10 +683,10 @@ To run the tests, use these commands:
661683
The project uses type annotations and mypy for static type checking. To run mypy, use this command from the root directory:
662684

663685
```bash
664-
mypy
686+
mypy .
665687
```
666688

667-
We find that mypy is an enormous time-saver, catching many errors early and greatly reducing time spent debugging unit tests. However, note that mypy requires you type annotate every variable, function, and method in your code base, so taking advantage of it is a lifestyle change!
689+
We find that mypy is an enormous time-saver, catching many errors early and greatly reducing time spent debugging unit tests. However, note that mypy requires you type annotate every variable, function, and method in your code base, so taking advantage of it requires a lifestyle change!
668690

669691
### Developing with LLMs
670692

@@ -705,15 +727,19 @@ We also create POST endpoints, which accept form submissions so the user can cre
705727

706728
#### Routing patterns in this template
707729

708-
In this template, GET routes are defined in the main entry point for the application, `main.py`. POST routes are organized into separate modules within the `routers/` directory. We name our GET routes using the convention `read_<name>`, where `<name>` is the name of the page, to indicate that they are read-only endpoints that do not modify the database.
730+
In this template, GET routes are defined in the main entry point for the application, `main.py`. POST routes are organized into separate modules within the `routers/` directory.
731+
732+
We name our GET routes using the convention `read_<name>`, where `<name>` is the name of the page, to indicate that they are read-only endpoints that do not modify the database.
709733

710734
We divide our GET routes into authenticated and unauthenticated routes, using commented section headers in our code that look like this:
711735

712736
```python
713737
# -- Authenticated Routes --
714738
```
715739

716-
Some of our routes take request parameters, which we pass as keyword arguments to the route handler. These parameters should be type annotated for validation purposes. Some parameters are shared across all authenticated or unauthenticated routes, so we define them in the `common_authenticated_parameters` and `common_unauthenticated_parameters` dependencies defined in `main.py`.
740+
Some of our routes take request parameters, which we pass as keyword arguments to the route handler. These parameters should be type annotated for validation purposes.
741+
742+
Some parameters are shared across all authenticated or unauthenticated routes, so we define them in the `common_authenticated_parameters` and `common_unauthenticated_parameters` dependencies defined in `main.py`.
717743

718744
### HTML templating with Jinja2
719745

@@ -734,7 +760,7 @@ async def welcome(request: Request):
734760
)
735761
```
736762

737-
In this example, the `welcome.html` template will receive two pieces of context: the user's `request`, which is always passed automatically by FastAPI, and a `username` variable, which we specify as "Alice". We can then use the `{{ username }}` syntax in the `welcome.html` template (or any of its parent or child templates) to insert the value into the HTML.
763+
In this example, the `welcome.html` template will receive two pieces of context: the user's `request`, which is always passed automatically by FastAPI, and a `username` variable, which we specify as "Alice". We can then use the `{{{ username }}}` syntax in the `welcome.html` template (or any of its parent or child templates) to insert the value into the HTML.
738764

739765
#### Form validation strategy
740766

@@ -890,9 +916,9 @@ graph.write_png('static/schema.png')
890916
![Database Schema](static/schema.png)
891917

892918

893-
#### Database operations
919+
#### Database helpers
894920

895-
Database operations are handled by helper functions in `utils/db.py`. Key functions include:
921+
Database operations are facilitated by helper functions in `utils/db.py`. Key functions include:
896922

897923
- `set_up_db()`: Initializes the database schema and default data (which we do on every application start in `main.py`)
898924
- `get_connection_url()`: Creates a database connection URL from environment variables in `.env`
@@ -909,6 +935,33 @@ async def get_users(session: Session = Depends(get_session)):
909935

910936
The session automatically handles transaction management, ensuring that database operations are atomic and consistent.
911937

938+
#### Cascade deletes
939+
940+
Cascade deletes (in which deleting a record from one table deletes related records from another table) can be handled at either the ORM level or the database level. This template handles cascade deletes at the ORM level, via SQLModel relationships. Inside a SQLModel `Relationship`, we set:
941+
942+
```python
943+
sa_relationship_kwargs={
944+
"cascade": "all, delete-orphan"
945+
}
946+
```
947+
948+
This tells SQLAlchemy to cascade all operations (e.g., `SELECT`, `INSERT`, `UPDATE`, `DELETE`) to the related table. Since this happens through the ORM, we need to be careful to do all our database operations through the ORM using supported syntax. That generally means loading database records into Python objects and then deleting those objects rather than deleting records in the database directly.
949+
950+
For example,
951+
952+
```python
953+
session.exec(delete(Role))
954+
```
955+
956+
will not trigger the cascade delete. Instead, we need to select the role objects and then delete them:
957+
958+
```python
959+
for role in session.exec(select(Role)).all():
960+
session.delete(role)
961+
```
962+
963+
This is slower than deleting the records directly, but it makes [many-to-many relationships](https://sqlmodel.tiangolo.com/tutorial/many-to-many/create-models-with-link/#create-the-tables) much easier to manage.
964+
912965

913966
# Deployment
914967

docs/static/schema.png

-16.3 KB
Loading

0 commit comments

Comments
 (0)