diff --git a/app/page.tsx b/app/page.tsx index ad7e384..eba5662 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -226,7 +226,7 @@ export default function Home() {

Pipeline Status

- Build Status(null); + + useEffect(() => { + mermaid.initialize({ + startOnLoad: false, + theme: "dark", + securityLevel: "loose", + fontFamily: "monospace", + }); + + // Render the chart once. Use a timeout to ensure DOM is stable. + const renderChart = async () => { + try { + await mermaid.contentLoaded(); + setIsRendered(true); + } catch (err) { + console.error("Mermaid render failed:", err); + } + }; + + renderChart(); + }, [chart]); // Only re-run if the chart string itself changes + + return ( +
+ !isExpanded && setIsExpanded(true)} + > + {/* Legend */} +
+
+
+ + Traffic Flow + +
+
+
+ + Service Node + +
+
+ + {/* Chart Area */} +
+
{chart}
+
+ + {/* Fade Overlay */} + + {!isExpanded && ( + + )} + + + + {/* Toggle Button */} + +
+ ); +} diff --git a/components/Mermaid copy.tsx b/components/Mermaid copy.tsx new file mode 100644 index 0000000..a03d2cc --- /dev/null +++ b/components/Mermaid copy.tsx @@ -0,0 +1,98 @@ +"use client"; +import { useEffect, useState, useRef } from "react"; +import mermaid from "mermaid"; +import { motion, AnimatePresence } from "framer-motion"; +import { Maximize2, Minimize2 } from "lucide-react"; + +export default function Mermaid({ chart }: { chart: string }) { + const [isExpanded, setIsExpanded] = useState(false); + const [needsExpansion, setNeedsExpansion] = useState(false); + const contentRef = useRef(null); + + useEffect(() => { + mermaid.initialize({ + startOnLoad: true, + theme: "dark", + securityLevel: "loose", + fontFamily: "monospace", + }); + mermaid.contentLoaded(); + + if (contentRef.current) { + const height = contentRef.current.scrollHeight; + setNeedsExpansion(height > 400); + } + }, [chart]); + + return ( +
+ needsExpansion && setIsExpanded(!isExpanded)} + animate={{ height: isExpanded || !needsExpansion ? "auto" : "400px" }} + className={`relative bg-neutral-900/20 rounded-3xl border border-neutral-800/50 p-4 md:p-12 overflow-hidden transition-colors duration-500 + ${needsExpansion && !isExpanded ? "cursor-pointer hover:border-neutral-700" : "cursor-default"}`} + > + {/* Legend */} +
+
+
+ + Traffic Flow + +
+
+
+ + Service Node + +
+
+ +
+ {chart} +
+ + {/* The "Fade to Darkness" Overlay (when expansion is needed) */} + + {needsExpansion && !isExpanded && ( + + )} + + + + {/* Expand/Collapse Button (when expansion is needed) */} + {needsExpansion && ( + + )} +
+ ); +} diff --git a/components/MonitorCard.tsx b/components/MonitorCard.tsx index 357188d..2fa0c95 100644 --- a/components/MonitorCard.tsx +++ b/components/MonitorCard.tsx @@ -114,12 +114,12 @@ export default function MonitorRegistry({ isHovered }: { isHovered: boolean }) { {m.name}
- up - ms - {`Thumb|HTTPS| B + B <-->|WSGI| C + C <-->|Query/Write| G + C ==>|Dataframes| D + D --> E + D --> F + + %% Styles %% + classDef traffic fill:#2563eb,stroke:#3b82f6,color:#fff + classDef node fill:#16a34a,stroke:#22c55e,color:#fff + `, }, { slug: "ayla", - category: "web", + category: "infrastructure", title: "Ayla", - subtitle: "Regulatory-Compliant Data Platform", - role: "Lead Full-Stack Engineer", + subtitle: "Regulatory-Compliant Medical Platform", + role: "Tech Lead & Scrum Master", duration: "2022 — 2024", - stack: ["Node.js", "PostgreSQL", "React", "Docker"], - metrics: ["99.9% Uptime", "Zero-Data-Loss Integrity", "ISO 27001 Ready"], - description: "Architected a high-integrity platform designed to meet rigid regulatory requirements.", - engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...", - images: ["/ratoong-hero.jpg", "/ratoong-dashboard.jpg"], - liveUrl: "https://ratoong.com", + stack: [ + "Kubernetes", + "Ruby on Rails", + "Flutter", + "Terraform", + "GCP", + "OTC", + ], + metrics: [ + "Multi-Region Data Residency", + "ISO 27001 Compliant", + "Single-Click IaC Deployment", + ], + description: + "A high-availability medical device platform supporting dementia treatment, featuring multi-cloud infrastructure, automated pipelines, cross-platform web and mobile deployments and strict regulatory requirements.", + storyLabel: "GOVERNANCE // CLOUD ORCHESTRATION", + images: [ + "/projects/ayla/ayla-1.jpg", + "/projects/ayla/ayla-2.jpg", + "/projects/ayla/ayla-3.jpg", + "/projects/ayla/ayla-4.jpg", + "/projects/ayla/ayla-5.jpg", + ], isPrivate: true, - storyLabel: "DATA EFFICIENCY", + engineeringStory: ` +As Tech Lead for Ayla, I was responsible for architecting a platform that met the rigorous safety and security standards of a certified medical device. This required a "Security-by-Design" approach, balancing high availability (SLA) with rigid data residency requirements across the UK and EU. + +#### Multi-Cloud Infrastructure & IaC +To satisfy GDPR and local health data regulations, I architected a dual-cloud strategy: **Open Telekom Cloud (OTC)** for European users and **GCP** for the UK. Using **Terraform**, I codified the entire infrastructure, enabling us to spin up identical, audit-ready Kubernetes clusters or Cloud Run environments in minutes. This automation was critical for maintaining the "Release-Pre-Release" protocols required for medical certification. + +#### Full-Stack Delivery & Automation +The platform featured a **Flutter** frontend for Web, iOS, and Android, all managed through automated **CICD** pipelines. I implemented a layered automation strategy, combining **GitHub Actions** for web deployments and server-side logic with **Fastlane** for mobile app store distribution. The backend was a high-performance **Ruby on Rails** API, architected as a stateless "mini-service" to ensure horizontal scalability within Kubernetes. I also integrated **Squidex CMS** to empower non-technical colleagues to manage content without compromising the system's core integrity. + +#### Leadership & Compliance +Beyond the code, I served as Scrum Master and Product Owner, leading sprint planning, retro and demos. I worked closely with regulatory partners and personally oversaw the creation of **DPIAs**, **Cyber Essentials** certification, and the path to **ISO 27001** compliance. In the absence of a dedicated IT department, I managed the MDM systems and sysadmin duties, ensuring that every layer of the organization met the strict regulatory bar. + `, + mermaidChart: ` +graph TB + %% Direction and Layout + direction TB + + subgraph Shared_Ops [DevOps & CMS] + I[GitHub Actions CICD]:::traffic + J[Terraform IaC]:::traffic + K[Squidex CMS]:::node + end + + subgraph Frontend_Layer [Omni-Channel] + A[Flutter Web / Mobile]:::traffic + B[Bunny CDN / Edge Storage]:::node + end + + subgraph UK_Region [GCP] + G[Cloud Run Containers]:::node + H[Cloud SQL]:::node + end + + subgraph EU_Region [Open Telekom Cloud] + D[NGINX Ingress]:::node + C[K8s Cluster]:::node + F[Object Storage]:::node + E[PostgreSQL RDS]:::node + end + + %% Connections + A <--> B + I -->|Fastlane| A + J -->|Provision| G + J -->|Provision| C + + B <-->|UK Traffic| G + B <-->|EU Traffic| D + + D --> C + G <--> H + C <--> E + C --- F + + G <--> K + C <--> K + + %% Styles + classDef traffic fill:#2563eb,stroke:#3b82f6,color:#fff + classDef node fill:#16a34a,stroke:#22c55e,color:#fff + `, }, - { + { slug: "flutter-1", category: "mobile", title: "Flutter-1", @@ -116,15 +253,17 @@ graph LR duration: "2025 — Present", stack: ["Python", "FastAPI", "Next.js", "Redis"], metrics: ["Sub-50ms Latency", "Automated ETL", "Self-Hosted"], - description: "A data science pipeline tool built to explore high-speed processing and real-time visualization of large datasets.", + description: + "A data science pipeline tool built to explore high-speed processing and real-time visualization of large datasets.", images: ["/datasaur-1.jpg"], repoUrl: "https://git.georgew.dev/georgew/datasaur", liveUrl: "https://ratoong.com", - engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...", + engineeringStory: + "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...", storyLabel: "DATA EFFICIENCY", isPrivate: true, }, - { + { slug: "flutter-2", category: "mobile", title: "Flutter-1", @@ -133,12 +272,14 @@ graph LR duration: "2025 — Present", stack: ["Python", "FastAPI", "Next.js", "Redis"], metrics: ["Sub-50ms Latency", "Automated ETL", "Self-Hosted"], - description: "A data science pipeline tool built to explore high-speed processing and real-time visualization of large datasets.", + description: + "A data science pipeline tool built to explore high-speed processing and real-time visualization of large datasets.", images: ["/datasaur-1.jpg"], repoUrl: "https://git.georgew.dev/georgew/datasaur", liveUrl: "https://ratoong.com", - engineeringStory: "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...", + engineeringStory: + "In this high-stakes medical environment, I implemented a custom audit logging system that ensured every state change was immutable...", storyLabel: "DATA EFFICIENCY", isPrivate: true, }, -]; \ No newline at end of file +]; diff --git a/public/projects/ayla/ayla-1.jpg b/public/projects/ayla/ayla-1.jpg new file mode 100644 index 0000000..12e09b0 Binary files /dev/null and b/public/projects/ayla/ayla-1.jpg differ diff --git a/public/projects/ayla/ayla-2.jpg b/public/projects/ayla/ayla-2.jpg new file mode 100644 index 0000000..786c0ec Binary files /dev/null and b/public/projects/ayla/ayla-2.jpg differ diff --git a/public/projects/ayla/ayla-3.jpg b/public/projects/ayla/ayla-3.jpg new file mode 100644 index 0000000..aa1c1c0 Binary files /dev/null and b/public/projects/ayla/ayla-3.jpg differ diff --git a/public/projects/ayla/ayla-4.jpg b/public/projects/ayla/ayla-4.jpg new file mode 100644 index 0000000..79d51c3 Binary files /dev/null and b/public/projects/ayla/ayla-4.jpg differ diff --git a/public/projects/ayla/ayla-5.jpg b/public/projects/ayla/ayla-5.jpg new file mode 100644 index 0000000..1826cdb Binary files /dev/null and b/public/projects/ayla/ayla-5.jpg differ diff --git a/public/projects/datasaur/datasaur-1.jpg b/public/projects/datasaur/datasaur-1.jpg new file mode 100644 index 0000000..fba1677 Binary files /dev/null and b/public/projects/datasaur/datasaur-1.jpg differ diff --git a/public/projects/datasaur/datasaur-2.jpg b/public/projects/datasaur/datasaur-2.jpg new file mode 100644 index 0000000..4070d14 Binary files /dev/null and b/public/projects/datasaur/datasaur-2.jpg differ diff --git a/public/projects/datasaur/datasaur-3.jpg b/public/projects/datasaur/datasaur-3.jpg new file mode 100644 index 0000000..c7f07dd Binary files /dev/null and b/public/projects/datasaur/datasaur-3.jpg differ diff --git a/public/projects/datasaur/datasaur-4.jpg b/public/projects/datasaur/datasaur-4.jpg new file mode 100644 index 0000000..cb432c8 Binary files /dev/null and b/public/projects/datasaur/datasaur-4.jpg differ diff --git a/public/projects/datasaur/datasaur-5.jpg b/public/projects/datasaur/datasaur-5.jpg new file mode 100644 index 0000000..12aaa98 Binary files /dev/null and b/public/projects/datasaur/datasaur-5.jpg differ diff --git a/public/projects/datasaur/datasaur-6.jpg b/public/projects/datasaur/datasaur-6.jpg new file mode 100644 index 0000000..7cda0fc Binary files /dev/null and b/public/projects/datasaur/datasaur-6.jpg differ