Skip to content

Commit 21e6d35

Browse files
Merge pull request #125 from Promptly-Technologies-LLC/124-commit-some-cursor-rules-to-enhance-development-workflow
Commit cursor rules to enhance development workflows
2 parents 0d93868 + 44d973b commit 21e6d35

File tree

6 files changed

+99
-2
lines changed

6 files changed

+99
-2
lines changed

.cursor/rules/general.mdc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
description: General guidelines
3+
globs:
4+
alwaysApply: true
5+
---
6+
This project uses `uv` for dependency management. To add or remove a dependency, use `uv add <packagename>` or `uv remove <packagename>`. To update a dependency to the latest version, use `uv lock --upgrade-package <packagename>` For development dependencies, add the `--group dev` flag to these commands. Dependencies can be installed with `uv sync`.
7+
8+
When building out features, always keep changes atomic and make sure to write and run tests. To run tests, use:
9+
10+
```bash
11+
uv run pytest tests # or the path to a specific test file
12+
```
13+
14+
All code should be rigorously type hinted so as to pass a static type check with `mypy`. To run a `mypy` check, use:
15+
16+
```bash
17+
uv run mypy .
18+
```

.cursor/rules/routers.mdc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
description: Testing FastAPI routes
3+
globs: routers/*.py
4+
alwaysApply: false
5+
---
6+
Here are the five most critical patterns to maintain consistency when adding a new router:
7+
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
10+
- Similarly, use the `get_optional_user` dependency for public routes with potential auth status
11+
12+
2. **Validation Patterns**
13+
- Validate requests with type hints in the route signature
14+
- Use `Annotated[str, Form()]` for complex request validation cases involving form data
15+
- Perform business logic validation checks in the route body, raising a custom HTTPException defined in `exceptions/http_exceptions.py`
16+
- Note that all exceptions will be handled by middleware in `main.py` that renders an error template
17+
18+
3. **Permission System**
19+
- Use `user.has_permission(ValidPermissions.X, resource)` for authorization
20+
- Validate organization membership through role relationships
21+
- Check permissions at both route and template levels via `user_permissions`
22+
23+
4. **Database & Transaction Patterns**
24+
- Inject session via `Depends(get_session)`
25+
- Commit after writes and refresh objects where needed
26+
- Use `selectinload` for eager loading relationships
27+
- Follow PRG pattern with RedirectResponse after mutations
28+
29+
5. **Templating**
30+
- Use Jinja templates from the `/templates` directory in GET routes, and always pass `request` and `user` objects as as context

.cursor/rules/routers_tests.mdc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
description:
3+
globs: tests/routers/test_*.py
4+
alwaysApply: false
5+
---
6+
# Setting test expectations regarding HTTP status codes
7+
8+
Since this is a FastAPI web application, test logic for API endpoints often involves checking status codes. Remember, when making a request to an API endpoint, you should specify the `follow_redirects` parameter. With `follow_redirects=False`, the response code will often be `303`; otherwise it will be the response code of the route we've redirected to. We mostly use `follow_redirects=False` so as to test routes in isolation, but there may be test cases where following the redirect is more appropriate.
9+
10+
When checking status codes, think carefully to make sure the expected status code is the most appropriate to the situation.

.cursor/rules/sqlmodel.mdc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
description: Satisfying the type checker when working with SQLModel
3+
globs:
4+
alwaysApply: false
5+
---
6+
Complex SQLModel queries sometimes cause the type checker to choke, even though the queries are valid.
7+
8+
For instance, this error sometimes arises when using `selectinload`:
9+
10+
'error: Argument 1 to "selectinload" has incompatible type "SomeModel"; expected "Literal['*'] | QueryableAttribute[Any]"'
11+
12+
The solution is to explicitly coerce the argument to the appropriate SQLModel type.
13+
14+
E.g., we can resolve the error above by casting the eager-loaded relationship to InstrumentedAttribute:
15+
16+
```python
17+
session.exec(select(SomeOtherModel).options(selectinload(cast(InstrumentedAttribute, SomeOtherModel.some_model))))
18+
```
19+
20+
Similarly, sometimes we get type checker errors when using `delete` or comparison operators like `in_`:
21+
22+
'error: Item "int" of "Optional[int]" has no attribute "in_"'
23+
24+
These can be resolved by wrapping the column in `col` to let the type checker know these are column objects:
25+
26+
```python
27+
session.exec(select(SomeModel).where(col(SomeModel.id).in_([1,2])))
28+
```

.cursor/rules/tests.mdc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
description: Building, running, and debugging tests
3+
globs: tests/*.py
4+
alwaysApply: false
5+
---
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.
7+
8+
The project uses test-driven development, so failing tests are often what we want. The goal is always to ensure that the code is high-quality and fulfills project goals in a production-like environment, *not* that the tests pass at any cost. Rigorous tests are always better than passing tests, and you will be rewarded for test quality!
9+
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+
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.

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ node_modules
1515
package-lock.json
1616
package.json
1717
.specstory
18-
.cursorrules
19-
.cursor
2018
repomix-output.txt
2119
artifacts/
20+
.cursorindexingignore

0 commit comments

Comments
 (0)