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
<p>If you are using VSCode or Cursor as your IDE, you will need to select the <code>uv</code>-managed Python version as your interpreter for the project. Go to <code>View > Command Palette</code>, search for <code>Python: Select Interpreter</code>, and select the Python version labeled <code>('.venv':venv)</code>.</p>
253
254
<p>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 <code>.venv/bin/python</code> subfolder in your project directory.</p>
<h3class="anchored" data-anchor-id="extending-the-template">Extending the template</h3>
258
+
<p>The <code>routers/core/</code> and <code>utils/core/</code> directories contain the core backend logic for the template.</p>
259
+
<p>Your custom Python backend code should go primarily in the <code>routers/app/</code> and <code>utils/app/</code> directories.</p>
260
+
<p>For the frontend, you will also need to develop custom Jinja2 templates in the <code>templates/</code> folder and add custom static assets in <code>static/</code>.</p>
<p>The project uses Pytest for unit testing. It’s highly recommended to write and run tests before committing code to ensure nothing is broken!</p>
@@ -283,9 +290,7 @@ <h3 class="anchored" data-anchor-id="type-checking-with-mypy">Type checking with
283
290
</section>
284
291
<sectionid="developing-with-llms" class="level3">
285
292
<h3class="anchored" data-anchor-id="developing-with-llms">Developing with LLMs</h3>
286
-
<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>
287
-
<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>
288
-
<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>
293
+
<p>The <code>.cursor/rules</code> folder contains a set of AI rules for working on this codebase in the Cursor IDE. We have also provided an <ahref="static/llms.txt">llms.txt</a> system prompt file for use with other agentic LLM workflows and 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.</p>
<p>In this template, we use FastAPI to define the “API endpoints” of our application. An API endpoint is simply a URL that accepts user requests and returns responses. When a user visits a page, their browser sends what’s called a “GET” request to an endpoint, and the server processes it (often querying a database), and returns a response (typically HTML). The browser renders the HTML, displaying the page.</p>
296
301
<p>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 <ahref="https://promptlytechnologies.com/fastapi-jinja2-postgres-webapp/docs/architecture.html">Architecture</a> for more details.)</p>
<p>The GET route for the homepage is defined in the main entry point for the application, <code>main.py</code>. The entrypoint imports router modules from the <code>routers/</code> 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., <code>account.py</code> for account management.</p>
354
+
<p>The GET route for the homepage is defined in the main entry point for the application, <code>main.py</code>. The entrypoint imports router modules from the <code>routers/core/</code> directory (for core/template logic) and <code>routers/app/</code> directory (for app-specific logic). In CRUD style, the core router modules are named after the resource they manage, e.g., <code>account.py</code> for account management. You should place your own endpoints in <code>routers/app/</code>.</p>
347
355
<p>We name our GET routes using the convention <code>read_<name></code>, where <code><name></code> 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 <code>get_session</code> dependency as an argument to get a database session.</p>
348
356
<p>Routes that require authentication generally take the <code>get_authenticated_account</code> dependency as an argument. Unauthenticated GET routes generally take the <code>get_optional_user</code> dependency as an argument. If a route should <em>only</em> be seen by authenticated users (i.e., a login page), you can redirect to the dashboard if <code>get_optional_user</code> returns a <code>User</code> object.</p>
<p>SQLModel is an Object-Relational Mapping (ORM) library that allows us to interact with our PostgreSQL database using Python classes instead of writing raw SQL. It combines the features of SQLAlchemy (a powerful database toolkit) with Pydantic’s data validation.</p>
<h3class="anchored" data-anchor-id="models-and-relationships">Models and relationships</h3>
403
-
<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>
411
+
<p>Core database models are defined in <code>utils/core/models.py</code>. Each model is a Python class that inherits from <code>SQLModel</code> and represents a database table. The key core models are:</p>
404
412
<ul>
405
413
<li><code>Account</code>: Represents a user account with email and password hash</li>
406
414
<li><code>User</code>: Represents a user profile with details like name and avatar; the email and password hash are stored in the related <code>Account</code> model</li>
@@ -415,34 +423,35 @@ <h3 class="anchored" data-anchor-id="models-and-relationships">Models and relati
415
423
<li><code>UserRoleLink</code>: Maps users to their roles (many-to-many relationship)</li>
416
424
<li><code>RolePermissionLink</code>: Maps roles to their permissions (many-to-many relationship)</li>
417
425
</ul>
418
-
<p>Here’s an entity-relationship diagram (ERD) of the current database schema, automatically generated from our SQLModel definitions:</p>
426
+
<p>Here’s an entity-relationship diagram (ERD) of the current core database schema, automatically generated from our SQLModel definitions:</p>
<p>To extend the database schema, define your own models in <code>utils/app/models.py</code> and import them in <code>utils/core/db.py</code> to make sure they are included in the <code>metadata</code> object in the <code>create_all</code> function.</p>
<p>Database operations are facilitated by helper functions in <code>utils/db.py</code>. Key functions include:</p>
437
+
<p>Database operations are facilitated by helper functions in <code>utils/core/db.py</code> (for core logic) and <code>utils/app/</code> (for app-specific helpers). Key functions in the core utils include:</p>
429
438
<ul>
430
439
<li><code>set_up_db()</code>: Initializes the database schema and default data (which we do on every application start in <code>main.py</code>)</li>
431
440
<li><code>get_connection_url()</code>: Creates a database connection URL from environment variables in <code>.env</code></li>
432
441
<li><code>get_session()</code>: Provides a database session for performing operations</li>
433
442
</ul>
434
-
<p>To perform database operations in route handlers, inject the database session as a dependency:</p>
443
+
<p>To perform database operations in route handlers, inject the database session as a dependency (from <code>utils/core/db.py</code>):</p>
<spanid="cb4-4"><ahref="#cb4-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>
439
448
<p>The session automatically handles transaction management, ensuring that database operations are atomic and consistent.</p>
440
-
<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>
449
+
<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/core/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="cb5-4"><ahref="#cb5-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>
445
-
<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>
454
+
<p>You should create custom <code>AppPermissions</code> enum values for your application in <code>utils/app/</code> (if needed) and validate that users have the necessary permissions before allowing them to modify organization data resources.</p>
0 commit comments