Skip to content

Commit aa46d06

Browse files
committed
✨(pcdbapi) introduce a REST API acting as MongoDB proxy to avoid direct connections
1 parent a45e02a commit aa46d06

23 files changed

+1149
-312
lines changed

.env.development

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ NEXT_PUBLIC_MATOMO_URL=""
66
NEXT_PUBLIC_MATOMO_SITE_ID=""
77
NEXT_PUBLIC_APP_REPOSITORY_URL="https://github.com/numerique-gouv/espace-partenaire"
88
NEXT_PUBLIC_BASE_PATH=""
9+
PCDB_API_URL="http://localhost:8000"
10+
PCDB_API_SECRET="pcdb-api-secret-key"
11+
MONGODB_CONNECTION_STRING=mongodb://fc:pass@localhost:27017/core-fca-low?authSource=admin&replicaSet=rs0&directConnection=true

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,10 @@ prisma/generated_clients/
6969

7070
# MongoDB keyfile
7171
docker/mongodb/mongodb-keyfile
72+
73+
# Python
74+
__pycache__/
75+
.pytest_cache/
76+
*.pyc
77+
.ruff_cache/
78+
.coverage

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
npm test
1+
npm run lint && npm test

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ npm run test
3434
# lancer les tests end-to-end
3535
npm run e2e --ui
3636
```
37+
38+
### Documentation
39+
40+
La documentation est disponible dans le dossier `docs`.
41+
42+
- [Architecture](docs/architecture.md)

docker-compose.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ services:
99
ports:
1010
- "5432:5432"
1111

12+
# This MongoDB will be seeded with mock data at each restart
1213
mongodb:
1314
image: mongo:5.0.23
1415
environment:
@@ -23,6 +24,39 @@ services:
2324
- /data/db
2425
- /data/configdb
2526

27+
pcdbapi:
28+
build: ./pcdbapi
29+
environment:
30+
- MONGODB_URL=mongodb://fc:pass@mongodb:27017/core-fca-low?authSource=admin&replicaSet=rs0&directConnection=true
31+
- API_SECRET=pcdb-api-secret-key
32+
- CANT_RUN_TESTS=1
33+
ports:
34+
- "8000:8000"
35+
volumes:
36+
- ./pcdbapi:/app
37+
depends_on:
38+
- mongodb
39+
healthcheck:
40+
test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
41+
interval: 10s
42+
timeout: 5s
43+
retries: 5
44+
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
45+
46+
pcdbapi-test:
47+
build:
48+
context: ./pcdbapi
49+
dockerfile: Dockerfile.test
50+
pull_policy: build
51+
profiles: ["test"]
52+
volumes:
53+
- ./pcdbapi:/app
54+
environment:
55+
- MONGODB_URL=mongodb://fc:pass@mongodb:27017/proconnect_test?authSource=admin&replicaSet=rs0
56+
- API_SECRET=pcdb-api-secret-key
57+
depends_on:
58+
- mongodb
59+
2660
mailcatcher:
2761
image: maildev/maildev:2.2.1
2862
ports:

docs/architecture.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Architecture Documentation
2+
3+
## Overview
4+
5+
The project consists of three main components:
6+
7+
1. Next.js Frontend - User interface and client-side logic
8+
2. Next.js API - Backend proxy and session management
9+
3. FastAPI Service (PCDBAPI) - MongoDB access and data validation
10+
11+
## Component Architecture
12+
13+
```
14+
├── src/ # Next.js Frontend & API
15+
│ ├── pages/
16+
│ │ ├── api/ # Next.js API Routes
17+
│ │ │ ├── apps/ # OIDC Client management
18+
│ │ │ └── auth/ # Authentication
19+
│ │ └── apps/ # Frontend pages
20+
│ ├── components/ # React components
21+
│ └── lib/ # Shared utilities
22+
23+
└── pcdbapi/ # FastAPI Service
24+
├── main.py # API endpoints
25+
└── middleware.py # Authentication
26+
```
27+
28+
## Next.js Frontend
29+
30+
### Core Features
31+
32+
- React-based UI with @codegouvfr/react-dsfr
33+
- Client-side state management
34+
- Form handling and validation
35+
- Compile-time Markdown rendering of files in `src/pages/docs`
36+
37+
### State Management
38+
39+
- Per-page React state
40+
- No global state store
41+
- Optimistic updates
42+
- Debounced saves
43+
44+
## Next.js API
45+
46+
### Responsibilities
47+
48+
- Session management with NextAuth.js
49+
- Request authentication
50+
- Proxy to PCDBAPI
51+
- Error handling
52+
53+
### Routes
54+
55+
- `/api/apps/*` - OIDC client management
56+
- `/api/auth/*` - Authentication endpoints
57+
58+
### Security
59+
60+
- Server-side sessions
61+
- Protected routes
62+
- Request validation
63+
- Error boundaries
64+
65+
## PCDBAPI Service
66+
67+
### Core Features
68+
69+
- MongoDB access layer
70+
- Simple, auditable code with 100% test coverage
71+
72+
### Data Model
73+
74+
The data model is strictly enforced by Pydantic models, see `pcdbapi/main.py`.
75+
76+
### Security
77+
78+
- HMAC-SHA256 request signing
79+
- Email-based access control
80+
- Timestamp validation (5-min window)
81+
82+
### API Endpoints
83+
84+
- `GET /api/oidc_clients` - List clients
85+
- `GET /api/oidc_clients/{id}` - Get client
86+
- `POST /api/oidc_clients` - Create client
87+
- `PATCH /api/oidc_clients/{id}` - Update client
88+
89+
## Authentication Flow
90+
91+
1. User -> Next.js Frontend
92+
93+
- Magic link authentication via email
94+
- No password required
95+
- Secure token in email link
96+
97+
2. Next.js Frontend -> Next.js API
98+
99+
- NextAuth.js session management
100+
- HTTP-only session cookie
101+
- Protected routes
102+
103+
3. Next.js API -> PCDBAPI
104+
- Request signing with HMAC-SHA256
105+
- Timestamp validation (5-min window)
106+
- Email ownership validation
107+
- Data validation

docs/best-practices.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Best Practices for code in this project
2+
3+
## General guidelines
4+
5+
- Use types everywhere
6+
- KISS: Keep It Simple Stupid
7+
- DRY: Don't Repeat Yourself
8+
- Don't include unnecessary third party libraries
9+
10+
## Next.js
11+
12+
- Follow the Next.js best practices
13+
14+
## FastAPI
15+
16+
- Follow the FastAPI best practices
17+
- Full test coverage

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@
1818
"build": "next build && npm run prod:prune",
1919
"prod:prune": "find node_modules -type f -name '*.map' -delete && rm -rf .next/cache",
2020
"start": "next start",
21-
"lint": "prettier --write '**/*.{ts,tsx,css,md,mdx,mjs,js}' && next lint --no-cache && npm run type-check",
21+
"lint": "prettier --write '**/*.{ts,tsx,css,md,mdx,mjs,js}' && next lint --no-cache && npm run type-check && npm run lint:pcdbapi",
22+
"lint:pcdbapi:test": "docker-compose run -T --rm pcdbapi-test sh -c 'ruff check . && ruff format --check .'",
23+
"lint:pcdbapi": "docker-compose run -T --rm pcdbapi-test sh -c 'ruff check --fix . && ruff format .'",
2224
"e2e": "NEXT_PUBLIC_BASE_PATH='' NODE_ENV=production npm run build && npm run playwright test",
23-
"test": "npm run test:lint",
25+
"test": "npm run test:lint && npm run test:pcdbapi",
2426
"test:unit": "vitest run",
2527
"test:watch": "vitest watch",
2628
"test:lint": "prettier '**/*.{ts,tsx,css,md,mdx,mjs,js}' --list-different && next lint --no-cache && npm run type-check",
2729
"test:links": "start-server-and-test 'npm run dev' 3000 'linkinator 'http://localhost:3000' --recurse --skip \"^(?!http://localhost:3000)\"'",
30+
"test:pcdbapi": "docker-compose run -T --rm pcdbapi-test pytest -vv --cov=. --cov-report term-missing --cov-fail-under=100",
2831
"type-check": "tsc --noEmit",
29-
"type-check:watch": "npm run type-check -- --watch",
3032
"db_espace:reset": "dotenv -e .env.local -- prisma db push --schema=./prisma/db_espace.prisma",
3133
"db_espace:browse": "dotenv -e .env.local -- prisma studio --schema=./prisma/db_espace.prisma",
3234
"db_proconnect:browse": "dotenv -e .env.local -- prisma studio --schema=./prisma/db_proconnect.prisma",

pcdbapi/.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
test_*.py
2+
__pycache__/
3+
.pytest_cache/
4+
.ruff_cache/
5+
*.pyc
6+
Dockerfile.test
7+
Dockerfile
8+
.coverage

pcdbapi/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:3.13.2-slim
2+
3+
WORKDIR /app
4+
5+
# Install dependencies
6+
COPY pyproject.toml .
7+
RUN pip install .
8+
9+
# Copy source code
10+
COPY . .
11+
12+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

0 commit comments

Comments
 (0)