Skip to content

Commit 94e5e20

Browse files
authored
Merge pull request #192 from feature/supabase-auth-google
feat: optional Google sign-in
2 parents 7fafb95 + 6d327da commit 94e5e20

60 files changed

Lines changed: 3257 additions & 47 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Bayan Flow — copy to .env.local for local development (never commit secrets)
2+
3+
# Supabase (Google OIDC auth) — publishable anon key only
4+
VITE_SUPABASE_URL=https://your-project-ref.supabase.co
5+
VITE_SUPABASE_ANON_KEY=your-anon-key
6+
7+
# Google Identity Services — Web OAuth client ID (public)
8+
VITE_GOOGLE_WEB_CLIENT_ID=your-web-client-id.apps.googleusercontent.com
9+
10+
# Optional: Pyodide CDN override (see src/constants/pyodideCdn.js)
11+
# VITE_PYODIDE_CDN_BASE=

.github/workflows/deploy-cloudflare.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ jobs:
4848
env:
4949
VITE_GIT_BRANCH: ${{ github.event.workflow_run.head_branch }}
5050
VITE_DEV_SITE_URL: https://dev.bayanflow.com
51+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
52+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
53+
VITE_GOOGLE_WEB_CLIENT_ID: ${{ secrets.VITE_GOOGLE_WEB_CLIENT_ID }}
5154

5255
- name: Deploy to Cloudflare Workers
5356
uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3

.github/workflows/preview-cloudflare.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ jobs:
5555
env:
5656
VITE_GIT_BRANCH: ${{ github.head_ref }}
5757
VITE_DEV_SITE_URL: https://dev.bayanflow.com
58+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
59+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
60+
VITE_GOOGLE_WEB_CLIENT_ID: ${{ secrets.VITE_GOOGLE_WEB_CLIENT_ID }}
5861

5962
- name: Upload preview version
6063
id: deploy

AGENTS.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
77
## Project Snapshot
88

9-
- Product: **Bayan Flow** · client-side React SPA (`/`, `/app`, `/roadmap`)
9+
- Product: **Bayan Flow** · client-side React SPA (`/`, `/app`, `/roadmap`, `/privacy`, `/terms`)
1010
- Repo: `https://github.com/ayoub3bidi/bayan-flow` · prod `main` → bayanflow.com · dev `develop` → dev.bayanflow.com
11+
- Hosting: **Cloudflare Workers** (static SPA via `wrangler.jsonc`); `netlify.toml` kept for rollback only — CI deploys through `.github/workflows/deploy-cloudflare.yml`
1112
- Tooling: React 19, Vite 7, Tailwind 4, Vitest 3, Remotion 4, i18next (en/fr/ar RTL), Pyodide 0.27.5 in worker
1213
- Engines: Node `>=24.11.1`, pnpm `>=8.15.9` · alias `@/``src/`
14+
- Version: `0.5.0` in `package.json` — algorithm categories (45 algos, 5 categories) shipped; optional Google sign-in when Supabase env vars are set
1315
- **PRs target `develop`**, not `main` (gated by `ensure-pr-source-develop.yml`)
1416

1517
## Source Of Truth (registries)
@@ -57,6 +59,19 @@ Audit all three locales + pseudocode strings + export fallbacks when renaming ca
5759

5860
See reference doc for full checklists (JS, Python, pseudocode, sound, insight, tests, registries). Keep graph algorithm commits scoped to one algorithm when possible.
5961

62+
## Auth contracts (non-negotiable)
63+
64+
- **OIDC only** — Google sign-in via Supabase Auth; no email/password flows in v0.5.0
65+
- **Service layer**`src/services/authService.js`, `profileService.js`; components use `AuthContext` / `useAuth`, never import Supabase directly
66+
- **Postgres-portable schema**`profiles` keyed to `auth.users`; RLS on public tables; client never writes `plan` (service role / webhook only, future)
67+
- **Session**`getSession()`, `onAuthStateChange()`; `AuthProvider` in `src/main.jsx`
68+
- **OAuth UX** — Google Identity Services (One Tap + PKCE popup on `/auth/google/callback`); web uses `signInWithIdToken`, not `signInWithOAuth`
69+
- **i18n** — sign-in/out strings and legal copy in en/fr/ar; audit RTL for Header auth control
70+
- **Free by default** — unauthenticated users keep full access; auth PRs must not gate existing features
71+
- **Secrets** — publishable anon key via `VITE_*` only; service role key never in repo or client bundle
72+
- **CSP** — Supabase origin in `connect-src`; Google profile photos in `img-src`; assert via `scripts/cspHeaders.js`
73+
- **Tests** — mock Supabase in Vitest (`src/test/supabaseMock.js`, wired in `src/test/setup.js`)
74+
6075
## Workflow rules
6176

6277
- Minimal diff; no unrelated edits; preserve user-authored changes

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Bayan Flow
22

33
<p align="center">
4-
<img src="./logo.png" alt="Bayan Flow Logo" width="120"/> <br/>
4+
<img src="./public/logo-white.png" alt="Bayan Flow Logo" width="120"/> <br/>
55
<strong>Learn algorithms with clarity through interactive, real-time visualizations</strong><br/>
66
<em>Bayan (بيان) means clarity in Arabic</em>
77
</p>
@@ -22,7 +22,7 @@
2222

2323
## What it is
2424

25-
Bayan Flow is a client-side SPA with **45 algorithms** across five modes. Pick a category, choose an algorithm, then step through or autoplay the visualization. Optional **Python** implementations run in the browser (Pyodide `0.27.5`), with a **complexity** panel after completion and **video export** (horizontal or vertical MP4) when you want to share or study offline.
25+
Bayan Flow is a an open source educational tool with **45 algorithms** across five categories. Choose an algorithm and step through or autoplay the visualization. Optional **Python** implementations run in the browser (Pyodide `0.27.5`), with a **complexity** panel after completion and **video export** (horizontal or vertical MP4) when you want to share or study offline.
2626

2727
## Features (overview)
2828

netlify.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
X-Content-Type-Options = "nosniff"
1818
X-Frame-Options = "DENY"
1919
Referrer-Policy = "strict-origin-when-cross-origin"
20-
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
21-
Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://cloud.umami.is https://static.cloudflareinsights.com https://cdn.jsdelivr.net; connect-src 'self' blob: https://cloud.umami.is https://gateway.umami.is https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro; img-src 'self' data: blob: https://api.producthunt.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; form-action 'self'"
20+
Permissions-Policy = "camera=(), microphone=(), geolocation=(), identity-credentials-get=(self \"https://accounts.google.com\")"
21+
Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://cloud.umami.is https://static.cloudflareinsights.com https://cdn.jsdelivr.net https://accounts.google.com; connect-src 'self' blob: https://cloud.umami.is https://gateway.umami.is https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro https://qketsapzqpzmccljfjcm.supabase.co https://accounts.google.com https://oauth2.googleapis.com; img-src 'self' data: blob: https://api.producthunt.com https://lh3.googleusercontent.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com https://accounts.google.com; object-src 'none'; base-uri 'self'; form-action 'self'"
2222

2323
# SPA routing: rewrite all non-file requests to index.html
2424
[[redirects]]

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@
5353
"preview:cf:upload": "wrangler versions upload --env staging"
5454
},
5555
"dependencies": {
56+
"@dicebear/core": "^10.3.0",
57+
"@dicebear/styles": "^10.2.0",
5658
"@fontsource-variable/inter": "^5.2.8",
5759
"@monaco-editor/react": "^4.7.0",
5860
"@octokit/rest": "^22.0.1",
5961
"@phosphor-icons/react": "^2.1.10",
6062
"@remotion/media": "4.0.436",
6163
"@remotion/web-renderer": "^4.0.436",
64+
"@supabase/supabase-js": "^2.108.2",
6265
"i18next": "^25.7.1",
6366
"i18next-browser-languagedetector": "^8.2.0",
6467
"react": "^19.2.0",

pnpm-lock.yaml

Lines changed: 85 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/_headers

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
X-Content-Type-Options: nosniff
44
X-Frame-Options: DENY
55
Referrer-Policy: strict-origin-when-cross-origin
6-
Permissions-Policy: camera=(), microphone=(), geolocation=()
6+
Permissions-Policy: camera=(), microphone=(), geolocation=(), identity-credentials-get=(self "https://accounts.google.com")
77
# Pyodide CDN origins: jsDelivr below; custom VITE_PYODIDE_CDN_BASE origins appended at build (vite.config.js)
8-
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://cloud.umami.is https://static.cloudflareinsights.com https://cdn.jsdelivr.net; connect-src 'self' blob: https://cloud.umami.is https://gateway.umami.is https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro; img-src 'self' data: blob: https://api.producthunt.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; form-action 'self'
8+
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://cloud.umami.is https://static.cloudflareinsights.com https://cdn.jsdelivr.net https://accounts.google.com; connect-src 'self' blob: https://cloud.umami.is https://gateway.umami.is https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro https://qketsapzqpzmccljfjcm.supabase.co https://accounts.google.com https://oauth2.googleapis.com; img-src 'self' data: blob: https://api.producthunt.com https://lh3.googleusercontent.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com https://accounts.google.com; object-src 'none'; base-uri 'self'; form-action 'self'
99
Link: <https://bayanflow.com/sitemap.xml>; rel="sitemap"
1010

1111
/assets/*

public/auth.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
# Authentication
22

3-
Bayan Flow is a fully client-side educational web application. No authentication or API keys are required to use the site.
3+
Bayan Flow offers optional sign-in with Google. You can use all algorithm visualizations, the code panel, insight panel, and video export without an account.
44

5-
## Usage
5+
## Sign in
66

7-
All features — algorithm visualizations, step-by-step execution, Python code editing, complexity analysis, and HD video export — are available without authentication.
7+
When you visit the site while signed into Google in your browser, a **Google One Tap** prompt may appear automatically so you can sign in with one click. You can also use the **Sign in with Google** control in the header at any time.
88

9-
## Data Privacy
9+
Sign-in uses [Google Identity Services](https://developers.google.com/identity) on **bayanflow.com** — Google shows our domain, not a third-party auth host. After you choose an account, Bayan Flow receives an ID token and creates a Supabase session. We store your Google account email, display name, and profile photo URL to show your account in the app and to maintain a minimal profile row in our database.
1010

11-
Since there is no backend server or user accounts, no personal data is collected, stored, or transmitted by the application itself. The site uses Umami analytics (a privacy-preserving analytics service) for aggregate usage statistics; no personal identification data is tracked.
11+
**Google Cloud setup (required):** in [Google Cloud Console](https://console.cloud.google.com/apis/credentials) → your **Web application** OAuth client → **Authorized JavaScript origins**, add every origin where the app runs (scheme + host + port, no trailing slash):
12+
13+
| Environment | Authorized JavaScript origin |
14+
|-------------|------------------------------|
15+
| Local dev (Vite default) | `http://localhost:5173` |
16+
| Dev deploy | `https://dev.bayanflow.com` |
17+
| Production | `https://bayanflow.com` |
18+
19+
The `VITE_GOOGLE_WEB_CLIENT_ID` in `.env.local` must match this same Web client. Redirect URIs are **not** required for One Tap or the header sign-in button. If sign-in fails with `origin_mismatch` or `403` on `accounts.google.com/gsi/`, the current browser origin is missing from that list — open DevTools and compare `window.location.origin` to the Console entries exactly.
20+
21+
**Supabase:** Authentication → Providers → Google — use the same Web Client ID and Client Secret from that OAuth client.
22+
23+
**Browser:** Chrome may block FedCM / third-party sign-in for a site. If One Tap fails, use the header **Sign in with Google** button, or re-enable third-party sign-in via the icon left of the address bar → Site settings.
24+
25+
## Data stored
26+
27+
- **Session tokens** are stored in your browser by the Supabase client library so you stay signed in across visits.
28+
- **Profile row** (`email`, display name, avatar URL, provider, plan tier) is stored in Supabase PostgreSQL. See the [Privacy Policy](/privacy) for full details.
29+
30+
## Sign out
31+
32+
Use **Sign out** from the account menu in the header at any time. This clears the local session and disables Google automatic sign-in for this browser until you sign in again.
1233

1334
## Contact
1435

15-
For questions or feedback, please open an issue at https://github.com/ayoub3bidi/bayan-flow
36+
For questions or feedback, email contact@bayanflow.com or open an issue at https://github.com/ayoub3bidi/bayan-flow

0 commit comments

Comments
 (0)