feat: platform security foundation, Pro waitlist, and UX improvements - #199
Conversation
- Delete netlify.toml (rollback config no longer needed) - Remove extractCspFromNetlifyToml from scripts/cspHeaders.js - Remove netlify.toml CSP test from cspHeaders.test.js - Update AGENTS.md hosting line to drop rollback note - Update wrangler.jsonc to drop migration-phase comments
… order - Move DELETE input and delete action into a modal with overlay/Escape/Cancel dismissal - Reorder modal buttons: Cancel left, Delete account right - Add cursor-pointer to the Delete account trigger button - Add common.cancel to all 3 locales (EN/FR/AR) - Add profile.description and profile.descriptionPlaceholder to all 3 locales
- Import useLocation alongside useNavigate - Update handleLogoClick to navigate to /app when not on /app, and to / when on /app - Fix header title descender clipping: leading-none -> leading-tight
- Add Supabase CLI local link cache to .gitignore. - Expand documentation on Supabase Edge Functions, detailing deployment steps and security measures. - Refactor main application entry to utilize centralized routing. - Implement user account access control, including handling for banned accounts and associated UI feedback. - Update privacy policy to reflect changes in data retention practices. - Add translations for access ban messages in multiple languages.
- Add entries to .gitignore for Impeccable ephemeral output and runtime state files. - Update AGENTS.md to reflect increased test coverage and source file counts. - Document new design agent workflow and Supabase Edge Functions deployment details in AGENTS_REFERENCE.md.
📝 WalkthroughWalkthroughThis PR adds platform security and signup controls, a Pro waitlist with email delivery, centralized routing and banned-account handling, shared application-shell updates, deployment automation, Cloudflare CSP validation, and expanded design, product, and operational documentation. ChangesPlatform security and signup enforcement
Pro waitlist
Application shell and interactions
Deployment and project contracts
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant Visitor
participant ProComingSoonPage
participant waitlistService
participant Supabase
participant waitlistWelcome
participant Resend
Visitor->>ProComingSoonPage: Submit email
ProComingSoonPage->>waitlistService: joinWaitlist(email, source)
waitlistService->>Supabase: Insert waitlist row
waitlistService->>Supabase: Read public waitlist count
waitlistService->>waitlistWelcome: Invoke welcome function
waitlistWelcome->>Resend: Send confirmation email
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Preview for Bayan Flow Staging ready!
Preview alias |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- Remove inert Tailwind utilities activated by @config (hover:bg-surface-elevated in Footer) - Remove fixed gradient overlay (from-bg via-bg to-surface-elevated) from LandingPage, LegalDocument, and ProComingSoonPage — this was transparent on main but renders a lighter-to-dark gradient in dark mode, causing a 'backlight' effect - Remove RoadmapCTA decorative elements (gradient overlay, glow orb, badge pill) that rendered unintentionally due to @config activating previously dead utilities - Make Header non-sticky (always relative, never sm:fixed) - Show 'Sign in with Google' text on non-/app pages; icon-only on /app - Update tests to match removed elements
There was a problem hiding this comment.
Actionable comments posted: 17
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/VisualizerApp.jsx (1)
639-646: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winEnsure the "Skip to main content" link remains the first focusable element.
Placing the
ProWaitlistBannerbefore the "Skip to main content" link introduces focusable elements (the banner's CTA link and dismiss button) before the skip link. This forces keyboard-only and screen-reader users to navigate through the banner before they can skip to the main content, degrading accessibility.Move the
ProWaitlistBannerbelow the skip navigation link.♿ Proposed fix
- <ProWaitlistBanner source="app" /> {/* Skip Navigation Link */} <a href="`#main-content`" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-blue-600 focus:text-white focus:rounded-md focus:shadow-lg" > Skip to main content </a> + <ProWaitlistBanner source="app" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/VisualizerApp.jsx` around lines 639 - 646, Move the ProWaitlistBanner component below the “Skip to main content” anchor in VisualizerApp, ensuring the skip-navigation link remains the first focusable element while preserving the banner’s existing rendering.
🟡 Minor comments (4)
supabase/functions/before-signup/index.ts-66-66 (1)
66-66: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winAvoid logging the raw email address.
console.warnhere logs the user's email in plaintext. Consider omitting it or logging a redacted/hashed identifier instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/before-signup/index.ts` at line 66, Update the warning in the before-signup handler for missing metadata.ip_address to stop logging the raw email address. Omit the email from the console.warn context or replace it with a redacted or hashed identifier while preserving the warning message.supabase/functions/waitlist-welcome/index.ts-39-66 (1)
39-66: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
positionparameter is unused in the email template.
buildEmailHtmlacceptspositionbut the returnedsubject/htmlnever reference it, so the queue-position feature implied by the parameter (and by the surrounding migration comment about "position display") never reaches the email content. Either wire it into the copy or drop the dead parameter.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/waitlist-welcome/index.ts` around lines 39 - 66, The buildEmailHtml function accepts an unused position parameter; either incorporate position into the returned subject or html to display the recipient’s queue position, or remove the parameter and update its callers if position is not intended to appear. Ensure the chosen behavior matches the surrounding waitlist position-display requirement.src/contexts/AuthProvider.jsx-110-120 (1)
110-120: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winLog non-ban
getUser()failures before falling through.AccountBannedErroris the only special case here; any other error fromauthService.getUser()is currently swallowed and the flow continues tocheckPlatformAccess(), which can hide auth/network issues.src/contexts/AuthProvider.jsx:110-120🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/contexts/AuthProvider.jsx` around lines 110 - 120, Update the getUser() catch block in AuthProvider to log non-AccountBannedError failures before continuing to checkPlatformAccess(). Preserve the existing stale-check guard and account_banned handling, and ensure only the non-ban error path is logged.src/i18n/locales/fr/translation.json-64-111 (1)
64-111: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFix French grammatical errors in waitlist copy.
A couple of phrases use incorrect grammar ("le Plan Pro" instead of "du Plan Pro") and contain an errant space before a period.
✏️ Proposed fixes
Apply these updates to correct the French phrasing:
- "metaDescription": "Rejoignez la liste d'attente le Plan Pro et sécurisez 50 % de réduction sur votre première année au plan annuel.", + "metaDescription": "Rejoignez la liste d'attente du Plan Pro et sécurisez 50 % de réduction sur votre première année au plan annuel.",And update the
alreadyJoinedbody text:"alreadyJoined": { "title": "Vous êtes déjà inscrit", - "body": "Nous avons déjà votre e-mail. Nous vous préviendrons au lancement de le plan pro ." + "body": "Nous avons déjà votre e-mail. Nous vous préviendrons au lancement du Plan Pro." },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/i18n/locales/fr/translation.json` around lines 64 - 111, Correct the French waitlist copy in the locale entries, changing the affected “le Plan Pro” phrasing to the grammatically correct “du Plan Pro” and removing the extra space before the period in the alreadyJoined.body text. Preserve all other translations and keys unchanged.
🧹 Nitpick comments (8)
supabase/functions/delete-account/index.ts (1)
89-93: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueComment overstates the effect of the explicit
falseargument.Per Supabase's docs,
shouldSoftDeletedefaults to false (permanent delete), so the previous call (without a second argument) was already a hard delete — this change doesn't alter reuse behavior, just makes the existing default explicit.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/delete-account/index.ts` around lines 89 - 93, Update the comment above the supabaseAdmin.auth.admin.deleteUser call to accurately state that the explicit false argument preserves the default permanent-delete behavior, without claiming it newly enables immediate Google email reuse.supabase/functions/_shared/cors.ts (1)
37-43: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueConsider adding
Vary: Originwhen echoing the request Origin.Since
Access-Control-Allow-Originis computed per-request based on the incomingOriginheader, addVary: Originto avoid a caching layer (if any is ever introduced in front of these functions) serving one origin's CORS headers to another origin's request.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/_shared/cors.ts` around lines 37 - 43, Add a "Vary: Origin" response header in buildCorsHeaders alongside the computed Access-Control-Allow-Origin header, preserving the existing origin resolution and other CORS headers.supabase/migrations/20260710150000_pro_waitlist_attribution.sql (1)
1-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMigration appears entirely redundant with
20260710140000_pro_waitlist.sql.
supabase/migrations/20260710140000_pro_waitlist.sql(which runs first by timestamp) already createspublic.waitlistwith the identicalsourcecolumn/check, the identicalwaitlist_source_idxindex, and an identicalwaitlist_public_count()function with the same grants. Every statement here is a guarded no-op (IF NOT EXISTS/CREATE OR REPLACE) against that schema, so this file adds no schema change in practice — worth double-checking this wasn't left behind after the base migration was later edited to embed what this file originally added.Since the index already exists when this statement runs, the Squawk
require-concurrent-index-creationhint on line 10 doesn't apply in practice here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/migrations/20260710150000_pro_waitlist_attribution.sql` around lines 1 - 24, Remove the redundant migration contents from the migration that duplicates the waitlist schema, index, RPC, and grants already established by the earlier waitlist migration. Ensure the migration no longer reissues the guarded ALTER, index creation, function replacement, or privilege statements, preserving the earlier migration as the single source of truth.Source: Linters/SAST tools
src/pages/Roadmap.jsx (1)
8-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove unused
useTranslationimport and hook call.The
tfunction is no longer used in this component since the language switcher and "back" controls were moved into theHeadercomponent. Removing it resolves the linter warning.♻️ Proposed refactor
import { useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; import RoadmapHero from '../components/roadmap/RoadmapHero'; import Timeline from '../components/roadmap/Timeline'; import Footer from '../components/Footer'; import Header from '../components/Header'; function Roadmap() { - const { t } = useTranslation(); - // Scroll to top when component mounts useEffect(() => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/Roadmap.jsx` around lines 8 - 15, Remove the unused useTranslation import and the corresponding t hook call from the Roadmap component, leaving the remaining imports and component behavior unchanged.Source: Linters/SAST tools
src/pages/ProComingSoonPage.jsx (2)
271-278: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winError-message branch untested.
codecov flags lines 272-278 (the
invalid_email/unavailable/genericerror rendering) as uncovered;ProComingSoonPage.test.jsxonly exercises success and already-joined paths.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/ProComingSoonPage.jsx` around lines 271 - 278, Extend ProComingSoonPage.test.jsx with coverage for the errorKey rendering branch in ProComingSoonPage, exercising invalid_email, unavailable, and generic error cases as appropriate. Assert that the alert with id pro-waitlist-email-error renders the translated error message, while preserving the existing success and already-joined tests.Source: Linters/SAST tools
71-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDead
positionstate and commented-out JSX.
position/setPositionare set but never rendered (only consumer is the commented-out TODO block), matching the CI "unused var" warnings on line 71. Since it's parked for later reinstatement, consider dropping the state now and re-adding it (with the JSX) when the feature returns — git history preserves the commented block.Also applies to: 102-102, 204-209
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/ProComingSoonPage.jsx` at line 71, Remove the unused position state declaration and its setter from ProComingSoonPage, along with the associated commented-out JSX/TODO block that is its only consumer. Leave the active page behavior unchanged and reintroduce this state only when the related feature is implemented.Source: Linters/SAST tools
src/utils/authBan.test.js (1)
17-28: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd coverage for the untested
isSignInBlockedErrorbranches.
'signup is disabled'and'User not allowed'message branches aren't exercised.✅ Suggested additional assertions
expect( isSignInBlockedError({ message: 'Invalid payload sent to hook' }) ).toBe(true); + expect( + isSignInBlockedError({ message: 'User not allowed to sign in' }) + ).toBe(true); + expect( + isSignInBlockedError({ message: 'signup is disabled for this project' }) + ).toBe(true); expect(isSignInBlockedError({ code: 'unexpected_failure' })).toBe(true);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/authBan.test.js` around lines 17 - 28, Add assertions to the existing “detects blocked sign-in errors” test for isSignInBlockedError, covering messages “signup is disabled” and “User not allowed” and expecting both to return true. Preserve the current cases and expectations.src/contexts/AuthProvider.jsx (1)
61-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRef mutated during render (flagged by static analysis).
userRef.current = userexecutes unconditionally in the component body, which React's rendering-purity rules discourage since render can be replayed/discarded without committing. Functionally safe here today (only consumed from thevisibilitychangelistener, not read during render), but consider moving the assignment into auseEffect/useLayoutEffectfor correctness under React 19 concurrent semantics.♻️ Optional refactor
- const userRef = useRef(null); - userRef.current = user; + const userRef = useRef(null); + useEffect(() => { + userRef.current = user; + }, [user]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/contexts/AuthProvider.jsx` around lines 61 - 65, Move the userRef.current assignment out of the AuthProvider render body and into an effect that runs when user changes, while preserving the existing userRef usage by the visibilitychange listener.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/deploy-supabase-functions.yml:
- Around line 17-20: Add a head_repository check to the workflow_run condition
in the deployment workflow, requiring
github.event.workflow_run.head_repository.full_name to equal github.repository
alongside the existing successful main/develop branch checks. Preserve
deployment behavior for successful base-repository runs while preventing
fork-originated workflows from executing.
In `@src/components/ProWaitlistBanner.jsx`:
- Around line 71-77: Update ProWaitlistBannerContent to accept the inRouter
boolean from ProWaitlistBanner and conditionally render the CTA as a React
Router Link when true, or a regular anchor using the same destination and
relevant attributes when false. Ensure both the primary CTA and the additionally
referenced banner link avoid Link rendering outside a Router context.
In `@src/contexts/AuthProvider.jsx`:
- Around line 90-108: Update the !activeUser branch of evaluateAccess to clear
the stored profile row by invoking refreshProfile(null) before returning, while
preserving the existing access-block reset and stale-check behavior. Ensure
hydrate and onAuthStateChange sign-out/session-loss paths remove the previous
user’s profile data.
In `@src/index.css`:
- Around line 578-755: Rename all proSort0–proSort5 keyframes to kebab-case
pro-sort-0 through pro-sort-5 and update the matching animation references in
the pro-sorting-tile-1 through pro-sorting-tile-6 rules. Add narrowly scoped
stylelint suppression around these intentional duplicate keyframe selectors so
the existing hold-and-jump animation timing remains unchanged.
In `@src/pages/ProComingSoonPage.jsx`:
- Around line 59-77: Prevent the default-email synchronization in the
ProComingSoonPage component from overwriting user input: track whether the email
field has been edited, mark it edited in the input/change handler, and make the
defaultEmail effect update email only while the field remains unedited. Preserve
applying asynchronously resolved profile, user, or stored email values before
any user edit.
In `@src/pages/ProfileSettingsPage.jsx`:
- Around line 469-492: Update the delete modal flow in ProfileSettingsPage
around the motion.div dialog so opening it moves initial focus into the dialog,
allowing Escape to trigger its existing onKeyDown dismissal immediately while
preserving the current close and confirmation-text reset behavior.
In `@src/security/cspHeaders.test.js`:
- Line 10: Restore expect to the vitest import in cspHeaders.test.js, alongside
describe, it, vi, and beforeEach, so the existing assertions resolve correctly.
In `@src/services/accessService.js`:
- Around line 22-47: Update checkPlatformAccess so the supabase.functions.invoke
call is bounded by a request timeout or timeout race. When the timeout expires,
handle it through the existing catch/fail-open path, returning allowed: true
with failOpen: true so evaluateAccess and AuthProvider hydration cannot remain
pending.
In `@src/services/waitlistService.js`:
- Around line 46-52: Update persistWaitlistEmail and readStoredWaitlistEmail to
use sessionStorage instead of localStorage, keeping the existing
WAITLIST_EMAIL_STORAGE_KEY and error-handling behavior. Ensure reads and writes
are session-scoped so the cleartext email is not retained across browser
sessions.
In `@supabase/functions/_shared/telegram.ts`:
- Around line 8-33: Add an AbortController-based timeout to the fetch call in
sendTelegramAlert, passing its signal and aborting after a bounded duration so
an unresponsive Telegram API cannot block the awaited request indefinitely.
Preserve the existing request payload and non-OK response logging.
In `@supabase/functions/before-signup/index.ts`:
- Around line 65-74: Update the invalid-IP branch in the before-signup handler
so missing or invalid metadata.ip_address does not immediately allow signup or
bypass trusted_ips, banned_ips, and rate-limit enforcement. Make this path fail
closed using the function’s established rejection or conservative-default
behavior, while preserving signup_pending recording as appropriate and ensuring
valid IPs continue through the existing checks.
In `@supabase/functions/delete-account/index.ts`:
- Around line 57-93: Refactor the delete-account flow around the cleanup queries
and auth.admin.deleteUser so profile, signup_events, signup_pending cleanup, and
account deletion execute atomically through a single transactional Postgres RPC
or equivalent database function. Ensure any failure rolls back all cleanup
changes and only report success after every operation completes.
In `@supabase/functions/post-signup/index.ts`:
- Around line 69-117: Handle and surface Supabase errors for every query in the
post-signup flow, including the pending lookup, profile update, signup event
insert, banned-IP lookup, IP-event lookup, and pending cleanup. Update each call
to inspect its returned error and log or propagate it using the function’s
established error-handling mechanism, while preserving the existing no-row
behavior for successful queries.
In `@supabase/functions/waitlist-welcome/index.ts`:
- Line 104: Update handleRequest to prevent repeated welcome-email sends by
atomically checking and recording a sent state on the waitlist record (using an
appropriate welcomed_at or equivalent column), while preserving safe behavior
for already-processed entries. Add basic rate limiting for unauthenticated
requests, and make waitlist lookup responses indistinguishable for existing
versus non-existing emails so membership cannot be enumerated.
In `@supabase/migrations/20260710120000_platform_security_foundation.sql`:
- Around line 102-118: Remove last_active_at from the authenticated role’s
direct column UPDATE grant, leaving only display_name and avatar_preference
writable. Keep touch_last_active() and its authenticated EXECUTE grant so
last_active_at can be changed exclusively through the RPC.
In `@supabase/migrations/20260710130000_post_signup_webhook_trigger.sql`:
- Around line 17-46: Replace the hardcoded Supabase project URL in the
net.http_post call with an environment-aware configuration value, reusing the
project’s established configuration mechanism. Ensure each environment resolves
its own post-signup function endpoint while preserving the existing webhook
payload, headers, and secret handling.
In `@supabase/migrations/20260710160000_drop_waitlist_pitch_variant.sql`:
- Line 3: Remove the destructive waitlist schema change by deleting the ALTER
TABLE statement that drops pitch_variant. Keep the column in place for backward
compatibility, and defer its removal until all deployed application and Edge
Function clients no longer reference it.
---
Outside diff comments:
In `@src/pages/VisualizerApp.jsx`:
- Around line 639-646: Move the ProWaitlistBanner component below the “Skip to
main content” anchor in VisualizerApp, ensuring the skip-navigation link remains
the first focusable element while preserving the banner’s existing rendering.
---
Minor comments:
In `@src/contexts/AuthProvider.jsx`:
- Around line 110-120: Update the getUser() catch block in AuthProvider to log
non-AccountBannedError failures before continuing to checkPlatformAccess().
Preserve the existing stale-check guard and account_banned handling, and ensure
only the non-ban error path is logged.
In `@src/i18n/locales/fr/translation.json`:
- Around line 64-111: Correct the French waitlist copy in the locale entries,
changing the affected “le Plan Pro” phrasing to the grammatically correct “du
Plan Pro” and removing the extra space before the period in the
alreadyJoined.body text. Preserve all other translations and keys unchanged.
In `@supabase/functions/before-signup/index.ts`:
- Line 66: Update the warning in the before-signup handler for missing
metadata.ip_address to stop logging the raw email address. Omit the email from
the console.warn context or replace it with a redacted or hashed identifier
while preserving the warning message.
In `@supabase/functions/waitlist-welcome/index.ts`:
- Around line 39-66: The buildEmailHtml function accepts an unused position
parameter; either incorporate position into the returned subject or html to
display the recipient’s queue position, or remove the parameter and update its
callers if position is not intended to appear. Ensure the chosen behavior
matches the surrounding waitlist position-display requirement.
---
Nitpick comments:
In `@src/contexts/AuthProvider.jsx`:
- Around line 61-65: Move the userRef.current assignment out of the AuthProvider
render body and into an effect that runs when user changes, while preserving the
existing userRef usage by the visibilitychange listener.
In `@src/pages/ProComingSoonPage.jsx`:
- Around line 271-278: Extend ProComingSoonPage.test.jsx with coverage for the
errorKey rendering branch in ProComingSoonPage, exercising invalid_email,
unavailable, and generic error cases as appropriate. Assert that the alert with
id pro-waitlist-email-error renders the translated error message, while
preserving the existing success and already-joined tests.
- Line 71: Remove the unused position state declaration and its setter from
ProComingSoonPage, along with the associated commented-out JSX/TODO block that
is its only consumer. Leave the active page behavior unchanged and reintroduce
this state only when the related feature is implemented.
In `@src/pages/Roadmap.jsx`:
- Around line 8-15: Remove the unused useTranslation import and the
corresponding t hook call from the Roadmap component, leaving the remaining
imports and component behavior unchanged.
In `@src/utils/authBan.test.js`:
- Around line 17-28: Add assertions to the existing “detects blocked sign-in
errors” test for isSignInBlockedError, covering messages “signup is disabled”
and “User not allowed” and expecting both to return true. Preserve the current
cases and expectations.
In `@supabase/functions/_shared/cors.ts`:
- Around line 37-43: Add a "Vary: Origin" response header in buildCorsHeaders
alongside the computed Access-Control-Allow-Origin header, preserving the
existing origin resolution and other CORS headers.
In `@supabase/functions/delete-account/index.ts`:
- Around line 89-93: Update the comment above the
supabaseAdmin.auth.admin.deleteUser call to accurately state that the explicit
false argument preserves the default permanent-delete behavior, without claiming
it newly enables immediate Google email reuse.
In `@supabase/migrations/20260710150000_pro_waitlist_attribution.sql`:
- Around line 1-24: Remove the redundant migration contents from the migration
that duplicates the waitlist schema, index, RPC, and grants already established
by the earlier waitlist migration. Ensure the migration no longer reissues the
guarded ALTER, index creation, function replacement, or privilege statements,
preserving the earlier migration as the single source of truth.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c8e773d9-a46a-4232-9260-b23b167b1e03
📒 Files selected for processing (83)
.github/workflows/deploy-supabase-functions.yml.gitignore.impeccable/config.json.impeccable/design.json.impeccable/live/config.jsonAGENTS.mdDESIGN.mdPRODUCT.mddocs/AGENTS_REFERENCE.mddocs/DEVELOPMENT.mdeslint.config.jsnetlify.tomlpublic/sitemap.xmlscripts/cspHeaders.jssrc/AppRoutes.jsxsrc/AppRoutes.test.jsxsrc/components/BannedScreen.jsxsrc/components/BannedScreen.test.jsxsrc/components/DocumentTitle.jsxsrc/components/DocumentTitle.test.jsxsrc/components/Footer.jsxsrc/components/Header.jsxsrc/components/LanguageSwitcher.jsxsrc/components/LegalDocument.jsxsrc/components/LegalDocument.test.jsxsrc/components/ProWaitlistBanner.jsxsrc/components/ProWaitlistBanner.test.jsxsrc/components/SignInPromptModal.jsxsrc/components/SignInPromptModal.test.jsxsrc/components/UserMenu.jsxsrc/components/UserMenu.test.jsxsrc/components/landing/RoadmapCTA.jsxsrc/components/landing/RoadmapCTA.test.jsxsrc/components/ui/Button.jsxsrc/constants/waitlist.jssrc/content/legal/privacy.en.jssrc/contexts/AuthContextDefinition.jssrc/contexts/AuthProvider.jsxsrc/contexts/AuthProvider.test.jsxsrc/i18n/locales/ar/translation.jsonsrc/i18n/locales/en/translation.jsonsrc/i18n/locales/fr/translation.jsonsrc/index.csssrc/main.jsxsrc/pages/LandingPage.jsxsrc/pages/LandingPage.test.jsxsrc/pages/PrivacyPolicy.test.jsxsrc/pages/ProComingSoonPage.jsxsrc/pages/ProComingSoonPage.test.jsxsrc/pages/ProfileSettingsPage.jsxsrc/pages/ProfileSettingsPage.test.jsxsrc/pages/Roadmap.jsxsrc/pages/Roadmap.test.jsxsrc/pages/TermsOfUse.test.jsxsrc/pages/VisualizerApp.jsxsrc/pages/VisualizerApp.test.jsxsrc/security/cspHeaders.test.jssrc/services/accessService.jssrc/services/accessService.test.jssrc/services/authService.jssrc/services/profileService.jssrc/services/waitlistService.jssrc/services/waitlistService.test.jssrc/test/supabaseMock.jssrc/utils/authBan.jssrc/utils/authBan.test.jssrc/utils/banLogic.jssrc/utils/banLogic.test.jssupabase/functions/_shared/banLogic.tssupabase/functions/_shared/cors.tssupabase/functions/_shared/telegram.tssupabase/functions/_shared/webhookVerify.tssupabase/functions/before-signup/index.tssupabase/functions/delete-account/index.tssupabase/functions/platform-access/index.tssupabase/functions/post-signup/index.tssupabase/functions/waitlist-welcome/index.tssupabase/migrations/20260710120000_platform_security_foundation.sqlsupabase/migrations/20260710130000_post_signup_webhook_trigger.sqlsupabase/migrations/20260710140000_pro_waitlist.sqlsupabase/migrations/20260710150000_pro_waitlist_attribution.sqlsupabase/migrations/20260710160000_drop_waitlist_pitch_variant.sqlwrangler.jsonc
💤 Files with no reviewable changes (4)
- src/components/LanguageSwitcher.jsx
- wrangler.jsonc
- netlify.toml
- scripts/cspHeaders.js
| begin | ||
| select ds.decrypted_secret into webhook_secret | ||
| from vault.decrypted_secrets ds | ||
| where ds.name = 'post_signup_webhook_secret' | ||
| limit 1; | ||
|
|
||
| if webhook_secret is null then | ||
| raise warning 'post_signup_webhook_secret missing from vault'; | ||
| return NEW; | ||
| end if; | ||
|
|
||
| payload := jsonb_build_object( | ||
| 'type', TG_OP, | ||
| 'table', TG_TABLE_NAME, | ||
| 'schema', TG_TABLE_SCHEMA, | ||
| 'record', to_jsonb(NEW), | ||
| 'old_record', null | ||
| ); | ||
|
|
||
| headers := jsonb_build_object( | ||
| 'Content-Type', 'application/json', | ||
| 'x-webhook-secret', webhook_secret | ||
| ); | ||
|
|
||
| perform net.http_post( | ||
| url := 'https://qketsapzqpzmccljfjcm.supabase.co/functions/v1/post-signup', | ||
| headers := headers, | ||
| body := payload | ||
| ); | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Hardcoded project URL breaks portability across environments.
The webhook secret is externalized via vault, but the target URL at Line 42 is hardcoded to one specific project ref. Replaying this migration in another environment (staging/preview) will send webhook calls to the wrong (or production) project.
🔧 Suggested approach
+ select ds.decrypted_secret into webhook_url
+ from vault.decrypted_secrets ds
+ where ds.name = 'post_signup_webhook_url'
+ limit 1;
+
perform net.http_post(
- url := 'https://qketsapzqpzmccljfjcm.supabase.co/functions/v1/post-signup',
+ url := coalesce(webhook_url, 'https://qketsapzqpzmccljfjcm.supabase.co/functions/v1/post-signup'),
headers := headers,
body := payload
);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@supabase/migrations/20260710130000_post_signup_webhook_trigger.sql` around
lines 17 - 46, Replace the hardcoded Supabase project URL in the net.http_post
call with an environment-aware configuration value, reusing the project’s
established configuration mechanism. Ensure each environment resolves its own
post-signup function endpoint while preserving the existing webhook payload,
headers, and secret handling.
Security: - Restrict deploy-supabase-functions workflow to base repository only (#1) - Fail-closed on missing IP metadata in before-signup hook (#11) - Switch waitlist email from localStorage to sessionStorage (#9) - Remove last_active_at from direct client UPDATE grant; use security definer RPC (#15) Functional correctness: - Clear profileRow on implicit sign-out in AuthProvider (#3) - Prevent email useEffect from clobbering user input on ProComingSoonPage (#5) - Add autoFocus to delete modal for immediate Escape dismissal (#6) - Fix Link rendering outside Router context in ProWaitlistBanner (#2) - Move skip-to-content link above ProWaitlistBanner for a11y (#18) Stability & hardening: - Add timeout to supabase.functions.invoke in accessService (#8) - Add AbortSignal.timeout to Telegram fetch call (#10) - Reorder delete-account to deleteUser before cleanup for atomicity (#12) - Add error handling for all Supabase calls in post-signup (#13) - Add idempotency guard (welcomed_at) to waitlist-welcome (#14) Code quality: - Rename proSort0-5 to kebab-case pro-sort-0-5 with stylelint suppression (#4) - Restore expect import in cspHeaders.test (#7) - Revert destructive column drop in migration (#17) - Add new migration for welcomed_at column (#14) Tests: - Add test for implicit sign-out profile clearing (AuthProvider) - Add test for email input not clobbered by async auth (ProComingSoonPage) - Add test for Escape dismissing delete modal (ProfileSettingsPage) - Add test for anchor rendering outside Router (ProWaitlistBanner)
npm retired the /-/npm/v1/security/audits endpoint, causing pnpm audit to fail with 410 on every CI run. Use the built-in --ignore-registry-errors flag so the audit still runs when the registry is available but doesn't block CI when it's down.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/pages/ProComingSoonPage.jsx (1)
72-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove unused
positionstate.The
positionstate variable is declared here and updated on line 105, but its usage in the JSX (lines 207-212) is currently commented out. This triggers a lint warning for an unused variable. Consider removing the state and its correspondingsetPositioncall until the UI is ready to be re-enabled.♻️ Proposed refactor
Remove the state declaration:
- const [position, setPosition] = useState(null);And also remove the state update further down in the file (around line 105):
if (result.status === 'joined') { - setPosition(result.position ?? null); setSubmitState('success'); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/ProComingSoonPage.jsx` at line 72, Remove the unused position state declaration in the component and delete the corresponding setPosition call in the joined-result branch of the submission handler, while leaving the existing submitState behavior unchanged.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/security/cspHeaders.test.js`:
- Line 10: Remove the unused expect import from the Vitest import declaration in
the cspHeaders test file, while preserving the remaining describe, it, vi, and
beforeEach imports.
---
Nitpick comments:
In `@src/pages/ProComingSoonPage.jsx`:
- Line 72: Remove the unused position state declaration in the component and
delete the corresponding setPosition call in the joined-result branch of the
submission handler, while leaving the existing submitState behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 637c2c24-3141-4b16-8c1b-f06f066ac3ae
📒 Files selected for processing (24)
.github/workflows/deploy-supabase-functions.ymlsrc/components/Footer.jsxsrc/components/ProWaitlistBanner.jsxsrc/components/ProWaitlistBanner.test.jsxsrc/contexts/AuthProvider.jsxsrc/contexts/AuthProvider.test.jsxsrc/index.csssrc/pages/ProComingSoonPage.jsxsrc/pages/ProComingSoonPage.test.jsxsrc/pages/ProfileSettingsPage.jsxsrc/pages/ProfileSettingsPage.test.jsxsrc/pages/VisualizerApp.jsxsrc/security/cspHeaders.test.jssrc/services/accessService.jssrc/services/waitlistService.jssrc/services/waitlistService.test.jssupabase/functions/_shared/telegram.tssupabase/functions/before-signup/index.tssupabase/functions/delete-account/index.tssupabase/functions/post-signup/index.tssupabase/functions/waitlist-welcome/index.tssupabase/migrations/20260710120000_platform_security_foundation.sqlsupabase/migrations/20260710160000_drop_waitlist_pitch_variant.sqlsupabase/migrations/20260715200000_add_welcomed_at_to_waitlist.sql
🚧 Files skipped from review as they are similar to previous changes (16)
- supabase/functions/_shared/telegram.ts
- src/services/accessService.js
- src/pages/VisualizerApp.jsx
- src/components/ProWaitlistBanner.jsx
- src/pages/ProfileSettingsPage.test.jsx
- .github/workflows/deploy-supabase-functions.yml
- supabase/functions/post-signup/index.ts
- src/pages/ProComingSoonPage.test.jsx
- src/components/Footer.jsx
- src/services/waitlistService.js
- src/index.css
- src/pages/ProfileSettingsPage.jsx
- src/services/waitlistService.test.js
- supabase/functions/delete-account/index.ts
- supabase/migrations/20260710120000_platform_security_foundation.sql
- src/contexts/AuthProvider.jsx
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/pages/ProComingSoonPage.jsx (1)
72-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove unused
positionstate.The
positionstate variable is declared here and updated on line 105, but its usage in the JSX (lines 207-212) is currently commented out. This triggers a lint warning for an unused variable. Consider removing the state and its correspondingsetPositioncall until the UI is ready to be re-enabled.♻️ Proposed refactor
Remove the state declaration:
- const [position, setPosition] = useState(null);And also remove the state update further down in the file (around line 105):
if (result.status === 'joined') { - setPosition(result.position ?? null); setSubmitState('success'); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/ProComingSoonPage.jsx` at line 72, Remove the unused position state declaration in the component and delete the corresponding setPosition call in the joined-result branch of the submission handler, while leaving the existing submitState behavior unchanged.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/security/cspHeaders.test.js`:
- Line 10: Remove the unused expect import from the Vitest import declaration in
the cspHeaders test file, while preserving the remaining describe, it, vi, and
beforeEach imports.
---
Nitpick comments:
In `@src/pages/ProComingSoonPage.jsx`:
- Line 72: Remove the unused position state declaration in the component and
delete the corresponding setPosition call in the joined-result branch of the
submission handler, while leaving the existing submitState behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 637c2c24-3141-4b16-8c1b-f06f066ac3ae
📒 Files selected for processing (24)
.github/workflows/deploy-supabase-functions.ymlsrc/components/Footer.jsxsrc/components/ProWaitlistBanner.jsxsrc/components/ProWaitlistBanner.test.jsxsrc/contexts/AuthProvider.jsxsrc/contexts/AuthProvider.test.jsxsrc/index.csssrc/pages/ProComingSoonPage.jsxsrc/pages/ProComingSoonPage.test.jsxsrc/pages/ProfileSettingsPage.jsxsrc/pages/ProfileSettingsPage.test.jsxsrc/pages/VisualizerApp.jsxsrc/security/cspHeaders.test.jssrc/services/accessService.jssrc/services/waitlistService.jssrc/services/waitlistService.test.jssupabase/functions/_shared/telegram.tssupabase/functions/before-signup/index.tssupabase/functions/delete-account/index.tssupabase/functions/post-signup/index.tssupabase/functions/waitlist-welcome/index.tssupabase/migrations/20260710120000_platform_security_foundation.sqlsupabase/migrations/20260710160000_drop_waitlist_pitch_variant.sqlsupabase/migrations/20260715200000_add_welcomed_at_to_waitlist.sql
🚧 Files skipped from review as they are similar to previous changes (16)
- supabase/functions/_shared/telegram.ts
- src/services/accessService.js
- src/pages/VisualizerApp.jsx
- src/components/ProWaitlistBanner.jsx
- src/pages/ProfileSettingsPage.test.jsx
- .github/workflows/deploy-supabase-functions.yml
- supabase/functions/post-signup/index.ts
- src/pages/ProComingSoonPage.test.jsx
- src/components/Footer.jsx
- src/services/waitlistService.js
- src/index.css
- src/pages/ProfileSettingsPage.jsx
- src/services/waitlistService.test.js
- supabase/functions/delete-account/index.ts
- supabase/migrations/20260710120000_platform_security_foundation.sql
- src/contexts/AuthProvider.jsx
🛑 Comments failed to post (1)
src/security/cspHeaders.test.js (1)
10-10: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the unused
expectimport.The
expectfunction is no longer used because the test block relying on it was deleted. Removing it will resolve the static analysis warning.♻️ Proposed fix
-import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { describe, it, vi, beforeEach } from 'vitest';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.import { describe, it, vi, beforeEach } from 'vitest';🧰 Tools
🪛 GitHub Check: Code Quality
[warning] 10-10:
'expect' is defined but never used. Allowed unused vars must match /^[A-Z_]|^motion$/u🪛 GitHub Check: Upload PR preview
[warning] 10-10:
'expect' is defined but never used. Allowed unused vars must match /^[A-Z_]|^motion$/u🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/security/cspHeaders.test.js` at line 10, Remove the unused expect import from the Vitest import declaration in the cspHeaders test file, while preserving the remaining describe, it, vi, and beforeEach imports.Source: Linters/SAST tools
The <main> element had sm:pt-20 (80px) while the header is only 56px (h-14) and in normal document flow. This created 24px of dead space between the header and content. Removed pt-0 sm:pt-20 since p-6 provides sufficient spacing.
Hide GitHub repo badge, language switcher, and theme toggle on pages other than /app. These controls are auto-detected (browser language, system theme) and can be changed from the visualizer. The sign-in button remains visible everywhere; the user avatar is hidden when authenticated on non-/app pages to reduce distraction. - Header: gate GitHubRepoBadge, LanguageSwitcher, ThemeToggle behind isAppPage - UserMenu: accept hideAvatar prop, return null when authenticated on non-/app - Extract isAppPage from location.pathname for cleaner conditionals
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/VisualizerApp.jsx (1)
646-646: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winHide the waitlist banner in fullscreen mode.
Line 646 renders
ProWaitlistBanneroutside theisFullScreenconditional, so it remains visible while the fullscreen panel is active and consumes space above theh-screenvisualizer. Render it only in normal mode, for example with{!isFullScreen && <ProWaitlistBanner source="app" />}.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/VisualizerApp.jsx` at line 646, Update the ProWaitlistBanner render in VisualizerApp so it is conditional on !isFullScreen, keeping the banner visible in normal mode while hiding it during fullscreen mode.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Line 47: Update the CI audit step to remove --ignore-registry-errors from the
pnpm audit command, ensuring registry failures remain visible and cause the
workflow gate to fail; alternatively, add a separate vulnerability scanner whose
result explicitly gates CI.
---
Outside diff comments:
In `@src/pages/VisualizerApp.jsx`:
- Line 646: Update the ProWaitlistBanner render in VisualizerApp so it is
conditional on !isFullScreen, keeping the banner visible in normal mode while
hiding it during fullscreen mode.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fbc2b594-523e-4150-95ea-29f2404c4a64
📒 Files selected for processing (2)
.github/workflows/ci.ymlsrc/pages/VisualizerApp.jsx
The insight panel backdrop used fixed inset-0 with no top offset,
covering the entire viewport including the header. On desktop, offset
the backdrop by 56px (header height) to match the PythonCodePanel
behavior. Mobile remains full-viewport since the panel sheets up from
the bottom.
- Add isMobile state with resize listener (matching PythonCodePanel)
- Apply style={{ top: '56px' }} to backdrop on desktop
The flag made pnpm audit exit 0 on registry non-200 responses, so the audit gate could pass without scanning any advisories. Remove it so registry failures are visible and the gate actually enforces audit results.
pnpm audit is broken on pnpm 10.x because npm retired the legacy audit endpoints (410 Gone). Switch to npm audit which uses the new bulk advisory endpoint. Generates a temporary package-lock.json, runs the audit, then cleans up. Add comment explaining the workaround for future maintainers.
pnpm audit is broken on pnpm 10.x — npm retired the legacy audit endpoints (410 Gone). Replace the fragile npm audit workaround with OSV-Scanner, a standalone vulnerability scanner that reads pnpm-lock.yaml natively and aggregates 30+ advisory sources. - Remove npm audit workaround from ci.yml quality job - Add .github/workflows/osv-scanner.yml with two jobs: - scan-pr: incremental PR scan (blocks on new vulns) - scan-scheduled: full scan on push/schedule (advisory only) - Pin reusable workflows to SHA 9a49870 (v2.3.8, verified) - Add osv-scanner.toml with empty ignore list for future triage
The reusable workflows require actions:read, contents:read, and security-events:write but the caller didn't grant them, causing a startup failure on the first run.
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
The scan completes successfully but the JSON export exceeds GitHub's 1MB job output limit. Disable export-results since SARIF upload to Code Scanning is the primary integration, not job outputs.
The PR reusable workflow at this SHA doesn't expose export-results. The default is already false, so no input is needed.
At v2.3.8 SHA (9a49870), the PR reusable workflow lacks the export-results input — the export step runs unconditionally and dumps full scan JSON into job outputs, exceeding GitHub's 1MB limit. Track @main which has export-results support, and explicitly disable it. Pin to a specific SHA once a release ships with this input.
Contribution workflow
develop: This PR targetsdevelop, notmain.Description
This PR introduces three major pillars of work: a platform security foundation (account banning, access control, edge function infrastructure), a Pro plan waitlist (demand validation before launch), and several UX polish fixes across the app. It touches 79 files with ~4,291 additions and ~408 deletions.
Type of Change
Changes Made
Platform Security Foundation
before-signup,post-signup, andplatform-accessSupabase Edge Functions with shared ban logic (banLogic.ts,cors.ts,telegram.ts,webhookVerify.ts)accessService.js+authBan.jsutilities;AuthProvidernow evaluates platform access on every auth state change and tab visibility restoreBannedScreencomponent shown to banned users with contact infoplatform_security_foundation.sql(profilesis_bannedcolumn + RLS +platform-accessRPC),post_signup_webhook_trigger.sql(pg_net webhook for post-signup edge function)Pro Plan Waitlist
/propage: Full landing page (ProComingSoonPage.jsx) with feature showcase, animated sorting bars, email form, success/already-joined states, and waitlist counter (shown when >50 signups)ProWaitlistBannercomponent on Landing and App pages with session-scoped dismissal, source attribution (landing/app/direct), RTL support, and smart hiding for already-enrolled userswaitlistService.jswith Supabase insert, duplicate detection (23505), email normalization, localStorage caching, public count RPC, and welcome email via edge functionwaitlist-welcomesends confirmation emails via Resendwaitlisttable with RLS, unique email constraint, source attribution column,waitlist_public_count()RPCUX Polish and Fixes
sm:pt-20(80px) top padding on/appmain content — header is 56px in normal document flow, so the padding created 24px of unnecessary dead space/app(auto-detected browser language and system theme suffice for first visit; controls available in the visualizer). User avatar hidden when authenticated on non-/app pages; sign-in button remains visible everywherestyle={{ top: "56px" }}) to stop blurring the header — matches the existing PythonCodePanel behavior. AddedisMobilestate with resize listener for responsive backdropwhileHover/whileTapscale animations that caused jarring hover effects/appwhen on landing,/when on appCI/CD Security
pnpm audit(npm retired legacy audit endpoints, 410 Gone on pnpm 10.x) with Google OSV-Scanner as a standalone workflow. Two jobs: incremental PR scan (blocks on new vulns) and full scheduled scan (advisory). SARIF upload to Security > Code Scanning tab. Emptyosv-scanner.tomlfor future triage/suppressionInfrastructure and Docs
deploy-supabase-functions.ymlCI workflowDESIGN.md,PRODUCT.md,.impeccable/config for design system documentationRelated Issues
Closes #
Testing
pnpm test:run) — 1834 tests passingTest Results
Code Quality
pnpm lint) — 0 errorspnpm format:check)Performance Impact
Accessibility
Breaking Changes
Checklist
Additional Notes
before-signupandpost-signupedge functions are fail-closed for ban checks;platform-accessis fail-open on transport errors to avoid locking out users during outages.@main(not pinned to SHA) because v2.3.8 lacks theexport-resultsinput needed to prevent 1MB output overflow on large repos. Pin to a specific SHA once a release ships with that input.