Skip to content

Commit c90f4bf

Browse files
committed
add dotenv loader
1 parent 220c12a commit c90f4bf

File tree

7 files changed

+81
-25
lines changed

7 files changed

+81
-25
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ If you simply want to test the application without modifying code, use the produ
1414
```
1515

1616
2. **Access the App**
17-
* **App URL:** `http://localhost:80`
17+
* **App URL:** [`http://localhost:80`](http://localhost:80)
1818
* **User:** `test` / `test`
1919

2020
---
@@ -28,9 +28,9 @@ This section covers setting up the local environment for coding. You need **Post
2828
The application relies on the following services. Ensure your environment variables are set (or use the provided `.env.example`):
2929

3030
```bash
31-
export DATABASE_URL="postgresql+asyncpg://postgres:password@localhost:5432/postgres"
32-
export REDIS_URL="redis://localhost:6379"
33-
export ENV=development
31+
DATABASE_URL="postgresql+asyncpg://postgres:password@localhost:5432/postgres"
32+
REDIS_URL="redis://localhost:6379"
33+
ENV=development
3434
```
3535

3636
### Option A: Manual Setup (Docker Compose)
@@ -82,14 +82,14 @@ Once the development environment is running:
8282

8383
| Service | URL | Description |
8484
| :--- | :--- | :--- |
85-
| **Web Frontend** | `http://localhost:3000` | The user interface (Next.js/React). |
86-
| **Backend API** | `http://localhost:8000/graphql` | The GraphQL Playground (Strawberry). |
87-
| **Keycloak** | `http://localhost:8080` | Identity Provider. |
85+
| **Web Frontend** | [`http://localhost:3000`](http://localhost:3000) | The user interface (Next.js/React). |
86+
| **Backend API** | [`http://localhost:8000/graphql`](http://localhost:8000/graphql) | The GraphQL Playground (Strawberry). |
87+
| **Keycloak** | [`http://localhost:8080`](http://localhost:8080) | Identity Provider. |
8888

8989
**Keycloak Realms & Users:**
90-
* **User Realm:** `http://localhost:8080/realms/tasks` (Redirects automatically from app login)
90+
* **tasks Realm:** `http://localhost:8080/realms/tasks` (Redirects automatically from app login)
9191
* User: `test`
9292
* Password: `test`
93-
* **Admin Console:** `http://localhost:8080/admin`
93+
* **master Realm (Admin Console):** [`http://localhost:8080/admin`](http://localhost:8080/admin)
9494
* User: `admin`
9595
* Password: `admin`

backend/.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Dockerfile
2+
.env*

backend/.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
DATABASE_HOSTNAME="postgres"
2+
DATABASE_NAME="postgres"
3+
DATABASE_USERNAME="postgres"
4+
DATABASE_PASSWORD="password"
5+
6+
REDIS_HOSTNAME="redis"
7+
REDIS_PASSWORD="password"
8+
9+
ISSUER_URI="http://keycloak:8080/realms/tasks"
10+
PUBLIC_ISSUER_URI="http://localhost:8080/realms/tasks"
11+
CLIENT_ID="tasks"
12+
CLIENT_SECRET="tasks-secret"
13+
14+
ENV="development"

backend/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import os
22

3+
from dotenv import load_dotenv
4+
5+
load_dotenv()
6+
37
_db_hostname = os.getenv("DATABASE_HOSTNAME", "postgres")
48
_db_name = os.getenv("DATABASE_NAME", "postgres")
59
_db_username = os.getenv("DATABASE_USERNAME", "postgres")

backend/main.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import logging
22

33
import requests
4-
from starlette.status import HTTP_400_BAD_REQUEST
54
from api.context import Context
65
from api.resolvers import Mutation, Query, Subscription
7-
from auth import UnauthenticatedRedirect, authenticate_connection, get_token_source, unauthenticated_redirect_handler, verify_token
6+
from auth import (
7+
UnauthenticatedRedirect,
8+
authenticate_connection,
9+
get_token_source,
10+
unauthenticated_redirect_handler,
11+
)
812
from config import (
913
CLIENT_ID,
1014
CLIENT_SECRET,
@@ -18,6 +22,7 @@
1822
from fastapi.responses import RedirectResponse
1923
from sqlalchemy import select
2024
from starlette.requests import HTTPConnection
25+
from starlette.status import HTTP_400_BAD_REQUEST
2126
from strawberry import Schema
2227
from strawberry.fastapi import GraphQLRouter
2328

@@ -32,15 +37,17 @@ async def get_context(
3237
user_payload = await authenticate_connection(connection, token)
3338

3439
user_id = user_payload.get("sub")
35-
username = (
36-
user_payload.get("preferred_username")
37-
or user_payload.get("name")
40+
username = user_payload.get("preferred_username") or user_payload.get(
41+
"name",
3842
)
3943
firstname = user_payload.get("given_name")
4044
lastname = user_payload.get("family_name")
4145

4246
if not (user_id and username and firstname and lastname):
43-
raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Missing required user details.")
47+
raise HTTPException(
48+
status_code=HTTP_400_BAD_REQUEST,
49+
detail="Missing required user details.",
50+
)
4451

4552
result = await session.execute(select(User).where(User.id == user_id))
4653
db_user = result.scalars().first()
@@ -73,7 +80,7 @@ async def get_context(
7380
graphql_app = GraphQLRouter(
7481
schema,
7582
context_getter=get_context,
76-
graphiql=IS_DEV,
83+
graphql_ide=IS_DEV,
7784
)
7885

7986

backend/requirements.txt

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,18 @@ anyio==4.12.0
1616
# watchfiles
1717
asyncpg==0.31.0
1818
# via -r requirements.in
19+
certifi==2025.11.12
20+
# via requests
21+
cffi==2.0.0
22+
# via cryptography
23+
charset-normalizer==3.4.4
24+
# via requests
1925
click==8.3.1
2026
# via uvicorn
27+
cryptography==46.0.3
28+
# via python-jose
29+
ecdsa==0.19.1
30+
# via python-jose
2131
fastapi==0.123.0
2232
# via
2333
# -r requirements.in
@@ -31,7 +41,9 @@ h11==0.16.0
3141
httptools==0.7.1
3242
# via uvicorn
3343
idna==3.11
34-
# via anyio
44+
# via
45+
# anyio
46+
# requests
3547
lia-web==0.2.3
3648
# via strawberry-graphql
3749
mako==1.3.10
@@ -40,26 +52,38 @@ markupsafe==3.0.3
4052
# via mako
4153
packaging==25.0
4254
# via strawberry-graphql
43-
psycopg[binary]==3.2.13
44-
# via -r requirements.in
45-
psycopg-binary==3.2.13
46-
# via psycopg
55+
pyasn1==0.6.1
56+
# via
57+
# python-jose
58+
# rsa
59+
pycparser==2.23
60+
# via cffi
4761
pydantic==2.12.5
4862
# via fastapi
4963
pydantic-core==2.41.5
5064
# via pydantic
5165
python-dateutil==2.9.0.post0
5266
# via strawberry-graphql
5367
python-dotenv==1.2.1
54-
# via uvicorn
68+
# via
69+
# -r requirements.in
70+
# uvicorn
71+
python-jose[cryptography]==3.5.0
72+
# via -r requirements.in
5573
python-multipart==0.0.20
5674
# via strawberry-graphql
5775
pyyaml==6.0.3
5876
# via uvicorn
5977
redis==7.1.0
6078
# via -r requirements.in
79+
requests==2.32.5
80+
# via -r requirements.in
81+
rsa==4.9.1
82+
# via python-jose
6183
six==1.17.0
62-
# via python-dateutil
84+
# via
85+
# ecdsa
86+
# python-dateutil
6387
sqlalchemy==2.0.44
6488
# via
6589
# -r requirements.in
@@ -80,6 +104,8 @@ typing-extensions==4.15.0
80104
# typing-inspection
81105
typing-inspection==0.4.2
82106
# via pydantic
107+
urllib3==2.5.0
108+
# via requests
83109
uvicorn[standard]==0.38.0
84110
# via -r requirements.in
85111
uvloop==0.22.1
@@ -88,5 +114,3 @@ watchfiles==1.1.1
88114
# via uvicorn
89115
websockets==15.0.1
90116
# via uvicorn
91-
python-jose[cryptography]
92-
requests

keycloak/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Disclaimer
2+
3+
`tasks.json` is a realm file.
4+
You can import it into your *development* keycloak.
5+
This configuration has preset credentials in it. Make sure to *not use it in production*.

0 commit comments

Comments
 (0)