Skip to content

Commit

Permalink
upgrade backend and frontend to latest
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-cognicode committed Jan 15, 2025
1 parent ba1706b commit f23cc0c
Show file tree
Hide file tree
Showing 128 changed files with 9,982 additions and 7,308 deletions.
9 changes: 9 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,18 @@ POSTGRES_PORT=5432
POSTGRES_DB=app
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changethis
# pytest and playwright
POSTGRES_TEST_DB=app_test

SENTRY_DSN=

# Configure these with your own Docker registry images
DOCKER_IMAGE_BACKEND=backend
DOCKER_IMAGE_FRONTEND=frontend

# CICD
CI=

# Frontend tests
VITE_API_URL=http://localhost:8000
MAILCATCHER_HOST=http://localhost:1080
1 change: 0 additions & 1 deletion .github/workflows/test-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ on:
- synchronize

jobs:

test-docker-compose:
runs-on: ubuntu-latest
steps:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.vscode
.vscode/settings.json
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.18.1
9 changes: 9 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"recommendations": [
"ms-azuretools.vscode-docker",
"ms-python.python",
"charliermarsh.ruff",
"biomejs.biome",
"ms-playwright.playwright"
]
}
24 changes: 24 additions & 0 deletions .vscode/settings.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"biome.lspBin": "./frontend/node_modules/.bin/biome",
"python.defaultInterpreterPath": "${workspaceFolder}/backend/.venv/bin/python",
"python.envFile": "${workspaceFolder}/.env",
"python.testing.cwd": "${workspaceFolder}/backend",
"python.testing.pytestArgs": ["-sv", "${workspaceFolder}/backend/app/tests"],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.analysis.extraPaths": ["${workspaceFolder}/backend"],
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
},
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"[markdown][yaml]": {
"editor.formatOnSave": false
},
"[json][javascript][javascriptreact][typescript][typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
## Technology Stack and Features

-[**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
- 🚀 [React](https://react.dev) for the frontend.
- 💃 Using TypeScript, hooks, Vite, and other parts of a modern frontend stack.
- 🎨 [Chakra UI](https://chakra-ui.com) for the frontend components.
- 🤖 An automatically generated frontend client.
- 🧪 [Playwright](https://playwright.dev) for End-to-End testing.
- 🦇 Dark mode support.
- 💃 Using TypeScript, hooks, Vite, and other parts of a modern frontend stack.
- 🎨 [Chakra UI](https://chakra-ui.com) for the frontend components.
- 🤖 An automatically generated frontend client.
- 🧪 [Playwright](https://playwright.dev) for End-to-End testing.
- 🦇 Dark mode support.
- 🐋 [Docker Compose](https://www.docker.com) for development and production.
- 🔒 Secure password hashing by default.
- 🔑 JWT (JSON Web Token) authentication.
Expand Down
28 changes: 17 additions & 11 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ By default, the dependencies are managed with [uv](https://docs.astral.sh/uv/),
From `./backend/` you can install all the dependencies with:

```console
$ uv sync
uv sync
```

Then you can activate the virtual environment with:

```console
$ source .venv/bin/activate
source .venv/bin/activate
```

Make sure your editor is using the correct Python virtual environment, with the interpreter at `backend/.venv/bin/python`.
Expand All @@ -35,6 +35,12 @@ There are already configurations in place to run the backend through the VS Code

The setup is also already configured so you can run the tests through the VS Code Python tests tab.

Copy the `.vscode/settings.example.json` for convenience:

```console
cp .vscode/settings.example.json .vscode/settings.json
```

## Docker Compose Override

During development, you can change Docker Compose settings that will only affect the local development environment in the file `docker-compose.override.yml`.
Expand All @@ -46,21 +52,21 @@ For example, the directory with the backend code is synchronized in the Docker c
There is also a command override that runs `fastapi run --reload` instead of the default `fastapi run`. It starts a single server process (instead of multiple, as would be for production) and reloads the process whenever the code changes. Have in mind that if you have a syntax error and save the Python file, it will break and exit, and the container will stop. After that, you can restart the container by fixing the error and running again:

```console
$ docker compose watch
docker compose watch
```

There is also a commented out `command` override, you can uncomment it and comment the default one. It makes the backend container run a process that does "nothing", but keeps the container alive. That allows you to get inside your running container and execute commands inside, for example a Python interpreter to test installed dependencies, or start the development server that reloads when it detects changes.

To get inside the container with a `bash` session you can start the stack with:

```console
$ docker compose watch
docker compose watch
```

and then in another terminal, `exec` inside the running container:

```console
$ docker compose exec backend bash
docker compose exec backend bash
```

You should see an output like:
Expand All @@ -74,7 +80,7 @@ that means that you are in a `bash` session inside your container, as a `root` u
There you can use the `fastapi run --reload` command to run the debug live reloading server.

```console
$ fastapi run --reload app/main.py
fastapi run --reload app/main.py
```

...it will look like:
Expand All @@ -94,7 +100,7 @@ Nevertheless, if it doesn't detect a change but a syntax error, it will just sto
To test the backend run:

```console
$ bash ./scripts/test.sh
bash ./scripts/test.sh
```

The tests run with Pytest, modify and add tests to `./backend/app/tests/`.
Expand Down Expand Up @@ -130,23 +136,23 @@ Make sure you create a "revision" of your models and that you "upgrade" your dat
* Start an interactive session in the backend container:

```console
$ docker compose exec backend bash
docker compose exec backend bash
```

* Alembic is already configured to import your SQLModel models from `./backend/app/models.py`.

* After changing a model (for example, adding a column), inside the container, create a revision, e.g.:

```console
$ alembic revision --autogenerate -m "Add column last_name to User model"
alembic revision --autogenerate -m "Add column last_name to User model"
```

* Commit to the git repository the files generated in the alembic directory.

* After creating the revision, run the migration in the database (this is what will actually change the database):

```console
$ alembic upgrade head
alembic upgrade head
```

If you don't want to use migrations at all, uncomment the lines in the file at `./backend/app/core/db.py` that end in:
Expand All @@ -158,7 +164,7 @@ SQLModel.metadata.create_all(engine)
and comment the line in the file `scripts/prestart.sh` that contains:

```console
$ alembic upgrade head
alembic upgrade head
```

If you don't want to start with the default models and want to remove them / modify them, from the beginning, without having any previous revision, you can remove the revision files (`.py` Python files) under `./backend/app/alembic/versions/`. And then create a first migration as described above.
Expand Down
50 changes: 45 additions & 5 deletions backend/app/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Annotated

import jwt
from fastapi import Depends, HTTPException, status
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import OAuth2PasswordBearer
from jwt.exceptions import InvalidTokenError
from pydantic import ValidationError
Expand All @@ -12,18 +12,27 @@
from app.core.config import settings
from app.core.db import engine
from app.models import TokenPayload, User
from app.repositories.items import ItemRepository
from app.repositories.users import UserRepository
from app.services.items import ItemService
from app.services.users import UserService

reusable_oauth2 = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR}/login/access-token"
)


def get_db() -> Generator[Session, None, None]:
with Session(engine) as session:
yield session
def get_session(request: Request) -> Generator[Session, None, None]:
"""reuses the session if it already exists in the request/response cycle"""
request_db_session = getattr(request.state, "db_session", None)
if request_db_session and isinstance(request_db_session, Session):
yield request_db_session
else:
with Session(engine) as session:
yield session


SessionDep = Annotated[Session, Depends(get_db)]
SessionDep = Annotated[Session, Depends(get_session)]
TokenDep = Annotated[str, Depends(reusable_oauth2)]


Expand Down Expand Up @@ -55,3 +64,34 @@ def get_current_active_superuser(current_user: CurrentUser) -> User:
status_code=403, detail="The user doesn't have enough privileges"
)
return current_user


## Entities


def user_repository(session: SessionDep) -> UserRepository:
return UserRepository(session)


UserRepositoryDep = Annotated[UserRepository, Depends(user_repository)]


def user_service(user_repository: UserRepositoryDep) -> UserService:
return UserService(user_repository)


UserServiceDep = Annotated[UserService, Depends(user_service)]


def item_repository(session: SessionDep) -> ItemRepository:
return ItemRepository(session)


ItemRepositoryDep = Annotated[ItemRepository, Depends(item_repository)]


def item_service(item_repository: ItemRepositoryDep) -> ItemService:
return ItemService(item_repository)


ItemServiceDep = Annotated[ItemService, Depends(item_service)]
Loading

0 comments on commit f23cc0c

Please sign in to comment.