From 8b16eba1ade0fdc63c9f700f83ea20e20086b4d2 Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Thu, 19 Feb 2026 10:35:26 +0100 Subject: [PATCH] chore: remove completed feature specs and apply dx fmt Remove CAI-1 and CAI-2 feature files that have been implemented. Apply dx fmt formatting to landing and privacy pages. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 4 - features/CAI-1.md | 9 -- features/CAI-2.md | 3 - src/pages/landing.rs | 197 +++++++++++++++++++++++++++++++------------ src/pages/privacy.rs | 8 +- 5 files changed, 145 insertions(+), 76 deletions(-) delete mode 100644 features/CAI-1.md delete mode 100644 features/CAI-2.md diff --git a/CLAUDE.md b/CLAUDE.md index c0a8dca..311505e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -237,10 +237,6 @@ The SaaS application dashboard is the landing page for the company admin to view This project is written in dioxus with fullstack and router features. MongoDB is used as a database for maintaining user state. Keycloak is used as identity provider for user management. - ## Features management - - All features are detailed and described under the features folder in clear markdown instructions which are valid for both human and AI code developers. - ## Code structure The following folder structure is maintained for separation of concerns: - src/components/*.rs : All components that are required to be rendered are placed here. These are frontend only, reusable components that are specific for the application. diff --git a/features/CAI-1.md b/features/CAI-1.md deleted file mode 100644 index ebf6606..0000000 --- a/features/CAI-1.md +++ /dev/null @@ -1,9 +0,0 @@ -# CAI-1 - -This feature creates a new login/registration page for the GenAI admin dashboard. The user management is provided by Keycloak, which also serves the login/registration flow. The dioxus app should detect if a user is already logged-in or not, and if not, redirect the user to the keycloak landing page and after successful login, capture the user's access token in a state and save a session state. - -Steps to follow: -- Create a docker-compose file for hosting a local keycloak and create a realm for testing and a client for Oauth. -- Setup the environment variables using .env. Fill the environment with keycloak URL, realm, client ID and secret. -- Create a user state in Dioxus which manages the session and the access token. Add other user identifying information like email address to the state. -- Modify dioxus to check the state and load the correct URL based on the state. diff --git a/features/CAI-2.md b/features/CAI-2.md deleted file mode 100644 index 1b9d119..0000000 --- a/features/CAI-2.md +++ /dev/null @@ -1,3 +0,0 @@ -# CERTifAI 2 - -This feature defines the types for database as well as the API between the dashboard backend and frontend. diff --git a/src/pages/landing.rs b/src/pages/landing.rs index b6c6c6a..d6cbd34 100644 --- a/src/pages/landing.rs +++ b/src/pages/landing.rs @@ -46,12 +46,16 @@ fn LandingNav() -> Element { } div { class: "landing-nav-actions", Link { - to: Route::Login { redirect_url: "/dashboard".into() }, + to: Route::Login { + redirect_url: "/dashboard".into(), + }, class: "btn btn-ghost btn-sm", "Log In" } Link { - to: Route::Login { redirect_url: "/dashboard".into() }, + to: Route::Login { + redirect_url: "/dashboard".into(), + }, class: "btn btn-primary btn-sm", "Get Started" } @@ -67,9 +71,7 @@ fn HeroSection() -> Element { rsx! { section { class: "hero-section", div { class: "hero-content", - div { class: "hero-badge badge badge-outline", - "Privacy-First GenAI Infrastructure" - } + div { class: "hero-badge badge badge-outline", "Privacy-First GenAI Infrastructure" } h1 { class: "hero-title", "Your AI. Your Data." br {} @@ -82,16 +84,14 @@ fn HeroSection() -> Element { } div { class: "hero-actions", Link { - to: Route::Login { redirect_url: "/dashboard".into() }, + to: Route::Login { + redirect_url: "/dashboard".into(), + }, class: "btn btn-primary btn-lg", "Get Started" Icon { icon: BsArrowRight, width: 18, height: 18 } } - a { - href: "#features", - class: "btn btn-outline btn-lg", - "Learn More" - } + a { href: "#features", class: "btn btn-outline btn-lg", "Learn More" } } } div { class: "hero-graphic", @@ -105,27 +105,44 @@ fn HeroSection() -> Element { defs { linearGradient { id: "grad1", - x1: "0%", y1: "0%", - x2: "100%", y2: "100%", + x1: "0%", + y1: "0%", + x2: "100%", + y2: "100%", stop { offset: "0%", stop_color: "#91a4d2" } stop { offset: "100%", stop_color: "#6d85c6" } } linearGradient { id: "grad2", - x1: "0%", y1: "100%", - x2: "100%", y2: "0%", + x1: "0%", + y1: "100%", + x2: "100%", + y2: "0%", stop { offset: "0%", stop_color: "#f97066" } stop { offset: "100%", stop_color: "#f9a066" } } radialGradient { id: "glow", - cx: "50%", cy: "50%", r: "50%", - stop { offset: "0%", stop_color: "rgba(145,164,210,0.3)" } - stop { offset: "100%", stop_color: "rgba(145,164,210,0)" } + cx: "50%", + cy: "50%", + r: "50%", + stop { + offset: "0%", + stop_color: "rgba(145,164,210,0.3)", + } + stop { + offset: "100%", + stop_color: "rgba(145,164,210,0)", + } } } // Background glow - circle { cx: "200", cy: "200", r: "180", fill: "url(#glow)" } + circle { + cx: "200", + cy: "200", + r: "180", + fill: "url(#glow)", + } // Shield outline path { d: "M200 40 L340 110 L340 230 C340 300 270 360 200 380 \ @@ -145,36 +162,98 @@ fn HeroSection() -> Element { opacity: "0.8", } // Network nodes - circle { cx: "200", cy: "180", r: "8", fill: "url(#grad1)" } - circle { cx: "150", cy: "230", r: "6", fill: "url(#grad2)" } - circle { cx: "250", cy: "230", r: "6", fill: "url(#grad2)" } - circle { cx: "200", cy: "280", r: "6", fill: "url(#grad1)" } - circle { cx: "130", cy: "170", r: "4", fill: "#91a4d2", opacity: "0.6" } - circle { cx: "270", cy: "170", r: "4", fill: "#91a4d2", opacity: "0.6" } + circle { + cx: "200", + cy: "180", + r: "8", + fill: "url(#grad1)", + } + circle { + cx: "150", + cy: "230", + r: "6", + fill: "url(#grad2)", + } + circle { + cx: "250", + cy: "230", + r: "6", + fill: "url(#grad2)", + } + circle { + cx: "200", + cy: "280", + r: "6", + fill: "url(#grad1)", + } + circle { + cx: "130", + cy: "170", + r: "4", + fill: "#91a4d2", + opacity: "0.6", + } + circle { + cx: "270", + cy: "170", + r: "4", + fill: "#91a4d2", + opacity: "0.6", + } // Network connections line { - x1: "200", y1: "180", x2: "150", y2: "230", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.4", + x1: "200", + y1: "180", + x2: "150", + y2: "230", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.4", } line { - x1: "200", y1: "180", x2: "250", y2: "230", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.4", + x1: "200", + y1: "180", + x2: "250", + y2: "230", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.4", } line { - x1: "150", y1: "230", x2: "200", y2: "280", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.4", + x1: "150", + y1: "230", + x2: "200", + y2: "280", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.4", } line { - x1: "250", y1: "230", x2: "200", y2: "280", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.4", + x1: "250", + y1: "230", + x2: "200", + y2: "280", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.4", } line { - x1: "200", y1: "180", x2: "130", y2: "170", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.3", + x1: "200", + y1: "180", + x2: "130", + y2: "170", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.3", } line { - x1: "200", y1: "180", x2: "270", y2: "170", - stroke: "#91a4d2", stroke_width: "1", opacity: "0.3", + x1: "200", + y1: "180", + x2: "270", + y2: "170", + stroke: "#91a4d2", + stroke_width: "1", + opacity: "0.3", } // Checkmark inside shield center path { @@ -236,37 +315,49 @@ fn FeaturesGrid() -> Element { } div { class: "features-grid", FeatureCard { - icon: rsx! { Icon { icon: BsServer, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: BsServer, width: 28, height: 28 } + }, title: "Self-Hosted Infrastructure", description: "Deploy on your own hardware or private cloud. \ Full control over your AI stack with no external dependencies.", } FeatureCard { - icon: rsx! { Icon { icon: BsShieldCheck, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: BsShieldCheck, width: 28, height: 28 } + }, title: "GDPR Compliant", description: "EU data residency guaranteed. Your data never \ leaves your infrastructure or gets shared with third parties.", } FeatureCard { - icon: rsx! { Icon { icon: FaCubes, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: FaCubes, width: 28, height: 28 } + }, title: "LLM Management", description: "Deploy, monitor, and manage multiple language \ models. Switch between models with zero downtime.", } FeatureCard { - icon: rsx! { Icon { icon: BsRobot, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: BsRobot, width: 28, height: 28 } + }, title: "Agent Builder", description: "Create custom AI agents with integrated Langchain \ and Langfuse for full observability and control.", } FeatureCard { - icon: rsx! { Icon { icon: BsGlobe2, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: BsGlobe2, width: 28, height: 28 } + }, title: "MCP Server Management", description: "Manage Model Context Protocol servers to extend \ your AI capabilities with external tool integrations.", } FeatureCard { - icon: rsx! { Icon { icon: BsKey, width: 28, height: 28 } }, + icon: rsx! { + Icon { icon: BsKey, width: 28, height: 28 } + }, title: "API Key Management", description: "Generate API keys, track usage per seat, and \ set fine-grained permissions for every integration.", @@ -300,9 +391,7 @@ fn HowItWorks() -> Element { rsx! { section { id: "how-it-works", class: "how-it-works-section", h2 { class: "section-title", "Up and Running in Minutes" } - p { class: "section-subtitle", - "Three steps to sovereign AI infrastructure." - } + p { class: "section-subtitle", "Three steps to sovereign AI infrastructure." } div { class: "steps-grid", StepCard { number: "01", @@ -353,21 +442,23 @@ fn StepCard(number: &'static str, title: &'static str, description: &'static str fn CtaBanner() -> Element { rsx! { section { class: "cta-banner", - h2 { class: "cta-title", - "Ready to take control of your AI infrastructure?" - } + h2 { class: "cta-title", "Ready to take control of your AI infrastructure?" } p { class: "cta-subtitle", "Start deploying sovereign GenAI today. No credit card required." } div { class: "cta-actions", Link { - to: Route::Login { redirect_url: "/dashboard".into() }, + to: Route::Login { + redirect_url: "/dashboard".into(), + }, class: "btn btn-primary btn-lg", "Get Started Free" Icon { icon: BsArrowRight, width: 18, height: 18 } } Link { - to: Route::Login { redirect_url: "/dashboard".into() }, + to: Route::Login { + redirect_url: "/dashboard".into(), + }, class: "btn btn-outline btn-lg", "Log In" } @@ -389,9 +480,7 @@ fn LandingFooter() -> Element { } span { "CERTifAI" } } - p { class: "footer-tagline", - "Sovereign GenAI infrastructure for enterprises." - } + p { class: "footer-tagline", "Sovereign GenAI infrastructure for enterprises." } } div { class: "footer-links-group", h4 { class: "footer-links-heading", "Product" } diff --git a/src/pages/privacy.rs b/src/pages/privacy.rs index 127e946..f7bccd0 100644 --- a/src/pages/privacy.rs +++ b/src/pages/privacy.rs @@ -22,9 +22,7 @@ pub fn PrivacyPage() -> Element { } main { class: "legal-content", h1 { "Privacy Policy" } - p { class: "legal-updated", - "Last updated: February 2026" - } + p { class: "legal-updated", "Last updated: February 2026" } h2 { "1. Introduction" } p { @@ -90,9 +88,7 @@ pub fn PrivacyPage() -> Element { li { "Request erasure of your data" } li { "Restrict or object to processing" } li { "Data portability" } - li { - "Lodge a complaint with a supervisory authority" - } + li { "Lodge a complaint with a supervisory authority" } } h2 { "7. Contact" }