8.1 KiB
8.1 KiB
PR Frontend (pr.degelas.be) – Plan & Deep-Dive
Goal
- Subdomain: pr.degelas.be (Public Relations – manage campaigns and scheduled posts).
- Container: degelas-pr (React/Vite frontend only).
- Auth: Login page; only authenticated users can access the PR app. Backend protects API with JWT.
- Certs/SSL: To be added later; this plan assumes HTTP first, then HTTPS when certs are in place.
Architecture
[User browser] → pr.degelas.be (nginx in fullstack_degelas)
↓
[degelas-pr container] (static React app)
↓
/api/* → proxy to degelas-backend (same as degelas.be)
↓
[degelas-backend] (FastAPI: scheduled-posts, campaigns, browser, pr-auth)
↓
[PostgreSQL] + [degelas-chrome via CDP]
- degelas-pr serves only the React SPA (built static files). No backend in this container.
- API: All calls from the PR app go to
/api(same origin once nginx proxies pr.degelas.be/api to the backend). Backend already has scheduled-posts, campaigns, browser; we add pr-auth (login, JWT) and protect PR-relevant routes when PR auth is enabled. - CORS: Backend will allow
https://pr.degelas.beandhttp://pr.degelas.beso that if the frontend ever calls degelas.be/api from pr.degelas.be (e.g. different proxy setup), it still works.
1. Backend (degelas) – PR Auth
1.1 Env (config)
- PR_AUTH_ENABLED (default
0): When1, routes under/scheduled-posts,/campaigns,/browserrequire a valid JWT. When0, no auth (current behaviour). - PR_USER: Allowed username for PR login (e.g.
pr-admin). - PR_PASSWORD: Password (plain; prefer strong value, HTTPS in production).
- PR_JWT_SECRET: Secret to sign JWTs (long random string). If unset and PR_AUTH_ENABLED=1, log a warning and reject login.
1.2 New routes
-
POST /api/pr-auth/login
Body:{ "username": "...", "password": "..." }.
If PR_AUTH_ENABLED and credentials match env: return{ "token": "<JWT>", "expires_in": 86400 }.
JWT payload:sub=username,exp=now+24h.
If auth disabled or credentials wrong: 401. -
GET /api/pr-auth/me (optional): Validate token, return
{ "username": "..." }. Used by frontend to check session.
1.3 Protection
- Dependency:
require_pr_auth– readsAuthorization: Bearer <token>, verifies JWT with PR_JWT_SECRET, returns 401 if missing/invalid. Applied to:/scheduled-posts(all methods)/campaigns(all methods)/browser(all methods)
- When PR_AUTH_ENABLED=0, dependency does nothing (no check).
1.4 CORS
- Add to
allow_origins:https://pr.degelas.be,http://pr.degelas.be,http://localhost:5174(local PR dev).
2. Frontend (degelas-pr) – React/Vite
2.1 Scope
- Container name: degelas-pr.
- Stack: React 18, Vite, TypeScript. No backend in this repo; calls
/apionly. - Build: Production build (
npm run build); serve with nginx inside the container (so one service, one port).
2.2 Routes (client-side)
- /login – Login form (username, password). On success: store token (e.g. localStorage), redirect to
/. - / – Dashboard/home (e.g. list campaigns + next scheduled posts).
- /campaigns – List campaigns; link to calendar.
- /campaigns/:id – Campaign detail / calendar (posts by date).
- /posts – List scheduled posts (filters: status, platform, campaign, date range).
- /post-now (optional) – Simple “Post now to X” test (calls POST /api/browser/post).
All routes except /login are protected: if no token (or 401 from /api), redirect to /login.
2.3 Auth flow
- Token storage: localStorage key e.g.
pr_token. Alternative: memory + refresh; localStorage is simpler for “stay logged in”. - API client: For every request to
/api, add headerAuthorization: Bearer <token>. On 401: clear token, redirect to/login. - Login page: Form → POST /api/pr-auth/login → store token → navigate to
/.
2.4 API base URL
- Production (pr.degelas.be): Use relative
/apiso the same nginx that serves the SPA can proxypr.degelas.be/apito the backend. No CORS issues. - Build-time:
VITE_API_URL=/apiin Dockerfile/env so fetch(${import.meta.env.VITE_API_URL}/scheduled-posts) becomes/api/scheduled-posts.
2.5 Docker
- Dockerfile: Multi-stage: (1) Node: install deps, build (Vite); (2) nginx: copy
dist/, copy nginx.conf, expose 80. Serve SPA with fallback to index.html for client routing. - nginx.conf:
location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; },location /api { proxy_pass http://degelas-backend:8000; proxy_set_header Host $host; }– but wait: in production, nginx is outside this container (fullstack_degelas). So the degelas-pr container only serves static files; it does not proxy /api (the external nginx will do that). So in-container nginx only needs to serve static and try_files for SPA. No /api in this container. - Compose: New service
degelas-pr, build./pr-frontend, container_namedegelas-pr, expose 80, networks: degelas + proxy. Env:VITE_API_URL=/apiat build time (ARG in Dockerfile).
3. Nginx (fullstack_degelas) – pr.degelas.be
- Later (certs/SSL): Add server block for pr.degelas.be (and optionally www.pr.degelas.be).
- SSL: certbot for pr.degelas.be when ready.
- Root: proxy_pass to degelas-pr:80 (or the port degelas-pr exposes).
location /api/: proxy_pass to degelas-backend:8000 (same as degelas.be/api).
So the browser sees one origin (pr.degelas.be), and /api goes to the same backend.
- For now: Document only; no nginx changes in this repo. When you add the block, CORS is already set for pr.degelas.be.
4. Security Summary
- Auth: Single user from env (PR_USER/PR_PASSWORD). JWT 24h expiry. No user DB in this phase.
- HTTPS: Mandatory in production for login (password in body). “Certs later” = use HTTP only for local/testing and document that production must use HTTPS.
- JWT secret: Must be set in production (PR_JWT_SECRET); strong random value.
- Rate limiting: Optional later (e.g. limit POST /api/pr-auth/login).
5. Implementation Order
- Backend: Config (PR_* env), JWT util, POST /pr-auth/login, GET /pr-auth/me, require_pr_auth dependency, apply to scheduled-posts/campaigns/browser, CORS update.
- Frontend: Scaffold React/Vite/TS in
pr-frontend/, Dockerfile (build + nginx serve static), login page, auth context, API client with Bearer token, routes (dashboard, campaigns, posts), wire to existing APIs. - Compose: Add degelas-pr service, build from pr-frontend, expose 80, networks degelas + proxy.
- Docs: README in pr-frontend (how to run, env), update main docs with pr.degelas.be and nginx/cert todo.
6. File Layout (after implementation)
solar_trading_engine/
pr-frontend/ # NEW
public/
src/
api/ # client (base URL, auth header, 401 → login)
components/
contexts/ # AuthContext
pages/
Login.tsx
Dashboard.tsx
Campaigns.tsx
CampaignCalendar.tsx
ScheduledPosts.tsx
App.tsx
main.tsx
index.html
package.json
vite.config.ts
Dockerfile # build + nginx
nginx.conf # SPA only
docker-compose.yml # + degelas-pr service
backend/
app/
pr_auth.py # NEW: login, me, JWT, dependency
main.py # include pr_auth router, CORS, apply dependency
Certs/SSL and nginx server block for pr.degelas.be remain “for later” as requested.
Implemented
- Backend:
app/pr_auth.py(login, me, JWT, require_pr_auth), config PR_* inconfig.py, CORS and router dependencies inmain.py. - Frontend:
pr-frontend/– React/Vite, Login, Dashboard, Campaigns, CampaignCalendar, ScheduledPosts, AuthContext, api client. Container degelas-pr in docker-compose. - Nginx/SSL: documented in
pr-frontend/README.md; to be configured in fullstack_degelas when ready.