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: docs/customization.html
+26-14Lines changed: 26 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -256,8 +256,9 @@ <h3 class="anchored" data-anchor-id="type-checking-with-mypy">Type checking with
256
256
</section>
257
257
<sectionid="developing-with-llms" class="level3">
258
258
<h3class="anchored" data-anchor-id="developing-with-llms">Developing with LLMs</h3>
259
-
<p>In line with the <ahref="https://llmstxt.org/">llms.txt standard</a>, we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a <ahref="static/llms.txt">text file</a>. One use case for this file is to rename it to <code>.cursorrules</code> and place it in your project directory is using the Cursor IDE (see the <ahref="https://docs.cursor.com/context/rules-for-ai">Cursor docs</a> on this for more information).</p>
260
-
<p>We have also exposed the full Markdown-formatted project documentation as a <ahref="static/documentation.txt">single text file</a> for easy downloading and embedding.</p>
259
+
<p>In line with the <ahref="https://llmstxt.org/">llms.txt standard</a>, we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a text file: <ahref="static/llms.txt">llms.txt</a>.</p>
260
+
<p>One use case for this file, if using the Cursor IDE, is to rename it to <code>.cursorrules</code> and place it in your project directory (see the <ahref="https://docs.cursor.com/context/rules-for-ai">Cursor docs</a> 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.</p>
261
+
<p>We have also exposed the full Markdown-formatted project documentation as a <ahref="static/documentation.txt">single text file</a> for easy downloading and embedding for RAG workflows.</p>
<p>In this template, GET routes are defined in the main entry point for the application, <code>main.py</code>. POST routes are organized into separate modules within the <code>routers/</code> directory.</p>
304
305
<p>We name our GET routes using the convention <code>read_<name></code>, where <code><name></code> is the name of the page, to indicate that they are read-only endpoints that do not modify the database.</p>
305
306
<p>We divide our GET routes into authenticated and unauthenticated routes, using commented section headers in our code that look like this:</p>
<p>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.</p>
308
309
<p>Some parameters are shared across all authenticated or unauthenticated routes, so we define them in the <code>common_authenticated_parameters</code> and <code>common_unauthenticated_parameters</code> dependencies defined in <code>main.py</code>.</p>
309
310
</section>
@@ -416,11 +417,16 @@ <h4 class="anchored" data-anchor-id="models-and-relationships">Models and relati
416
417
<p>Our database models are defined in <code>utils/models.py</code>. Each model is a Python class that inherits from <code>SQLModel</code> and represents a database table. The key models are:</p>
417
418
<ul>
418
419
<li><code>Organization</code>: Represents a company or team</li>
419
-
<li><code>User</code>: Represents a user account</li>
420
-
<li><code>Role</code>: Represents a discrete set of user permissions within an organization</li>
421
-
<li><code>Permission</code>: Represents specific actions a user can perform</li>
422
-
<li><code>RolePermissionLink</code>: Maps roles to their allowed permissions</li>
<spanid="cb8-4"><ahref="#cb8-4" aria-hidden="true" tabindex="-1"></a><spanclass="cf">return</span> users</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
446
452
<p>The session automatically handles transaction management, ensuring that database operations are atomic and consistent.</p>
453
+
<p>There is also a helper method on the <code>User</code> model that checks if a user has a specific permission for a given organization. Its first argument must be a <code>ValidPermissions</code> enum value (from <code>utils/models.py</code>), and its second argument must be an <code>Organization</code> object or an <code>int</code> representing an organization ID:</p>
<spanid="cb9-4"><ahref="#cb9-4" aria-hidden="true" tabindex="-1"></a>user.has_permission(permission, organization)</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
458
+
<p>You should create custom <code>ValidPermissions</code> enum values for your application and validate that users have the necessary permissions before allowing them to modify organization data resources.</p>
<p>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 <code>Relationship</code>, we set:</p>
<spanid="cb10-3"><ahref="#cb10-3" aria-hidden="true" tabindex="-1"></a>}</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
454
466
<p>This tells SQLAlchemy to cascade all operations (e.g., <code>SELECT</code>, <code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code>) 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.</p>
455
467
<p>For example,</p>
456
-
<divclass="sourceCode" id="cb10"><preclass="sourceCode python code-with-copy"><codeclass="sourceCode python"><spanid="cb10-1"><ahref="#cb10-1" aria-hidden="true" tabindex="-1"></a>session.<spanclass="bu">exec</span>(delete(Role))</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
468
+
<divclass="sourceCode" id="cb11"><preclass="sourceCode python code-with-copy"><codeclass="sourceCode python"><spanid="cb11-1"><ahref="#cb11-1" aria-hidden="true" tabindex="-1"></a>session.<spanclass="bu">exec</span>(delete(Role))</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
457
469
<p>will not trigger the cascade delete. Instead, we need to select the role objects and then delete them:</p>
458
-
<divclass="sourceCode" id="cb11"><preclass="sourceCode python code-with-copy"><codeclass="sourceCode python"><spanid="cb11-1"><ahref="#cb11-1" aria-hidden="true" tabindex="-1"></a><spanclass="cf">for</span> role <spanclass="kw">in</span> session.<spanclass="bu">exec</span>(select(Role)).<spanclass="bu">all</span>():</span>
459
-
<spanid="cb11-2"><ahref="#cb11-2" aria-hidden="true" tabindex="-1"></a> session.delete(role)</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
470
+
<divclass="sourceCode" id="cb12"><preclass="sourceCode python code-with-copy"><codeclass="sourceCode python"><spanid="cb12-1"><ahref="#cb12-1" aria-hidden="true" tabindex="-1"></a><spanclass="cf">for</span> role <spanclass="kw">in</span> session.<spanclass="bu">exec</span>(select(Role)).<spanclass="bu">all</span>():</span>
471
+
<spanid="cb12-2"><ahref="#cb12-2" aria-hidden="true" tabindex="-1"></a> session.delete(role)</span></code><buttontitle="Copy to Clipboard" class="code-copy-button"><iclass="bi"></i></button></pre></div>
460
472
<p>This is slower than deleting the records directly, but it makes <ahref="https://sqlmodel.tiangolo.com/tutorial/many-to-many/create-models-with-link/#create-the-tables">many-to-many relationships</a> much easier to manage.</p>
Copy file name to clipboardExpand all lines: docs/static/documentation.txt
+30-10Lines changed: 30 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -192,9 +192,11 @@ with open(output_path, 'w', encoding='utf-8') as f:
192
192
f.write(final_content)
193
193
```
194
194
195
-
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](docs/static/llms.txt). One use case for this file is to rename it to `.cursorrules` and place it in your project directory is using the Cursor IDE (see the [Cursor docs](https://docs.cursor.com/context/rules-for-ai) on this for more information).
195
+
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).
196
196
197
-
We have also exposed the full Markdown-formatted project documentation as a [single text file](docs/static/documentation.txt) for easy downloading and embedding.
197
+
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.
198
+
199
+
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.
198
200
199
201
## Contributing
200
202
@@ -692,9 +694,11 @@ We find that mypy is an enormous time-saver, catching many errors early and grea
692
694
693
695
### Developing with LLMs
694
696
695
-
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](static/llms.txt). One use case for this file is to rename it to `.cursorrules` and place it in your project directory is using the Cursor IDE (see the [Cursor docs](https://docs.cursor.com/context/rules-for-ai) on this for more information).
697
+
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).
698
+
699
+
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.
696
700
697
-
We have also exposed the full Markdown-formatted project documentation as a [single text file](static/documentation.txt) for easy downloading and embedding.
701
+
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.
698
702
699
703
## Project structure
700
704
@@ -738,7 +742,7 @@ We name our GET routes using the convention `read_<name>`, where `<name>` is the
738
742
We divide our GET routes into authenticated and unauthenticated routes, using commented section headers in our code that look like this:
739
743
740
744
```python
741
-
# -- Authenticated Routes --
745
+
# --- Authenticated Routes ---
742
746
```
743
747
744
748
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.
@@ -885,11 +889,16 @@ SQLModel is an Object-Relational Mapping (ORM) library that allows us to interac
885
889
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:
886
890
887
891
- `Organization`: Represents a company or team
888
-
- `User`: Represents a user account
889
-
- `Role`: Represents a discrete set of user permissions within an organization
890
-
- `Permission`: Represents specific actions a user can perform
891
-
- `RolePermissionLink`: Maps roles to their allowed permissions
The session automatically handles transaction management, ensuring that database operations are atomic and consistent.
941
950
951
+
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:
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.
961
+
942
962
#### Cascade deletes
943
963
944
964
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:
Copy file name to clipboardExpand all lines: index.html
+3-2Lines changed: 3 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -327,8 +327,9 @@ <h3 class="anchored" data-anchor-id="lint-types-with-mypy">Lint types with mypy<
327
327
</section>
328
328
<sectionid="developing-with-llms" class="level2">
329
329
<h2class="anchored" data-anchor-id="developing-with-llms">Developing with LLMs</h2>
330
-
<p>In line with the <ahref="https://llmstxt.org/">llms.txt standard</a>, we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a <ahref="docs/static/llms.txt">text file</a>. One use case for this file is to rename it to <code>.cursorrules</code> and place it in your project directory is using the Cursor IDE (see the <ahref="https://docs.cursor.com/context/rules-for-ai">Cursor docs</a> on this for more information).</p>
331
-
<p>We have also exposed the full Markdown-formatted project documentation as a <ahref="docs/static/documentation.txt">single text file</a> for easy downloading and embedding.</p>
330
+
<p>In line with the <ahref="https://llmstxt.org/">llms.txt standard</a>, we have provided a Markdown-formatted prompt—designed to help LLM agents understand how to work with this template—as a text file: <ahref="docs/static/llms.txt">llms.txt</a>.</p>
331
+
<p>One use case for this file, if using the Cursor IDE, is to rename it to <code>.cursorrules</code> and place it in your project directory (see the <ahref="https://docs.cursor.com/context/rules-for-ai">Cursor docs</a> 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.</p>
332
+
<p>We have also exposed the full Markdown-formatted project documentation as a <ahref="docs/static/documentation.txt">single text file</a> for easy downloading and embedding for RAG workflows.</p>
0 commit comments