Code Review, Architecture Analysis & PRD Assessment
A hidden element labeled "NVISION" triggers handleDevExport on click. This function:
api-platform.sticklight.com using credentials: 'include'This is a Sticklight platform dev utility left in production code. The credentials: 'include' flag transmits authentication cookies to a third-party domain — a cross-site credential exposure risk.
Remove handleDevExport and the hidden NVISION button entirely. ✓ Fixed — removed in deployment commit.
The component calls useReducedMotion(), then conditionally returns JSX early, and only after that calls useEffect and useCallback. React requires all hooks to be called unconditionally in the same order on every render.
Move the reduced-motion guard inside the useEffect/animation logic, or restructure so all hooks run unconditionally.
The form's handleSubmit calls setSent(true) and resets after 4 seconds. A comment reads: "In production, hook up to a real API". The form collects name, phone, email, company, and message — and silently discards all of it. Users see a success confirmation but their message is never delivered.
Connect to a real backend: Resend, SendGrid, Formspree, or a Cloudflare Worker that emails submissions.
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768; const NODE_COUNT = isMobile ? 30 : 60; const CONN_DIST = isMobile ? 120 : 160;
These values are computed once at module evaluation time, not inside any React hook. They never update on resize or orientation change.
Compute inside a useState/useEffect + resize listener, or use a media query hook.
Four legacy service pages use office@plan-b.systems via window.open(). All other contact surfaces (Footer, CTASection, ContactPage) use info@plan-b.co.il. Messages sent to the wrong address may be permanently lost.
Align all CTA links to one authoritative address. Replace window.open('mailto:...') with <a href="mailto:...">.
Both components define SVG <defs> with hardcoded IDs. SVG id attributes must be document-unique. PlanBLogo.tsx already solves this with a per-instance uid via useRef.
Generate unique suffix per instance using useRef(() => Math.random().toString(36).slice(2)).
Runs an unbounded requestAnimationFrame loop with no prefers-reduced-motion check. Other components (NeuralCanvas, SVGOrbitSystem) respect this. The global MotionConfig only covers Framer Motion, not raw rAF loops.
Reads window.scrollY 60 times/second even when idle. A passive scroll event listener has zero cost at rest.
Uses role="status" with randomly generated values presented as real-time AI system metrics. Screen readers announce meaningless numbers as genuine data. Violates WCAG 3.3.2.
Uses role="menu" and role="menuitem" — these are for application context menus, not site navigation. Requires arrow-key/Home/End/type-ahead keyboard behavior that isn't implemented.
theme.css declares --font-sans: 'Heebo', 'Inter', system-ui but index.html has no font link. Typography silently falls back to system-ui on every platform.
Six legacy pages use direct Navbar import, bg-slate-950 background, cyan/blue accents, and inline footers — completely different from the modern pages' design system.
14 explicit routes, no <Route path="*"> fallback. Invalid URLs render a blank white page.
Canvas dimensions set once at mount. No resize listener. Device rotation or browser resize leaves canvas clipped.
Math.random() called inside whileInView produces different bar heights on every render/re-mount.
Fully implemented but not imported anywhere. PageLayout.tsx handles transitions directly.
Defined but never imported. TrustBar.tsx and NumbersStrip.tsx duplicate the same counter animation logic.
Uses mr-[0.3em] instead of logical me-[0.3em]. In RTL, margin-right adds space on the wrong side.
Only <title> and basic description. No Open Graph, Twitter Card, canonical link, or JSON-LD schema.
TrustBar respects reduced motion; LogoCloud (near-identical marquee) hardcodes repeat: Infinity.
Decorative background numbers positioned with physical left-8 instead of logical start-8.
Same tracking ID ev_050b10447f on two different elements. Sticklight analytics events will be misattributed.
The Plan B website was built on Sticklight (a Lovable-like AI code generation platform) using React 18 + Vite 6 + Tailwind CSS v4 + Framer Motion. The demo impressed the client, but the production code has structural problems.
| Metric | Value | Assessment |
|---|---|---|
| JS Bundle | 614 KB | Too large — 10x what's needed for static pages |
| Components | 60+ | Many duplicates (4 service components doing the same thing) |
| Issues Found | 22 | Including 1 critical security backdoor |
| SSR/SSG | None | Client-side only — blank page until 614KB JS loads |
| Code Splitting | None | All 14 pages bundled together |
| Contact Form | Fake | Silently discards submissions |
| Design Systems | Two | 6 legacy pages on completely different visual system |
| Build Config | Missing | No package.json, tsconfig, or vite.config shipped |
Sticklight is good for demos — which is exactly how it was used. But the output is:
{"path":"...","content":"..."} JSON, not actual source codedata-ev-id tracking attributes on every element, Sticklight API backdoor in Footer| Aspect | Current (Sticklight) | Recommended (Astro) |
|---|---|---|
| Components | 60+ generated | ~15 intentional |
| Bundle per page | 614KB everywhere | 0-50KB (JS only where needed) |
| SEO | Client-side, Google sees blank | Pre-rendered HTML, fully indexable |
| Content editing | Edit TSX files | Edit Markdown/MDX files |
| Contact form | Fake | Working from day 1 |
| Time to first paint | ~2-3 seconds | ~0.3 seconds |
| Footer change | Touch 6+ files | Touch 1 file |
Astro ships zero JavaScript by default. The animated hero and contact form become React "islands" — only those components load JS. Static pages (services, about, privacy) are pure HTML/CSS with zero runtime cost.
The demo served its purpose — the client said yes. Now the site needs to be rebuilt properly for production. The current React SPA approach is the wrong architecture for a marketing site, but adding lazy loading and fixing the 22 issues would make it acceptable. For the v2.0 SaaS platform (see PRD analysis), the architecture needs to be fundamentally different.
The PRD describes a completely different product from the current demo site. It's no longer a brochure — it's a full SaaS platform with multi-tenant customer portal, license management, billing, and AI agents.
The PRD is surprisingly well-architected for a non-developer-written document. The multi-tenant RLS approach, licensing handshake, and API versioning are industry-standard patterns done right. But there are gaps and risks.
Shared database with RLS is exactly the right call. Per-tenant databases are a maintenance nightmare. The schema design (Organizations → Profiles → Licenses) is clean. The RLS policy example is correct:
CREATE POLICY tenant_isolation_policy ON licenses
USING (org_id = auth.jwt() ->> 'org_id');
This means even if the frontend code has bugs, the database itself blocks cross-tenant data access. This is the Supabase/AWS standard approach.
The SIEM validation flow (POST to /v1/validate with license_key + machine_id → signed JWT valid for 24h) is well-designed. The 72-hour offline grace period is a good practical decision — it prevents customer disruption from temporary network issues while still enforcing license compliance.
All licensing API under /v1/ from day one. This means v2 can coexist without breaking deployed SIEM systems. The specific error codes (ERR_EXPIRED, ERR_QUOTA_EXCEEDED) are also correct — much better than generic 401/403.
The PRD explicitly states the frontend never touches the DB directly (only through Supabase Client with RLS). This is the right security posture for a multi-tenant platform.
The PRD mixes three different products into one:
These should be separate deployments:
| What | Tech | URL |
|---|---|---|
| Marketing site | Astro (static) | plan-b.systems |
| Customer portal | Next.js (SSR) | app.plan-b.systems |
| API | Edge Functions | api.plan-b.systems |
Mixing a marketing site with a SaaS dashboard in the same app creates conflicting performance requirements. The marketing site needs to be fast and SEO-friendly. The dashboard needs real-time data and authenticated routes.
The PRD suggests "Astro 5.0 or Next.js". For the marketing site, Astro is better. For the SaaS portal, Next.js is the clear winner:
Astro is wrong for the portal — it's designed for content sites, not authenticated multi-tenant dashboards.
The PRD says the bot should perform "Function Calling" like "generate a new license key". This is extremely dangerous without guardrails:
The PRD says: "When I'm at a client, I don't need presentations, the site IS the presentation." This means the marketing site needs to be spectacular — heavy animations, Three.js, premium feel. But the customer portal needs to be functional — fast, clear, data-dense.
These are opposing requirements. The marketing site should wow; the portal should work. Trying to make the portal "impressive" usually makes it slow and confusing. Separate the two.
The PRD correctly marks usage-based billing as uncertain. For an early-stage SaaS, start with fixed-tier pricing (Basic/Pro/Enterprise already defined in the schema). Add usage-based billing later when you have enough customers to justify the engineering cost. Stripe metered billing works but adds significant complexity in tracking, threshold alerts, and edge cases (what happens when a customer disputes usage data?).
The PRD mentions Vercel hosting but doesn't address:
/v1/validate endpoint will be hammered by SIEM systems every 24hThe current site says "cybersecurity/SIEM" but Plan B does AI integration, bots, agents, Claude Code courses, Monday automation, enterprise integration. The PRD doesn't address the content gap — whoever builds v2 needs a content brief, not just a tech spec.
| Layer | Technology | Why |
|---|---|---|
| Marketing site | Astro 5 + React islands | Fast, SEO-friendly, animations where needed |
| Customer portal | Next.js 15 (App Router) | SSR, auth middleware, API routes, real-time dashboard |
| Database | Supabase (PostgreSQL + RLS) | As specified — correct choice |
| Auth | Clerk (with Organizations) | Multi-tenant auth out of the box, better than Supabase Auth for this use case |
| API | Next.js API Routes + Edge | License validation needs low latency globally |
| AI Agent | Claude API + pgvector RAG | Function calling with strict role-based authorization |
| Billing | Stripe (fixed tiers first) | Start simple, add metered billing in v2.1 |
| Hosting | Vercel (portal) + CF Pages (marketing) | Best-in-class for each use case |
This is a solid foundation written by someone who understands enterprise software. The multi-tenant architecture, licensing handshake, and API design are correct. The main risk is scope — this is 3 products (marketing site + SaaS portal + API service) described as one. Separate them architecturally, start with the marketing site + licensing API, and add the customer portal as phase 2.
The biggest gap: the AI agent needs a security design document before implementation. Function calling that creates licenses and sends invoices requires explicit authorization flows, audit logging, and rate limiting — none of which are specified.
הקמת פלטפורמת SaaS מרכזית עבור Plan-b.systems שתשמש כחלון הראווה של החברה, מרכז ניהול לקוחות מרובי דיירים (Multi-tenant), ומנגנון הנפקת רישיונות עבור מערכות ה-SIEM וה-AI של החברה.
הערה למפתח: סעיפים 3.1 ו-3.2 נתונים לשיקול דעתך המקצועי, בתנאי שיעמדו בדרישות הביצועים וה-UX המפורטות.
אפשרויות מומלצות: Astro 5.0 או Next.js.
דרישת סף: תמיכה מלאה ב-Server Side Rendering וביצועי Lighthouse (Performance) מעל לציון 90.
אפשרויות מומלצות: Tailwind CSS בשילוב Shadcn UI או ספריה דומה.
דרישת סף: מימוש שפת עיצוב פרימיום (Dark Mode, Glassmorphism), תמיכה ב-RTL מלא ואנימציות חלקות.
בסיס נתונים: Supabase (PostgreSQL).
אבטחה: חובת שימוש ב-Row Level Security (RLS) למניעת זליגת מידע בין לקוחות שונים.
אירוח (Hosting): Vercel. (אופציה!)
אימות משתמשים: Supabase Auth או Clerk.
בידוד נתונים: ארכיטקטורה קשיחה שבה לקוח רואה אך ורק את הישויות (מפתחות, חשבוניות, לוגים) המשויכות לארגון שלו בלבד.
ניהול הרשאות: הפרדה בין מנהל לקוח (Admin) לבין משתמש קצה בארגון. אפשרות לתת גישה לקריאה בלבד ולתת גישה לבודקים שונים מטעם הלקוח.
ניהול רישיונות: הנפקת מפתחות API וניהול תוקף המנוי.
ממשק אימות (Validation Endpoint): חשיפת API מאובטח שישמש את מערכת ה-SIEM החיצונית לאימות הרישוי בזמן אמת.
תשלומים מתחדשים: חיוב חודשי מתחדש מבוסס שימוש או מנוי קבוע.
אינטגרציה: חיבור לספק תשלומים (כגון Stripe או ספק מקומי) דרך Webhooks. (נושא פתוח לדיון, גם ספק סליקה כגון טרנזילה יכול לעבוד.)
צ'אט חכם: שילוב בוט AI המחובר לנתוני הלקוח ומאפשר שאילתות על סטטוס הרישוי, השירותים וניתוח נתונים בסיסי. תשובות הבוט רק על המידע של אותו לקוח (מולטי טננט AI).
תנועה וגרפיקה: האתר חייב לכלול אלמנטים גרפיים מודרניים המשרים תחושת הייטק יוקרתית.
תגובתיות: פידבק ויזואלי מהיר לכל פעולת משתמש (לחיצה, טעינה, הצלחת פעולה).
אנחנו לא נפתח בסיס נתונים נפרד לכל לקוח (יקר ומסובך לתחזוקה), אלא נשתמש ב-Shared Database, Separate Schema/Row Isolation.
Table: Organizations (Tenants)
Table: Profiles (Users)
Table: Licenses (The SIEM Keys)
המתכנת חייב להגדיר ב-Postgres מדיניות שאומרת:
CREATE POLICY tenant_isolation_policy ON licenses USING (org_id = auth.jwt() ->> 'org_id');
זה מבטיח שגם אם יש באג בקוד ה-Frontend, ה-DB עצמו יחסום ניסיון של משתמש לראות רישיון שלא שייך ל-org_id שלו.
כאן אנחנו מגדירים איך ה-SIEM (שמותקן אצל הלקוח או בענן) מוודא שהוא רשאי לעבוד.
api.plan-b.systems/v1/validate.המנגנון יתבסס על Asymmetric Key Validation או Signed JWTs.
לא בטוח שנלך על זה.
במערכת SIEM, המחיר בדרך כלל נגזר מנפח דאטה.
ניתן לביצוע? כן. הוכח במערכות כמו Datadog ו-Sentry.
הבוט צריך להיות Context-Aware:
מגבלה: הבוט לא "לומד" לבד בזמן אמת, הוא משתמש רק במידע שסיפקנו לו ב-Prompt.
האתר הנוכחי יכול לשרת כאתר שיווקי זמני — אחרי תיקון 22 הבאגים. אבל הוא לא יכול להיות הבסיס לפלטפורמת SaaS כפי שה-PRD מתאר. אלה שני מוצרים שונים לחלוטין.
הבעלים רוצה שלושה דברים במקביל:
אתר עם אנימציות פרימיום, Three.js, תחושת הייטק — שאפשר לפתוח אצל לקוח במקום מצגת PowerPoint. זה מה שיש היום (בערך), ועם תיקונים זה יכול לעבוד.
מערכת שבה כל לקוח נכנס לאזור שלו, רואה את הרישיונות שלו, מנהל את המנויים שלו, מדבר עם בוט AI שמכיר אותו. זה לא אתר — זה מוצר תוכנה.
Endpoint שמערכות ה-SIEM של הלקוחות פונות אליו כל 24 שעות כדי לוודא שהרישיון עדיין תקף. זה שירות Backend טהור — אין לו שום קשר לעיצוב האתר.
| שאלה | תשובה |
|---|---|
| האם האתר הנוכחי יכול לשמש כאתר שיווקי? | כן — אחרי תיקון הבאגים, הסרת הBackdoor (כבר נעשה), חיבור טופס יצירת קשר אמיתי, ותיקוני SEO. |
| האם האתר הנוכחי יכול לשמש כפורטל לקוחות? | לא — אין בו שום תשתית ל-Auth, Multi-tenant, DB, או API. זה אתר סטטי עם אנימציות. |
| האם צריך לזרוק הכל ולבנות מחדש? | לא בהכרח — אפשר להשאיר את האתר השיווקי ולבנות את הפורטל בנפרד. |
תיקון האתר הנוכחי — הוא ישמש כאתר שיווקי זמני:
תוצאה: אתר שיווקי עובד שאפשר להראות ללקוחות.
בניית אתר שיווקי חדש ב-Astro — יחליף את האתר הנוכחי:
זה מתיישב לגמרי עם ה-PRD — ה-PRD אומר "Astro 5.0 או Next.js" וזה בדיוק מה שמוצע.
בניית פורטל לקוחות ב-Next.js על app.plan-b.systems:
ה-PRD הוא מסמך מצוין. הארכיטקטורה (Multi-tenant, RLS, Licensing Handshake) — הכל נכון. מה שצריך לשנות זה לא את מה לבנות, אלא את איך לבנות:
/v1/validate כל 24 שעות. ב-100 לקוחות זה 100 בקשות ביום. ב-10,000 לקוחות — צריך CDN/Edge.| אפשרות | מה זה אומר | המלצה |
|---|---|---|
| א. להישאר עם מה שיש | לתקן 22 באגים, לחבר טופס, להוסיף SEO | טוב לטווח קצר (1-2 חודשים). לא פתרון קבוע. |
| ב. Astro + Next.js (ההצעה שלי) | אתר שיווקי חדש + פורטל לקוחות נפרד | המלצה. מתיישב עם ה-PRD ומפריד נכון בין שיווק ל-SaaS. |
| ג. ללכת לפי ה-PRD כמות שהוא | לבנות הכל כפרויקט אחד | מסוכן. ניסיון לשים שיווק + SaaS + API באותו פרויקט ייצור מפלצת. |
ה-PRD הוא בסיס מצוין. הקונספט נכון — Plan B צריך יותר מאתר שיווקי. הוא צריך פורטל לקוחות, ניהול רישיונות, ובוט AI. אבל צריך לבנות את זה כשלושה מוצרים נפרדים, לא כפרויקט אחד מונוליטי.
התוכנית המומלצת: עכשיו — לתקן את האתר הנוכחי כך שיעבוד. במקביל — להתחיל לבנות אתר שיווקי ב-Astro. אחר כך — פורטל לקוחות ב-Next.js. ה-PRD מנחה את הכיוון, אנחנו רק מפרידים את הביצוע לשלבים הגיוניים.