Production-readiness pass: unblock Supabase, route protection, data integrity, schema hardening - #19
Draft
macaddy2 wants to merge 32 commits into
Draft
Production-readiness pass: unblock Supabase, route protection, data integrity, schema hardening#19macaddy2 wants to merge 32 commits into
macaddy2 wants to merge 32 commits into
Conversation
- .gitignore / .env.example: harden secret handling (.env*, *.pem/*.key, clearer placeholders) - index.html: add referrer-policy, X-Content-Type-Options, color-scheme, theme-color meta tags - vite.config.js: add production build config with vendor chunk splitting (react, supabase, radix) - src/lib/ai.js: move Gemini key from URL query to x-goog-api-key header so it no longer leaks into server logs / referrer chains - src/pages/Signup.jsx: bump min password length to 8 and require a letter + digit (client-side guardrail) - src/pages/Dashboard.jsx: guard LEVELS.find fallback and prevent division-by-zero / overflow when computing level progress - src/pages/Home.jsx: use stable keys for testimonial cards - src/components/Header.jsx + NotificationDropdown.jsx: add aria-labels, aria-expanded, aria-haspopup on icon buttons for keyboard/SR users - README.md: replace generic Vite template with real project overview - .nvmrc: pin Node 20 Supabase RLS policies, payment tokenization (PCI), and localStorage session handling were flagged in the audit but deferred — they require schema changes and auth refactor that should land in dedicated PRs.
Enhance security, accessibility, and build configuration
The "Submit Idea", "Create Stake", "Create Board", and "List Your Skills" buttons previously had no onClick handlers, so clicking them did nothing. DataContext already exposed submitIdea/createStake/createBoard/createTalentProfile — this commit adds the missing UI. New components: - src/components/ui/modal.jsx — reusable modal shell with backdrop, Esc-to-close, body scroll lock, aria-modal, and a Field primitive - src/components/SubmitIdeaModal.jsx — title, description, category, up to 5 impact tags with suggestions; awards SUBMIT_IDEA points - src/components/CreateStakeModal.jsx — title, description, category, risk level, target amount, expected returns, deadline with validation - src/components/CreateBoardModal.jsx — title + description; auto-creates To Do / In Progress / Done columns; jumps into the new board on success - src/components/ListSkillsModal.jsx — display name, bio, availability, hourly rate, multi-skill tagger with level; awards PROFILE_COMPLETE - src/components/AddTaskModal.jsx — title, column, due date, labels for Collaboard board view Wiring: - ConceptNexus: Submit Idea header button + empty-state CTA - VestDen: Create Stake header button + empty-state CTA (also fixed mangled JSX formatting with stray whitespace inside tags and the "risks.Earn" concat typo; guarded stake progress against overflow; disabled Stake Now on funded stakes) - Collaboard: Create Board header button + empty-state CTA, plus the per-column "+" and header "Add Task" now open AddTaskModal; Chat button now links to /messages - SkillsCanvas: List Your Skills header button + empty-state CTA All modals: form validation with inline errors, loading states, activity logging via logActivity, and consistent per-app gradient styling.
Wire up primary action buttons across all 4 sub-apps
Root cause: after supabase.auth.signInWithPassword() resolved, Login.jsx
immediately called navigate('/dashboard'). But the user state in
AuthContext is populated asynchronously by onAuthStateChange →
fetchProfile, so on Dashboard mount isAuthenticated was still false and
<Navigate to="/login" replace /> bounced the user right back.
Changes:
- Login.jsx: navigate inside a useEffect watching isAuthenticated instead
of immediately after login(). Also supports an optional location.state.from
so protected routes can round-trip back to their original destination.
- Signup.jsx: same pattern for the auto-sign-in case (no email confirmation).
- Dashboard.jsx / Analytics.jsx: show a loader while isLoading is true
instead of redirecting. Pass location.pathname as state.from so after
login the user returns to where they were going.
Fix sign-in race that bounced users back to /login
- Sidebar now overlays content on hover instead of pushing grid layout - Added Sun/Moon theme toggle in TopBar with localStorage persistence - Fixed routing so authenticated users stay in app shell - Set default dark theme in index.html to prevent flash - Updated TopBar action buttons with proper navigation links
- Remove unused lucide-react icon imports (CheckCircle, Zap, ArrowRight, Play) - Collapse copy-paste sub-app cards, float cards, how-it-works steps, and footer columns into local data arrays + map(), matching the existing <step.icon /> rendering pattern used elsewhere in the codebase https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
- Remove unused lucide-react icon imports (CheckCircle, Zap, ArrowRight, Play) - Collapse copy-paste sub-app cards, float cards, how-it-works steps, and footer columns into local data arrays + map(), matching the existing <step.icon /> rendering pattern used elsewhere in the codebase https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ Co-authored-by: Claude <[email protected]>
…n system - Complete the dark-theme ink scale (ink-300/400/500/700/900) and add translucent app-color -bg tints so semantic colors flip in dark mode, matching the prototype token system - Drive splash heading/stat/brand colors from --color-ink-900 (which now flips) and drop the hardcoded #F4F7FB dark-mode overrides - Add dark-mode topbar background (rgba navy) instead of a translucent white bar; reference --color-border for the topbar divider - Add the prototype's app-colored 3px accent bar to dashboard sub-app tiles - Remove dead components orphaned by the landing-page rebuild (Hero, HowItWorks, AppCard/AppList) https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
…n system (#5) * refactor: drive splash landing sections from data arrays - Remove unused lucide-react icon imports (CheckCircle, Zap, ArrowRight, Play) - Collapse copy-paste sub-app cards, float cards, how-it-works steps, and footer columns into local data arrays + map(), matching the existing <step.icon /> rendering pattern used elsewhere in the codebase https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ * fix: align dark-theme tokens and dashboard tiles with prototype design system - Complete the dark-theme ink scale (ink-300/400/500/700/900) and add translucent app-color -bg tints so semantic colors flip in dark mode, matching the prototype token system - Drive splash heading/stat/brand colors from --color-ink-900 (which now flips) and drop the hardcoded #F4F7FB dark-mode overrides - Add dark-mode topbar background (rgba navy) instead of a translucent white bar; reference --color-border for the topbar divider - Add the prototype's app-colored 3px accent bar to dashboard sub-app tiles - Remove dead components orphaned by the landing-page rebuild (Hero, HowItWorks, AppCard/AppList) https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ --------- Co-authored-by: Claude <[email protected]>
Full re-audit of the design handoff (Design System + Prototype + Showcase) against the live app; this applies the verified top gaps: - Brand: replace the improvised lucide Hexagon on the splash nav/footer with the real Fixars gear+F mark assets already shipped in /public - Iconography: enforce the design system's 1.75px outline stroke globally for lucide icons; drop now-inert per-icon strokeWidth overrides - Page-head grammar: add the prototype's page-head/eyebrow/icon/tag/title/sub CSS and a shared PageHead component; adopt it on all four sub-app pages with the prototype's app glyphs, taglines, and missions - Wallet: add the prototype's radial gradient blob to both wallet hero cards - Numerals: tabular figures on the .mono utility per the number-dense design principles https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
…doff
Phase 1 (foundation) of the v2 super-app redesign:
- Retune brand to deeper indigo (#2F45E0): primary/blue ramp/ring, plus
decorative glow literals, replacing the electric blue. Logo mark nudged
to match via a calibrated CSS filter (hue-rotate + desaturate) in the
sidebar, mobile header, and splash nav.
- Align semantic tokens to the v2 spec (success #16A34A, warning #D97706,
danger bg) in both light and dark, with matching dark-mode tint alphas.
- Add the sepia ("dim") theme and density/vibe token blocks (compact/cozy/
spacious, focused/expressive/playful).
- Add ThemeContext as the single source of truth for theme/density/vibe,
applied as data-* attributes on <html> and persisted; default is
light · cozy · expressive. TopBar now consumes it.
- Vendor the approved v2 design handoff under design-handoff/fixars-v2 as
the reference for subsequent phases.
https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
- Add time-aware greeting eyebrow (page-tag) and refine the home head to the v2 grammar. - Add a 4-stat strip (FCS, Fixars points, active stakes, verified skills) with inline SVG sparklines pinned bottom-right, driven by live data. - Port the shared v2 grammar to phase2.css: .stats-strip/.stat-card/.spark, the reusable .tag status-pill family, and .page-eyebrow/.page-tag — the expressive-vibe gradient bar now rides the stat cards by default. - Drop two dead payment imports from Dashboard. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Command palette (SearchContext + SearchOverlay): - Add a global ⌘K / Ctrl+K listener in SearchProvider (works app-wide), removing the duplicate listener that only lived in the public Header. - Add a "Go to" pages group so the palette navigates routes; the empty query now lists all destinations instead of a hint. - Full keyboard support: ↑↓ moves a highlighted selection, Enter opens (navigate or open the item), Esc closes; results capped at 9 and grouped (Go to / Ideas / Campaigns / Projects / Talent) with a key-hint footer. - Expose a clean open/close/toggle API (plus a setIsSearchOpen alias) and fix the app-shell search box, which previously called a missing setter. Notifications: - Wire the existing NotificationDropdown popover into the app TopBar bell (unread badge, mark-all-read, type glyphs) in place of the page link. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Adopt the v2 wallet model so staking spends a real, shared balance: - Add WalletContext: a single ₦ balance + transaction ledger persisted to localStorage, with a validated `spend`/`deposit` primitive and a navy toast (`notify`). Wired into the provider tree; <WalletToast/> renders the bottom-center pill. - Add StakeFlowModal (the v2 "key flow"): backs a campaign from the wallet with an IRR/return banner, amount input + quick-amount chips, wallet source showing the live balance, a live projected-return range, and validation against the balance. Confirm deducts the wallet, increments the campaign (funded/backers via makeStake), toasts, and closes. - VestDen now opens StakeFlowModal instead of the card PaymentModal; the modal is mounted only while active so it starts from fresh state. - Wire the shared balance through WalletPage (balance + live ledger ahead of seeded history) and the Home "Wallet" stat card. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Bring all four sub-apps to v2 fidelity with a shared kit: - Add SubAppKit (StatRow, Toolbar with search + segmented filter, ListGrid, EmptyState) and port the v2 grammar to phase2.css: .toolbar/.segment, .list-grid/.list-card (+title/desc/meta/progress), .av/.team-av, .skill-chip, .btn-app-*, .btn-ghost, .empty. - ConceptNexus: idea list-cards (status tag + score + validation bar + reviewers) with live search and All/Submitted/In Validation/Validated segment; AI recommendations retained. - vestDen: campaign list-cards (funding tag, days left, funded progress, target return, backers) with All/Funding now/Closing soon/Funded/My Portfolio filters that drive both the list and the stat strip. - SkillsCanvas: talent list-cards (gradient avatar, verified tag, skill chips, rate · rating, projects) with availability filters. - CollaBoard: project list-cards (derived status tag, task counts, team avatars) with All/My Boards/Active/In review/Done; kanban detail view preserved. Each page now uses the shared PageHead + 4-stat strip + toolbar + 2-col list grid with live filtering and a Clear-filters empty state. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Reconcile the Settings pickers to the real v2 theming axes and make them live: theme (light/dim·sepia/dark), density (compact/cozy/spacious), and vibe (focused/expressive/playful) now read from and write to ThemeContext, applied as data-* attributes on <html> and persisted. Drops the dead local state and the unused-user lint error. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Phase 4 refinements: - Currency: switch the remaining $/USD displays to ₦ — Analytics total staked, BookingModal and CollaBoard Skill-Summoner rates, and the CreateStake/ListSkills amount labels + validation messages. - FCS: reconcile the Profile gauge to the v2 300–850 scale, driven by the user's stored fcs, with banded labels (Excellent/Very good/Good/Fair/ Building) and a matching ring color; range now reads 300 — 850. - Accessibility: add a global prefers-reduced-motion guard that disables entrance/looping animations and long transitions, per the handoff. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
- ui/Modal now renders as a bottom-sheet on mobile (full-width, anchored to the bottom edge, rounded top corners, slide-up) and a centered card on sm+, with the v2 slim 3px app-accent bar and scroll-contained body (max-h + overflow) so long forms fit. This brings SubmitIdea, CreateBoard, CreateStake, ListSkills and AddTask to v2 modal chrome. - Remove PaymentModal — dead since vestDen moved to the wallet-based StakeFlowModal. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
# Conflicts: # src/index.css # src/pages/Home.jsx
Redesign Fixars to the v2 super-app design system
Comprehensive pre-launch audit of the production codebase against the Fixars Comprehensive PRD and the four sub-app PRDs. Flags the P0 blockers (mock backend/auth, simulated money + escrow, missing KYC, non-existent DMs, regulatory/NDPR gaps), trust/brand inconsistencies (Western seed names, naming/logo conflicts, currency leftovers, FCS-vs-reputation scale), feature gaps vs the v2 vision, and a recommended phased launch path. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
…chines) Visual-first model of how the four sub-apps connect, pre-AI: the innovation journey, the event pub/sub webbing (publisher -> event -> subscribers), and the per-entity state machines (Concept/Campaign/Milestone/Engagement) with deterministic guards. Includes the rules-table preview that the engine layer will implement. Diagrams authored in Mermaid so they render on GitHub. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
The runnable form of the ecosystem webbing diagrams — connects the four sub-apps via state machines + an event bus + a rules table. - events.js: event catalog + payload schemas + tunables (threshold, fee) - guards.js: pure, deterministic predicates (KYC, score, verified) - stateMachines.js: Concept/Campaign/Milestone/Engagement lifecycles (View 3) - effects.js: the THEN actions + an in-memory reference store - rules.js: the algorithm — WHEN event -> IF guard -> THEN effects (View 2) - engine.js: dispatcher with idempotency, compensation/sagas, bounded cascades - index.js: public entry point - demo.mjs: runnable end-to-end journey (24 assertions, exits non-zero on fail) - README.md: architecture + how it maps to the diagrams + where AI plugs in Backend-agnostic: swap the in-memory store/effects for Supabase/Paystack/ escrow without changing event names, machines, or rule structure. All code thoroughly commented. `node src/engine/demo.mjs` passes 24/24. https://claude.ai/code/session_018zosF6Byo1ieTvvk2EEvAZ
Ecosystem engine + launch-readiness review + visual webbing
…data integrity, schema hardening Blockers: - Enable Supabase when env vars are set (flag was hardcoded false); lazy client creation, no more placeholder URL - RequireAuth wrapper on all private routes; signed-in users redirected away from /login and /signup - Fix talent creation (missing userId arg), persist updateTalentProfile, map DB rows to the camelCase shape everywhere - Fix boards query for members-less users (invalid id.in.() filter) and check all insert errors - BookingModal now actually creates a skill_request via createBookingRequest Data unification: - Single talent store (DataContext); useTalents/useTalent read from it; TalentProfile/useReviews moved to camelCase - Persist comments (new post_comments table + trigger), follows (new table), activities, and notification deletes - Pass vote comment/badge through to idea_votes; task completion detected by target column title instead of UUID comparison Reliability: - Reference-counted realtime channels; debounced reconciliation refetches - AuthContext: safe localStorage parse, single profile fetch via INITIAL_SESSION, updateUser only sends defined columns - WalletContext: ref-mirror balance so concurrent spends can't overdraft - Collaboard: derived board selection (no setState in render/effects) Schema hardening (supabase/schema.sql, idempotent): - notifications insert restricted to self; profiles rows hidden from anon - post_comments, follows, payments tables + RLS; comment_count trigger - create_dm_conversation upserts on a deterministic dm_key (unique index) so concurrent DM creation can't duplicate conversations Hygiene: - Currency unified to Naira; payments.js no longer sends raw card data - api.js checks res.ok, clamps limits, docs match schema - Dead buttons/links wired: mobile bell, mobile create, post share, forgot-password, landing CTAs/footer; dead kanban kebab removed - Analytics sparklines memoized (no random-per-render); lazy useState initializers for impure mock data - Add vitest + 18 unit tests (utils + engine cascade/idempotency)
macaddy2
marked this pull request as draft
August 22, 2026 18:03
…l/screenshot policy Server-side money rails (#2): - schema RPCs: award_points/spend_points (amounts resolved server-side), make_stake (validates state + refuses over-funding), wallet_balance, wallet_spend; wallet_transactions ledger (derived balance, no client writes) - PointsContext/WalletContext switch to RPCs; stake flow persists BEFORE wallet debit (failed stakes never charge the wallet) - Paystack Edge Functions: create-payment (hosted checkout, PCI stays with Paystack), verify-payment (verify + credit wallet); payments.js rewritten around them; WalletPage Fund button runs checkout + verifies on return Engine activation (#3): - src/engine/runtime.js bridges app -> @/engine: concept lifecycle cascades (validated -> campaign draft -> points/feed/notify), funded campaigns -> room+escrow mirrors; fail-soft everywhere; DB stays source of truth - wired into DataContext submitIdea/voteIdea/makeStake; 4 new runtime tests Hardening (#4): - Gemini behind gemini-proxy Edge Function (key out of the browser bundle) - ui/modal.jsx rebuilt on Radix Dialog (focus trap/restore); star ratings get radiogroup semantics - Kanban drag-and-drop between columns wired to moveTask - CI workflow (.github/workflows/ci.yml): lint + test + build - eslint: ignore design-handoff/functions, add eslint-plugin-react jsx-uses-vars (fixes false 'unused' for JSX components), lint is fully green Crawl policy (#5): landing page only indexable - robots.txt allow /\$ + AI-bot blocks, default noindex meta flipped to index,follow only on Home, X-Robots-Tag header for every other route via serve.json Screenshot deterrence (#6): ScreenShield blanks UI on blur/hide, PrintScreen clipboard wipe, print CSS lockdown (no watermarks) Also: derived wallet stats replace hardcoded numbers; ActivityHeatmap uses seeded pseudo-random (render purity)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the production-readiness recommendations (excluding server-side money rails and engine wiring, per scope decision).
Blockers fixed
isSupabaseConfigured()returned hardcodedfalse. Now checks env vars; client is created lazily (no placeholder URL).RequireAuthwrapper guards all private routes (/dashboard,/wallet,/apps/*, etc.); signed-in users are redirected away from/login//signup`.userId; rows now map to the camelCase shape;updateTalentProfileactually persists.id.in.()PostgREST filter when membership list is empty.createBookingRequestso talents actually receive requests.Data unification
useTalents/useTalentread from DataContext (newly listed skills no longer 404 in TalentProfile).post_commentstable (+comment_counttrigger), follows via a newfollowstable, activities via the existingactivitiestable; notification deletes persist.idea_votes; task completion is detected by target column title (UUID-vs-'done' comparison never matched).Reliability
INITIAL_SESSION,updateUsersends only defined columns.Schema hardening (idempotent, re-runnable)
notifications_insertrestricted to self (no cross-user notification spoofing); profiles hidden from anon clients; emails no longer selected anywhere.post_comments,follows,payments(service-role-write-only ledger for future payment rails).create_dm_conversationupserts on a deterministicdm_keyunique index — simultaneous first messages converge on one conversation.Hygiene
formatCurrency-> NGN); payments.js never transmits raw card data.api.jschecksres.ok, clamps limits, docs aligned with actual schema.Tests
src/lib/utils.test.jsandsrc/engine/engine.test.js(full concept->validated cascade incl. guards, idempotency, audit log).npm testpasses,npm run buildclean.Test plan
npm test— 18/18 passingnpm run build— clean production buildnpm run lint— all changed files clean (remaining repo-wide errors are pre-existing in untouched files / design-handoff)supabase/schema.sql, verify signup -> list skills -> book talent end-to-end