# DulapahV Portfolio > This document provides a detailed overview of DulapahV's portfolio, including skills, open source contributions, and detailed listings of blog posts, projects, and work experiences. @last-updated: 2025-11-17 @site-url: https://dulapahv.dev @content-types: Blog Posts, Projects, Work Experiences, Skills, Open Source Contributions ## Sitemaps - [sitemap.xml](https://dulapahv.dev/sitemap.xml): XML sitemap for search engines - [llms.txt](https://dulapahv.dev/llms.txt): Lightweight portfolio summary for language models - [llms-full.txt](https://dulapahv.dev/llms-full.txt): Detailed portfolio summary for language models ================================================================================ SECTION: Technical Skills Description: Core technical competencies and technologies ================================================================================ -------------------------------------------------------------------------------- Category: General programming -------------------------------------------------------------------------------- TypeScript, JavaScript, Python, C, C++, Java, Bash -------------------------------------------------------------------------------- Category: Databases -------------------------------------------------------------------------------- PostgreSQL, MongoDB, SQLite, MySQL, Snowflake -------------------------------------------------------------------------------- Category: Web frameworks & UI -------------------------------------------------------------------------------- Next.js, React.js, Tailwind CSS, shadcn/ui, Radix UI, HeroUI, daisyUI, MUI -------------------------------------------------------------------------------- Category: Backend -------------------------------------------------------------------------------- Express.js, Prisma, WebSocket -------------------------------------------------------------------------------- Category: Cross-platform & Desktop -------------------------------------------------------------------------------- Electron.js, Qt -------------------------------------------------------------------------------- Category: DevOps & Testing -------------------------------------------------------------------------------- GitHub Actions, GitLab CI/CD, Playwright, Jest, Sentry, Turborepo -------------------------------------------------------------------------------- Category: Cloud & Infrastructure -------------------------------------------------------------------------------- Vercel, Cloudflare, Docker, Supabase, GCP, Nginx, Firebase ================================================================================ SECTION: Open Source Contributions Description: Community contributions to open source projects Statistics: Total: 4 | Merged: 2 | Open: 2 | Closed: 0 ================================================================================ -------------------------------------------------------------------------------- title: "fix: include width param in Cloudflare image loader to resolve Next.js warnings" repository: "opennextjs/docs" url: "https://github.com/opennextjs/docs/pull/190" type: PR status: MERGED date: 2025-11-08 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- title: "fix: include width param in Next.js Cloudflare Image loader examples to resolve warnings" repository: "cloudflare/cloudflare-docs" url: "https://github.com/cloudflare/cloudflare-docs/pull/26391" type: PR status: OPEN date: 2025-11-08 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- title: "refactor(components): use canonical Tailwind class syntax" repository: "shadcn-ui/ui" url: "https://github.com/shadcn/ui/pull/8742" type: PR status: OPEN date: 2025-11-08 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- title: "feat(th.json): add Thai language support" repository: "anders94/blockchain-demo" url: "https://github.com/anders94/blockchain-demo/pull/142" type: PR status: MERGED date: 2025-09-28 -------------------------------------------------------------------------------- ================================================================================ SECTION: Blog Description: My thoughts, ideas, and experiences. URL: https://dulapahv.dev/blog ================================================================================ -------------------------------------------------------------------------------- title: "Display Different Images for Dark/Light Mode Without FOUC in Next.js" description: "Learn how to display different images for dark and light themes without flash of unstyled content or client-side rendering." source: "https://dulapahv.dev/blog/display-different-images-dark-light-mode-nextjs" -------------------------------------------------------------------------------- # Display Different Images for Dark/Light Mode Without FOUC in Next.js ## The Problem You might occasionally come across a situation where you need to display an image or logo with a solid color background. Often, the logo color will be solid white or solid black. This becomes problematic when displaying the image on a dark or light background that has a similar color to the logo, causing poor contrast or, even worse, making the logo completely disappear. ## Initial Solution With Client-Side Rendering If you're using [next-themes](https://github.com/pacocoursey/next-themes), you can use the `useTheme` hook to get the current theme and render different images based on the theme. ```tsx title="ThemeAwareImage.tsx" showLineNumbers 'use client'; // [!code warning] import Image from 'next/image'; import { useTheme } from 'next-themes'; export function ThemeAwareImage() { const { resolvedTheme } = useTheme(); return ( ) } ``` However, this approach requires client-side rendering, which can lead to a flash of unstyled content (FOUC) as the theme is determined after the initial render. ## Better Solution Without Client-Side Rendering To avoid client-side rendering, we can use CSS to handle theme-aware image rendering. ```tsx title="ThemeAwareImage.tsx" showLineNumbers {16,20} import Image from 'next/image'; interface ThemeAwareImageProps { lightSrc: string; darkSrc: string; } export function ThemeAwareImage({ lightSrc, darkSrc, }: ThemeAwareImageProps) { return ( <> ) } ``` With this approach, we render both images in the DOM and use CSS to show or hide them based on the current theme. The first image will be displayed when the theme is dark, and the second image will be displayed when the theme is light. Building on this concept, we can create a more robust and reusable component for all our projects: ```tsx title="ThemeAwareImage.tsx" showLineNumbers import Image from 'next/image'; interface ThemeAwareImageProps extends Omit, 'src'> { lightSrc: string; darkSrc: string; } export function ThemeAwareImage({ lightSrc, darkSrc, className = '', ...props }: ThemeAwareImageProps) { return ( <> ); } ``` ## Conclusion This approach allows us to render different images based on the theme without relying on client-side rendering. This not only improves performance but also eliminates potential FOUC issues. The `ThemeAwareImage` component can be reused across your Next.js projects, making it a versatile solution for theme-aware images. -------------------------------------------------------------------------------- title: "How I Became a Software Engineer (Even Though I Wanted to Be a Heart Surgeon)" description: "A personal journey from chasing medicine to discovering a love for code." source: "https://dulapahv.dev/blog/how-i-became-a-software-engineer" -------------------------------------------------------------------------------- # How I Became a Software Engineer (Even Though I Wanted to Be a Heart Surgeon) > *What if you chased a dream your whole life—only to discover your real passion just before it was too late?* For as long as I can remember, I wanted to be a doctor. Specifically, a heart surgeon. That dream started when I was a child watching *[Iryû: Team Medical Dragon](https://en.wikipedia.org/wiki/Iry%C5%AB)*, a Japanese medical drama, with my mom. Something about the precision, the intensity, and the ability to save lives captured my imagination—and it never let go. ## The Dream of a Surgeon For most of my youth, every step I took was toward that goal. I attended medical camps, university open houses, and volunteered in hospitals like Phramongkutklao and Ramathibodi. I even donated handmade face shields to hospitals during the COVID-19 pandemic. ![Attending Siriraj Medical Camp](/blog/how-i-became-a-software-engineer/siriraj_med_camp.jpg) My parents supported me, emotionally and financially. We invested heavily in pursuing that path. I attended events at top medical faculties like Siriraj, Phramongkutklao College of Medicine, Chulabhorn International College of Medicine, Thammasat University, and more. I also studied rigorously for exams like the [BioMedical Admissions Test (BMAT)](https://en.wikipedia.org/wiki/BioMedical_Admissions_Test)1. To strengthen my academic profile, I enrolled in online courses from top universities, including **[Harvard University](https://www.edx.org/school/harvardx)** on edX, **[Yale University](https://www.coursera.org/partners/yale)** on Coursera, and **[University of Pennsylvania](https://www.coursera.org/partners/penn)** on Coursera—covering subjects related to medicine, health, and science. Everything in my life revolved around medicine. ![My collection of medical and volunteer certificates](/blog/how-i-became-a-software-engineer/certificates.png) That is, until Grade 12. ## A Project That Changed Everything As part of a required school project at Suankularb Wittayalai School, I joined a biology team working on: > **An Experiment on Carnivorous Plants' Ability to Add Nitrogen to Soil** > *(Hypothesis: planting carnivorous plants in degraded soil might enrich nitrogen levels in an eco-friendly way.)* ![Biology project on carnivorous plants and soil nitrogen levels](/blog/how-i-became-a-software-engineer/carnivorous_plants_project.png) This was meant to be another highlight in my medical school portfolio. But I wanted to challenge myself and do more. So I asked a teacher if I could take on a second project—and he agreed. That's when I started: > **A Development of a Strategic Role-Playing Video Game to Reduce Student Stress** > *(A game designed to help teenagers relax and express themselves, built using [Unreal Engine Blueprints](https://dev.epicgames.com/documentation/en-us/unreal-engine/blueprints-visual-scripting-in-unreal-engine), [VRoid Studio](https://vroid.com/en/studio) for avatars, and [Blender](https://www.blender.org/) for animations.)* ![Screenshot of my student-built role-playing video game for stress relief](/blog/how-i-became-a-software-engineer/strategic_role_playing_game.png) It was my first time exploring anything related to game development or programming. Even though Unreal's Blueprint system is visual and node-based, it required logical thinking, problem-solving, and a deep understanding of systems interaction. And I was hooked. I spent entire days building and testing the game, completely absorbed. It never felt like work. It felt like something I was meant to do. ## Realizing My Passion (and Facing the Consequences) That project lit a fire in me. I wasn't just enjoying it—I was obsessed. I talked about it constantly and worked on it nonstop. Meanwhile, I continued studying for the BMAT, still trying to hold on to the medical dream. But the contrast became unbearable. Preparing for medicine drained me. Coding energized me. Eventually, I had to be honest—with myself and with my family. I told my parents I wanted to become a software engineer instead. It was one of the hardest conversations of my life. We had spent years preparing for medical school. A lot of money had been invested. And worst of all, I made my mom cry. My family didn't fully understand what software engineers do—they imagined me fixing PCs in a department store. We argued for nearly a year. But I didn't give up. I showed them how serious I was: spending hours each day coding, enrolling in challenging courses like Harvard's [CS50](https://www.edx.org/cs50) (even though the C language nearly broke me at the time), and researching universities that could support this new path. ![CS50 online course interface](/blog/how-i-became-a-software-engineer/cs50_course.png) I also completed my first Scratch project as part of CS50: **[Check it out on Scratch](https://scratch.mit.edu/projects/445443221)** ![Scratch project screenshot: My first interactive game](/blog/how-i-became-a-software-engineer/scratch_project.png)
Gradually, they began to believe in me too. ## Choosing My Path In the end, I applied to both medical and engineering programs. I was rejected by every medical faculty. But I was accepted into every engineering and computer science one. I chose the double degree in Software Engineering from **KMITL and the University of Glasgow**, believing it offered the strongest combination of academic depth and international opportunity. The University of Glasgow is ranked among the top 100 universities in the world2. Even though I started later than most of my peers—many of whom had been coding since childhood—I was determined to catch up. I practiced every day using platforms like [W3Schools](https://www.w3schools.com/) and [Sololearn](https://www.sololearn.com/), and I documented my journey at [github.com/dulapahv/PracticeCoding](https://github.com/dulapahv/PracticeCoding). ## Where I Am Now Today, I hold a **First Class Honours degree from the University of Glasgow**. I secured a return offer from my internship in the UK before I even graduated. I have a full-time job lined up—and most importantly, I love what I do. ![My First Class Honours certificate from University of Glasgow](/blog/how-i-became-a-software-engineer/first_class_honours.png) I made my parents proud. I made *myself* proud. ## Looking Back Looking back, I didn't fail at becoming a doctor—I simply discovered a better way to help people, in a way that felt right for me. That childhood desire to improve lives never went away. I've just taken a different route to get there. And who knows? Maybe one day I'll build something in health tech, medical AI, or digital well-being—blending the two worlds that shaped who I am. If you're someone who's scared to change direction, or afraid it's “too late” to start something new—trust your passion. It might just lead you somewhere even better. --- 1 BMAT has been discontinued since 2023, but it was a standardized test used for medical school admissions in the UK and some other countries. 2 According to the Times Higher Education Rankings, the University of Glasgow was ranked 92nd globally in 2021 and improved to 87th in 2025. -------------------------------------------------------------------------------- title: "How to Use Variables in JSDoc with vite-plugin-dts" description: "Learn how to incorporate variables into your JSDoc comments using vite-plugin-dts for more maintainable and consistent documentation." source: "https://dulapahv.dev/blog/how-to-use-variables-in-jsdoc-with-vite-plugin-dts" -------------------------------------------------------------------------------- # How to Use Variables in JSDoc with vite-plugin-dts ## Introduction When documenting your code, JSDoc comments are a great way to provide additional context and information. However, sometimes you may want to use variables within your JSDoc comments to avoid repetition and make your documentation more maintainable. If you're using `vite-plugin-dts` to generate type declarations, you'll know that it doesn't natively support variable interpolation in JSDoc comments. In this blog post, we'll explore a workaround to achieve this. ## Setting Up vite-plugin-dts for Variable Replacement The `vite-plugin-dts` plugin gives us a way to hook into the declaration file generation process. We can use the `beforeWriteFile` option to modify the content of the generated `.d.ts` files before they are written to disk. ```ts title="vite.config.ts" showLineNumbers import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; import type { PluginOptions } from 'vite-plugin-dts'; import fs from 'fs'; import path from 'path'; interface JsdocVarReplacerOptions { variables?: Record; pattern?: RegExp; } function JsdocVarReplacer( options: JsdocVarReplacerOptions = {} ): NonNullable { let pkg: { config?: { jsdoc?: Record } } = {}; try { pkg = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), 'package.json'), 'utf-8')); } catch (error) { console.warn(`\x1b[33m[jsdoc-var-replacer] Could not read package.json: ${error}\x1b[0m`); } const variables = options.variables || pkg.config?.jsdoc || {}; const pattern = options.pattern || /\$([A-Za-z_$][A-Za-z0-9_$]*)\$/g; return (filePath: string, content: string) => { const modifiedContent = content.replace( pattern, (match, varName) => variables[varName] ?? (console.warn(`\x1b[33m[jsdoc-var-replacer] Variable not found: ${varName}\x1b[0m`), match) ); return { filePath, content: modifiedContent }; }; } export default defineConfig({ plugins: [ dts({ beforeWriteFile: JsdocVarReplacer() }) ] }); ``` The plugin works by reading the `package.json` file to extract variables defined under the `config.jsdoc` section. It then scans the generated `.d.ts` files for placeholders in the format `$variableName$` and replaces them with the corresponding values. These variables are replaced during the build process when generating type declarations. They won't affect your source code or runtime behavior. ## Using Variables in JSDoc Comments With our `vite-plugin-dts` setup ready, we can now use variables in our JSDoc comments. Here's how to do it: 1. **Define Variables**: In your `package.json`, define the variables you want to use in your JSDoc comments under the `config.jsdoc` section. You can also define them directly in the `JsdocVarReplacer` options if preferred. (see [Options and Customization](#options-and-customization) below) > [!Note] > If your `package.json` is located elsewhere, see [Limitations](#limitations) for instructions on how to import it manually. ```json title="package.json" showLineNumbers { "config": { "jsdoc": { "AUTHOR": "Your Name", "VERSION": "1.0.0", "BASE_URL": "https://example.com" } } } ``` 2. **Use Variables in JSDoc**: In your TypeScript files, you can now use these variables in your JSDoc comments. > [!Important] > The variables should be wrapped with `$` symbols. This is chosen to avoid conflicts with other JSDoc syntax. You can customize the pattern in the `JsdocVarReplacer` options if needed. (see [Options and Customization](#options-and-customization) below) ```ts title="src/components/Button.ts" showLineNumbers /** * Button component function * @author $AUTHOR$ * @version $VERSION$ * @see {@link $BASE_URL$/button|Button Documentation} */ function Button() { // Implementation details } ``` 3. **Build Your Project**: When you build your project, `vite-plugin-dts` will replace the variables in your JSDoc comments with the values defined in your `package.json`. ```bash npm run build ``` 4. **Check the Output**: After building, check the generated `.d.ts` files to see the replaced variables in the JSDoc comments. ```ts title="dist/components/Button.d.ts" showLineNumbers /** * Button component function * @author Your Name * @version 1.0.0 * @see {@link https://example.com/button|Button Documentation} */ function Button() { // Implementation details } ``` And that's it! You've successfully incorporated variables into your JSDoc comments using `vite-plugin-dts`. This approach not only makes your documentation more maintainable but also ensures consistency across your codebase. ## Options and Customization The `JsdocVarReplacer` function accepts an options object that allows you to customize its behavior: - `variables`: An object mapping variable names to their values. If not provided, it defaults to reading from `package.json` under `config.jsdoc`. - `pattern`: A regular expression to match variable placeholders in JSDoc comments. The default pattern matches `$variableName$`. Feel free to adjust these options to fit your project's needs. ## Limitations The plugin only scans for a `package.json` file located in the same directory where the Vite command is executed. If your `package.json` is located elsewhere, you can manually import it using: ```ts import pkg from '../path/to/your/package.json'; ``` Then pass the config to the plugin as an argument: ```ts dts({ beforeWriteFile: JsdocVarReplacer({ variables: pkg.config?.jsdoc || {} }) }); ``` ## Conclusion Using variables in JSDoc comments can significantly enhance the maintainability and consistency of your documentation. With the help of `vite-plugin-dts` and a custom `beforeWriteFile` function, you can easily achieve this in your projects. Give it a try and see how it improves your documentation workflow! -------------------------------------------------------------------------------- title: "Improve Captcha User Experience with Invisible CAPTCHA by Vercel BotID" description: "Protect your site from bots without frustrating users. Learn how to implementing Vercel BotID's invisible CAPTCHA in Next.js." source: "https://dulapahv.dev/blog/improve-user-experience-with-invisibile-captcha" -------------------------------------------------------------------------------- # Improve Captcha User Experience with Invisible CAPTCHA by Vercel BotID ## Introduction CAPTCHA has been a standardized method to differentiate between human users and bots on websites. However, traditional CAPTCHA methods often disrupt user experience (UX), leading to frustration and abandonment. In this blog post, we will explore how to implement invisible CAPTCHA solutions that enhance UX while maintaining security. [Jump to implementation -->](#getting-started-with-botid) ## The Problem with Traditional CAPTCHA [Google reCAPTCHA](https://developers.google.com/recaptcha) is currently one of the most widely used CAPTCHA services, but it also comes with one of the most disruptive user experiences. Users are often required to solve puzzles, identify images, or type distorted text, which can be time-consuming and frustrating. ![reCAPTCHA](/blog/vercel-botid-invisible-protection/recaptcha.png "Source: https://developers.nopecha.com/recognition/recaptcha/") Another similarly disruptive CAPTCHA is [hCaptcha](https://www.hcaptcha.com/), commonly seen in Discord, which also requires user interaction to verify they are human. ![hCaptcha](/blog/vercel-botid-invisible-protection/hcaptcha.png "Source: https://developers.nopecha.com/token/hcaptcha/") Some websites use proprietary CAPTCHA systems, but these often suffer from the same issues as Google reCAPTCHA and hCaptcha — or even worse. ![proprietary CAPTCHA](/blog/vercel-botid-invisible-protection/proprietary-captcha.jpg "Source: Chang et al., Journal of Information Security and Applications, 2024. https://doi.org/10.1016/j.jisa.2024.103711") [Cloudflare Turnstile](https://www.cloudflare.com/application-services/products/turnstile/) tries to address this by offering a less intrusive experience, verifying automatically without user interaction. However, it sometimes still requires users to click a checkbox, which can still be a minor disruption. ![Cloudflare Turnstile](/blog/vercel-botid-invisible-protection/turnstile.gif "Source: https://blog.cloudflare.com/turnstile-ga/") ## Vercel BotID On [June 25, 2025](https://vercel.com/changelog/vercel-botid-is-now-generally-available), Vercel released [BotID](https://vercel.com/docs/botid) — an invisible CAPTCHA solution that protects your application without visible challenges in typical usage. ### How It Works BotID takes a fundamentally different approach: - **Silent Detection:** Collects thousands of signals to distinguish humans from bots without user interaction - **Dynamic Protection:** Changes detection methods on every page load to prevent reverse engineering - **Machine Learning:** Streams attack data into a global ML system that strengthens protection for all users BotID has two operational modes: - **Basic Mode** is a lightweight, Vercel-hosted check that validates browser sessions with minimal processing. - **Deep Analysis** is an optional, stronger check (used when you explicitly call `checkBotId()` with Deep Analysis enabled) and is powered by Kasada's advanced detection engine. This means **not all BotID traffic is routed to Kasada** — only Deep Analysis calls are (and those calls may be billed). The best part? Your users never know it's there. ## Getting Started with BotID Let's walk through setting up BotID in a Next.js App Router project. For this example, we'll protect a newsletter signup endpoint. > [!tip] > BotID also supports other frameworks like SvelteKit, Nuxt, and others. Check the [official documentation](https://vercel.com/docs/botid/get-started) for more details. ### Step 1: Installation ```bash # Install the BotID package pnpm install botid ``` ### Step 2: Configure Next.js ```ts title="next.config.ts" showLineNumbers {1,7} import { withBotId } from 'botid/next/config'; const nextConfig = { // Your existing config }; export default withBotId(nextConfig); ``` ### Step 3: Add Client Protection ```ts title="instrumentation.client.ts" showLineNumbers import { initBotId } from 'botid/client/core'; initBotId({ protect: [ { path: '/api/newsletter', method: 'POST', }, { path: '/api/contact', method: 'POST', }, ], }); ``` ### Step 4: Verify on the Server ```ts title="app/api/newsletter/route.ts" showLineNumbers {3,6,8-10} import { NextRequest, NextResponse } from 'next/server'; import { checkBotId } from 'botid/server'; export async function POST(request: NextRequest) { const verification = await checkBotId(); if (verification.isBot) { return NextResponse.json({ error: 'Bot detected' }, { status: 403 }); } // Process legitimate signup const { email } = await request.json(); await saveToNewsletter(email); return NextResponse.json({ success: true }); } ``` ## Server Actions Support BotID also works seamlessly with Next.js Server Actions: ```ts title="app/actions/submit-feedback.ts" showLineNumbers 'use server'; import { checkBotId } from 'botid/server'; export async function submitFeedback(formData: FormData) { const verification = await checkBotId(); if (verification.isBot) { throw new Error('Access denied'); } // Process feedback const feedback = formData.get('feedback') as string; await saveFeedback(feedback); return { success: true }; } ``` ## Handling Verified Bots Not all bots are bad. BotID can identify verified bots like ChatGPT Operator, allowing you to permit certain AI assistants while blocking malicious ones: ```ts title="app/api/public-data/route.ts" showLineNumbers {5} export async function GET(request: NextRequest) { const { isBot, isVerifiedBot, verifiedBotName } = await checkBotId(); // Allow ChatGPT Operator but block other bots if (isBot && !(isVerifiedBot && verifiedBotName === 'chatgpt-operator')) { return NextResponse.json({ error: 'Access denied' }, { status: 403 }); } // Return data return NextResponse.json({ data: await fetchPublicData() }); } ``` ## Development Mode During local development, BotID automatically returns `isBot: false` to avoid disrupting your workflow. You can test bot detection logic using development options: ```ts showLineNumbers {4} // Testing bot detection in development const verification = await checkBotId({ developmentOptions: { bypass: 'BAD-BOT', // Simulate bot detection }, }); ``` ## Pricing BotID offers two modes: - **Basic Mode:** Free on all plans — validates browser sessions - **Deep Analysis:** $1 per 1,000 calls (Pro/Enterprise) — advanced detection with thousands of signals You're only charged when calling `checkBotId()` with Deep Analysis enabled. Passive page views don't incur charges. ## Real-World Use Cases BotID shines for protecting: - Checkout flows: Prevent inventory hoarding by bots - API endpoints: Stop automated scraping and abuse - AI chat interfaces: Protect expensive LLM-powered features - Sign-up forms: Block fake account creation - Contact forms: Eliminate spam submissions ## Conclusion While the idea of invisible CAPTCHA isn't new1, Vercel BotID makes it accessible and easy to implement. By integrating BotID into your application, you can significantly enhance user experience while maintaining robust security against bots. For detailed documentation and advanced configurations, visit the [Vercel BotID documentation](https://vercel.com/docs/botid). --- 1 Gooding, Sarah (March 9, 2017). ["Google Launches Invisible reCAPTCHA"](https://wptavern.com/google-launches-invisible-recaptcha). [WP Tavern](https://wptavern.com/). -------------------------------------------------------------------------------- title: "Structural and Contextual Styling with Tailwind CSS Arbitrary Variants" description: "Go beyond utility classes and learn how to target children, style elements by parent context, and handle complex structures—without custom CSS or JavaScript." source: "https://dulapahv.dev/blog/tailwind-css-arbitrary-variants-guide" -------------------------------------------------------------------------------- # Structural and Contextual Styling with Tailwind CSS Arbitrary Variants export function Preview({ children }) { return (
{children}
); } ## Introduction [Tailwind CSS arbitrary variants](https://tailwindcss.com/docs/hover-focus-and-other-states#using-arbitrary-variants) allow you to create custom styles that target specific elements in your HTML structure. This is particularly useful when you need to apply styles to child elements based on their type, class, or attributes without adding additional CSS classes or JavaScript. While the official documentation covers the basics, it doesn't demonstrate how to handle more complex scenarios like targeting deeply nested children, combining multiple selectors, or working with custom attributes. > [!WARNING] > **Use arbitrary variants sparingly** as they can reduce code readability and maintainability. ## Core Concepts ### Understanding the & Symbol The `&` character represents the current element (the one with the arbitrary variant class). Think of it as "this element" in your selector. ### Canonical Syntax vs Arbitrary Variants Tailwind CSS now provides canonical syntax for common patterns, which is more concise and readable: - **`*:`** - Targets direct children (canonical for `[&>...]`) - **`**:`** - Targets all descendants (canonical for `[&_...]`) - **`in-[...]`** - Matches when inside a parent (canonical for `[..._&]`) ### Direct Children vs All Descendants This is the most important distinction to understand: - **`*:`** or **`[&>...]`** - Targets only **direct children** (immediate descendants) - **`**:`** or **`[&_...]`** - Targets **all descendants** at any nesting level ```html showLineNumbers {2,5,7}

Direct child - will be red

Nested child - won't be red (not direct)

Nested span - will be blue (all descendants)
Direct span - will be blue
```

Direct child - will be red

Nested child - won't be red (not direct)

Nested span - will be blue (all descendants)
Direct span - will be blue
## Targeting Children by Tag When you need to target direct children by their tag, you can use the `&` selector followed by the tag name. ```html showLineNumbers {3}
Black text

Red text

```
Black text

Red text

## Targeting Children by Class When you need to target direct children by their class, you can use the `&` selector with the class name prefixed by a dot. > [!NOTE] > This also works with `className` attributes in React components. ```html showLineNumbers {3}
Black text
Red text
```
Black text
Red text
You can also add additional classes to the selector. ```html showLineNumbers {3}
Black text
Red text
```
Black text
Red text
## Targeting Children by Data Attributes When you need to target elements based on their data attributes, you can use the `*:` variant for direct children combined with the `data-[attribute="value"]` syntax. > [!NOTE] > This also works with other attributes, not just `data-*`, for example, `role`, `aria-*`, or custom attributes. Target immediate children with specific data attributes using the `*:data-[attribute="value"]` pattern. ```html showLineNumbers {3}
Black text
Red text
```
Black text
Red text
You can also target nested elements with data attributes using the `**:` variant for all descendants. ```html showLineNumbers {3}
Red text
```
Red text
When you need to target elements based on both their attributes and classes, you can combine them in the selector. ```html showLineNumbers {2,3}

Red text

Blue text

```

Red text

Blue text

## Targeting Nested Child Elements When you need to target deeply nested child elements, you can use the `&` selector with a path that describes the hierarchy. ```html showLineNumbers {4}
Deep Child
```
Deep Child
## Conditional Styling Based on Parent Tag When you need to style child elements based on the tag of their parent, you can use the `in-[tag]` variant to check if the element is inside a specific parent tag. ```html showLineNumbers {2}

Styled if parent is p

Styled if parent is p
```

Styled if parent is p

Styled if parent is p
## Conditional Styling Based on Parent Class When you need to style child elements based on the class of their parent, you can use the `in-[.classname]` variant to check if the element is inside a parent with a specific class. ```html showLineNumbers {3}
Child 1
Child 2
```
Child 1
Child 2
## Conditional Styling Based on Parent Attribute When you need to style child elements based on a specific attribute of their parent, you can use the `in-data-[attribute="value"]` variant to check if the element is inside a parent with that data attribute. ```html showLineNumbers {2}

Styled if parent has data-type="special"

Not styled

```

Styled if parent has data-type="special"

Not styled

## Targeting by nth-child You can use the `&` selector with `:nth-child(n)` to target specific children based on their position within the parent. ```html showLineNumbers {4}

One

Two

Three

```

One

Two

Three

To combine multiple nth-child selectors to target different children, you need to add another `&` selector for each child you want to style. ```html showLineNumbers {2,4}

One

Two

Three

```

One

Two

Three

## Advanced Combinations ### Target second child inside `.foo` only When you want to target a specific child element inside a parent with a specific class, you can use the `&` selector with `:nth-child(n)`. ```html showLineNumbers {4}

1

2

3

Not affected

```

1

2

3

Not affected

### Conditional nth-child with Exclusion When you need to exclude certain elements from a universal styling rule, you can use the `:not()` pseudo-class. ```html showLineNumbers {3}
Not Excluded
Excluded
```
Not Excluded
Excluded
```html showLineNumbers {3}
Not Excluded
Excluded
```
Not Excluded
Excluded
### Pseudo + Tag + Descendant + Modifier When you need to style elements based on a combination of pseudo-classes, tags, and modifiers, you can use the `&` selector with a complex path. ```html showLineNumbers {3}
Trigger

Styled paragraph

Trigger

Styled paragraph

```
Trigger

Styled paragraph

Trigger

Styled paragraph

## Conclusion Tailwind CSS arbitrary variants provide powerful tools for targeting child elements, styling based on parent context, and handling complex structures without the need for custom CSS or JavaScript. However, they should be used with care to maintain readability and code maintainability. ## Cheat Sheet | Selector | Use Case | |-|-| | `[&>tag]` | Target direct child elements by tag | | `[&_tag]` | Target all descendant elements by tag | | `[&>.class]` | Target direct children by class | | `[&_.class]` | Target all descendants by class | | `[&>div.class1.class2]` | Target direct children with multiple classes | | `*:data-[x="y"]` | Target direct children with data attributes | | `**:data-[x="y"]` | Target any nested element with data attributes | | `[&_[data-type='a'].class]` | Combine attributes and classes | | `[&>div>div>span]` | Target deeply nested children with specific path | | `in-[tag]` | Style based on parent's tag | | `in-[.parent]` | Style based on parent's class | | `in-data-[x="y"]` | Style based on parent's attributes | | `[&>*:nth-child(n)]` | Target children by position | | `[&>div.class>*:nth-child(n)]` | Target nth-child within specific parent | | `*:[&:not(.excluded)]` | Exclude elements from universal styling | | `*:[&:not([excluded])]` | Exclude elements by attribute | | `[div:has(span)&>p]` | Style based on parent containing specific child | ================================================================================ SECTION: Project Description: Professional and personal projects I have worked on. URL: https://dulapahv.dev/project ================================================================================ -------------------------------------------------------------------------------- title: "AceMath" description: "Online speed mathematics game. Solve math problems as fast as you can while also competing with other people around the world!" source: "https://dulapahv.dev/project/acemath" -------------------------------------------------------------------------------- # AceMath ## Project Description AceMath is an online speed mathematics game written in Python. The goal is to solve math problems as fast as you can while also competing with other people around the world! The key features are: 1. 4 Difficulties - Easy (1 digit integer x 20 questions) - Normal (2 digits integer x 20 questions) - Hard (3 digits integer x 20 questions) - Expert (4 digits integer x 20 questions) 2. Online account synchronization with built-in register/login account feature 3. Online leaderboard system with separated difficulty 4. Users can log in to view their profile stats and sync their progress anywhere/anytime in the world 5. Can also be played offline! To run a program, run these commands in the terminal : - `pip install Pillow` - `pip install firebase-admin` Then simply compile `Main.py`! **Download Here** - [gdrive](https://drive.google.com/file/d/18cR53-hUbM7ec3JAbiwLo_uEHLXHPubf/view?usp=sharing) - [Github](https://github.com/DulapahV/AceMath/blob/main/AceMath.zip) ## Demo ### Main Menu ![image](https://user-images.githubusercontent.com/71577909/138806837-186e85a3-fde0-4e70-b5ba-1d181ea52b34.png) ### Register Account Select `Sync` ![image](https://user-images.githubusercontent.com/71577909/138806837-186e85a3-fde0-4e70-b5ba-1d181ea52b34.png) Select `Create` ![image](https://user-images.githubusercontent.com/71577909/138807760-d7f48b15-7c08-43fd-8cac-e313fe58a1c2.png) Enter your desired Username and Password then click `Create` ![image](https://user-images.githubusercontent.com/71577909/138807898-d5b9f498-1dfc-4cac-aa87-205bf46aef5b.png) If successful, a green message will show up ![image](https://user-images.githubusercontent.com/71577909/138808081-eb15f9cf-0289-4500-8b80-9d1ac31294e1.png) New user will be created in the game's online database ![image](https://user-images.githubusercontent.com/71577909/138812340-d91742ef-d4bf-4cf1-80db-79d18bc695e3.png) ### Login Select `Login` ![image](https://user-images.githubusercontent.com/71577909/138807760-d7f48b15-7c08-43fd-8cac-e313fe58a1c2.png) Enter your credentials then press `Login` ![image](https://user-images.githubusercontent.com/71577909/138808168-4b32fdae-05b3-4f62-9a58-6c95b147683e.png) If successful, you will see this welcome message ![image](https://user-images.githubusercontent.com/71577909/138808251-b749391b-c36c-40d7-a278-135daf1d313e.png) ### Play Select `Play` ![image](https://user-images.githubusercontent.com/71577909/138806837-186e85a3-fde0-4e70-b5ba-1d181ea52b34.png) Select your desired difficulty ![image](https://user-images.githubusercontent.com/71577909/138808402-a220aa37-e3dc-4fca-a035-4a2d721b90a8.png) There will be 5 seconds countdown before the game will start, get ready! ![image](https://user-images.githubusercontent.com/71577909/138808460-79bf1045-5c2e-49ac-9c79-2e4626ae2571.png) Start typing your answer and press enter (the answer field is automatically focussed). If your answer is correct, you will advance to the next question. The top right number shows what question you are working on. ![image](https://user-images.githubusercontent.com/71577909/138808473-02644450-1950-41d1-b8ab-6e502a1aac6e.png) Once you finished all questions, your performance stat will show up ![image](https://user-images.githubusercontent.com/71577909/138808840-e7472b2c-71cc-46a1-91c0-ba08cc529ab6.png) ### Profile Select `Profile` ![image](https://user-images.githubusercontent.com/71577909/138806837-186e85a3-fde0-4e70-b5ba-1d181ea52b34.png) Here, you can see all your stats including the amount of time you played in all/each difficulty as well as the fastest time in each difficulty. You can also change gender by clicking on the bottom left icon! ![image](https://user-images.githubusercontent.com/71577909/138808900-c0380f16-e5ec-4481-838f-56d717f45a19.png) ### Leaderboard Select `Leaderboard` ![image](https://user-images.githubusercontent.com/71577909/138806837-186e85a3-fde0-4e70-b5ba-1d181ea52b34.png) Top-10 users with their fastest time will appear. You can also select the difficulty at the top to change the category. ![image](https://user-images.githubusercontent.com/71577909/138809250-20a37684-1ab3-4e26-87b0-f1ed27078575.png) _Now, you are on your way to becoming an AceMath champion!_ -------------------------------------------------------------------------------- title: "CalcLab" description: "All-encompassing application combines a scientific calculator with graph plotting capabilities, a date comparator, a real-time currency converter, and 12 more converter tools, offering efficient mathematical calculations and conversions." source: "https://dulapahv.dev/project/calclab" -------------------------------------------------------------------------------- # CalcLab An individual project for Introduction to Computers and Programming, KMITL Software Engineering, Year 1, Semester 1 ## Introduction CalcLab is an all-in-one application which includes a scientific calculator with graph plotting capability, date comparator, currency converter (real-time rates), and 12 more converter tools. It is designed to be as easy to use and as straightforward as possible. It also has a beautiful flat-modern GUI which makes it fit seamlessly into any workspace. ## Motivation Generally, when people want to perform conversions or calculations, they must look up on the internet to get the right tools. However, that is inefficient and not so productive as they have to waste their precious time finding the right tools, not to mention some people even have a hard time finding the right tools. This is where CalcLab will solve the problem as it has all the right tools located at their fingertip, and it is very easy to use. ## Features 1. [Calculator (scientific)](#1-calculator-scientific) 2. [Graph Plotter](#2-graph-plotter) 3. [History](#3-history) 4. [Tools Selection Menu](#4-tools-selection-menu) 5. [Date Comparator](#5-date-comparator) 6. [Currency Converter](#6-currency-converter) 7. [Volume Converter](#7-volume-converter) 8. [Length Converter](#8-length-converter) 9. [Weight and Mass Converter](#9-weight-and-mass-converter) 10. [Temperature Converter](#10-temperature-converter) 11. [Energy Converter](#11-energy-converter) 12. [Area Converter](#12-area-converter) 13. [Speed Converter](#13-speed-converter) 14. [Time Converter](#14-time-converter) 15. [Power Converter](#15-power-converter) 16. [Data Converter](#16-data-converter) 17. [Pressure Converter](#17-pressure-converter) 18. [Angle Converter](#18-angle-converter) ### 1. Calculator (scientific) **Supports:** add, subtract, multiply, divide, percentage, square, cube, square root, cube root, factorial, natural logarithm, common logarithm (base 10), sin, cos, tan, sinh, cosh, tanh, e constant, pi constant ![image](https://user-images.githubusercontent.com/71577909/143985101-fa815096-d885-464a-b129-16246dc6db83.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) and invalid number operations (i.e. dividing by 0) - Auto prevent user from using more than one decimal point - If the result is the same as what is currently displayed (i.e. 4/2 = 2), the display will blink, indicating that the result is updated - Auto conversion to scientific notation when the result is too long - Able to do continuous calculations, no need to press AC (i.e. pressing 5 + 2 x 2 will give out 14) - Result will be automatically stored in [history](#3-history) ### 2. Graph Plotter **Supports:** - Straight line `y=mx+c`, `x=my` - Parabola `y=mx^2+c` - Cubic graph `y=mx^3+c` - Graph of `n` power `y=mx^n+c`; 0 **≤** n **≤** 6 ![plot8ex](https://user-images.githubusercontent.com/71577909/144034842-3af13abf-41ee-426e-adc4-e4ffeb50fb86.png) ![image](https://user-images.githubusercontent.com/71577909/143985456-15214eac-4d89-46d5-bfa1-103bc41108e3.png) User can also type `/undo` to remove the latest plotted line. Examples of supported equation: y=20 x=5.23 y=2x y=-2x+10 y=(1/2)x^2-(100/3) f(x)=-0.03x^2.5+20 y=(1/3)**3x^2+(25/2)**1.3 ### 3. History Everytime user calculates something, it will be stored in a text file `history.txt` which user can view it right from the program. User also has an option to clear all history. ![image](https://user-images.githubusercontent.com/71577909/143897465-2215ddfe-8c28-4fb1-8e18-3a59bed5942f.png) ![image](https://user-images.githubusercontent.com/71577909/143897528-f05970f9-3ba6-413a-b4f7-d3213c29fd17.png) ### 4. Tools Selection Menu When user presses the upper left button, the selection menu will appear. From here, they can select tools they want. ![image](https://user-images.githubusercontent.com/71577909/144091724-d3a348aa-ce73-4ec6-8efd-f5735ddd84aa.png) ### 5. Date Comparator **Supports:** Calculate date difference and output in year, month, week, day, and sum of day. ![image](https://user-images.githubusercontent.com/71577909/143898075-c5290f80-e365-4c8d-9f44-6def21911d9e.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character, invalid date number, not entering date completely) - If the year/month/week/day is 0, it will not be displayed - Suffix (s) is automatically determined - “From” date does not have to be less than “To” date ### 6. Currency Converter **Supports:** BTC, AED, AUD, BRL, CAD, CHF, CLP, CNY, COP, CZK, DKK, EUR, GBP, HKD, HUF, IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SAR, SEK, SGD, THB, TRY, TWD, USD, ZAR The rates are obtained real-time right when press the equal button. ![image](https://user-images.githubusercontent.com/71577909/141669036-b1da7848-668c-4084-a9b7-43a88cae455c.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) - The program will show the current rates, date, and time at the bottom left - The program will show error if the server is not responding ### 7. Volume Converter **Supports:** Milliliters, Cubic centimeters, Liters, Cubic meters, Teaspoons (US), Tablespoons (US), Fluid ounces (US), Cups (US), Pints (US), Quarts (US), Gallons (US), Cubic inches, Cubic feet, Cubic yards, Teaspoons (UK), Tablespoons (UK), Fluid ounces (UK), Pints (UK), Quarts (UK), Gallons (UK), ![image](https://user-images.githubusercontent.com/71577909/141669071-e4b24d8e-47e9-4b27-9589-02c7cf9dd31b.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 8. Length Converter **Supports:** Nanometers, Microns, Millimeters, Centimeters, Meters, Kilometers, Inches, Feet, Yards, Miles, Nautical Miles ![image](https://user-images.githubusercontent.com/71577909/141669101-73342ade-0f5f-417f-b92d-5147f3817dbe.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 9. Weight and Mass Converter **Supports:** Carats, Milligrams, Centigrams, Decigrams, Grams, Dekagrams, Hectogram, Kilograms, Metric tonnes, Ounces, Pounds, Stone, Short tons (US), Long tons (US) ![image](https://user-images.githubusercontent.com/71577909/141669129-2b26b508-123d-4a51-aa3e-dd16ccb9c3bf.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 10. Temperature Converter **Supports:** Celsius, Fahrenheit, Kelvin ![image](https://user-images.githubusercontent.com/71577909/141669144-08d542f9-e393-4ce2-a270-afd4504e5c69.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 11. Energy Converter **Supports:** Electron volts, Joules, Kilojoules, Thermal calories, Food calories, Foot-pounds, British thermal units ![image](https://user-images.githubusercontent.com/71577909/141669166-81a72214-fcf4-4b2e-982d-a7700d201f5e.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 12. Area Converter **Supports:** Square millimeters, Square centimeters, Square meters, Hectares, Square kilometers, Square inches, Square feet, Square yards, Acres, Square miles ![image](https://user-images.githubusercontent.com/71577909/141669183-4f12dcb5-d00f-439b-b69e-fd1e2f9244bd.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 13. Speed Converter **Supports:** Centimeters per second, Meters per second, Kilometers per hour, Feet per second, Miles per hour, Knots, Mach ![image](https://user-images.githubusercontent.com/71577909/141669264-f7f7c564-b137-4e48-9099-02aa310fc4c3.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 14. Time Converter **Supports:** Microseconds, Milliseconds, Seconds, Minutes, Hours, Days, Weeks, Years ![image](https://user-images.githubusercontent.com/71577909/141669281-3528763d-ef47-4c90-af4f-5a6b4da5ccc4.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 15. Power Converter **Supports:** Watts, Kilowats, Horsepower (US), Foot-pounds/minute, BTUs/minute ![image](https://user-images.githubusercontent.com/71577909/141669298-7882f156-c9e7-4c71-8c9d-d26f82dac9d1.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 16. Data Converter **Supports:** Bits, Bytes, Kilobits, Kibibits, Kilobytes, Kibibytes, Megabits, Mebibits, Megabytes, Mebibytes, Gigabits, Gibibits, Gigabytes, Gibibytes, Terabits, Tebibits, Terabytes, Tebibytes, Petabits, Pebibits, Petabytes, Pebibytes, Exabits, Exbibits, Exabytes, Exibytes, Zetabits, Zebibits, Zetabytes, Zebibytes, Yottabit, Yobibits, Yottabyte, Yobibytes ![image](https://user-images.githubusercontent.com/71577909/141669318-80165320-077f-4cc3-a897-0a05cf224dcb.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 17. Pressure Converter **Supports:** Atmospheres, Bars, Kilopascals, Millimeters of mercury, Pascals, Pounds per square inch ![image](https://user-images.githubusercontent.com/71577909/141669350-ea6f27c9-c790-402c-af69-f94ea0cdf0bd.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) ### 18. Angle Converter **Supports:** Degrees, Radians, Gradians ![image](https://user-images.githubusercontent.com/71577909/141669369-f42ca142-d237-47f5-a81d-f3a313de9d93.png) **Other features:** - Auto detect invalid input (i.e. contains non-numeric character) -------------------------------------------------------------------------------- title: "CodeX - Code Collaboration Platform for the Web" description: "Online code collaboration platform featuring real-time coding, cursor sharing, live UI preview, and video chat with integrated Git support—no sign-up required." source: "https://dulapahv.dev/project/codex" -------------------------------------------------------------------------------- # CodeX - Code Collaboration Platform for the Web **CodeX is an online code collaboration platform that enables real-time coding, cursor sharing, live UI preview, and video communication with integrated Git support—no sign-up required.** **✨ Try now at [codex.dulapahv.dev](https://codex.dulapahv.dev/)** > This project is part of the course "COMPSCI4025P Level 4 Individual Project" at the University of Glasgow. For detailed usage instructions and feature documentation, please see the **[User Manual](manual.md)**. ## Features - **Real-time Collaboration** - Code together in real-time with cursor sharing, highlighting, and follow mode - **Shared Terminal** - Execute code and see results together with over 80 supported languages - **Live Preview** - Preview UI changes instantly with loaded libraries like Tailwind CSS, and more - **GitHub Integrated** - Save your work and open files from your repositories - **Shared Notepad** - Take notes together in real-time with rich text and markdown support - **Video & Voice** - Communicate with your team using video and voice chat ## Project Structure The project is organized as a [monorepo](https://en.wikipedia.org/wiki/Monorepo) using [Turborepo](https://turbo.build/repo/docs): ```txt CodeX ├── apps/ # Application packages │ ├── client/ # Frontend Next.js application │ │ ├── public/ # Static assets │ │ ├── src/ # Source code │ │ │ ├── app/ # Next.js app router pages and API routes │ │ │ ├── components/ # React components │ │ │ ├── hooks/ # Custom React hooks │ │ │ └── lib/ # Utility functions and services │ │ └── tests/ # Frontend tests (Playwright) │ └── server/ # Backend Socket.IO server │ ├── src/ # Source code │ │ ├── service/ # Backend services │ │ └── utils/ # Utility functions │ └── tests/ # Backend tests (Jest) ├── docs/ # Documentation assets ├── packages/ # Shared packages │ └── types/ # Shared TypeScript types and interfaces ├── scripts/ # Build and maintenance scripts ├── package.json # Root package.json └── pnpm-workspace.yaml # PNPM workspace configuration ``` ## Prerequisites Before you begin, ensure you have the following installed: - [Node.js](https://nodejs.org/en/) (v18 or higher) - [pnpm](https://pnpm.io) (v6 or higher) If you don't have `pnpm` installed, you can install it globally: ```bash npm install -g pnpm ``` ## Getting Started After checking the [prerequisites](#prerequisites) above, follow these steps to set up the project: 1. **Clone the repository** ```bash git clone https://github.com/dulapahv/CodeX.git cd CodeX ``` 2. **Install dependencies** This will install all dependencies for the frontend and backend applications: ```bash pnpm install ``` > Note: Git hooks will be automatically installed via Husky when running `pnpm install` 3. **Environment setup** Create `apps/client/.env` using the template from `apps/client/.env.example`: ```bash BETTERSTACK_API_KEY= SENTRY_AUTH_TOKEN= GITHUB_CLIENT_SECRET_PROD= GITHUB_CLIENT_SECRET_DEV= SENTRY_SUPPRESS_TURBOPACK_WARNING="1" TURBO_TEAM= TURBO_TOKEN= ``` > Note: This is a personal project and the required API keys and secrets are not publicly shared. For local development, you'll need to set up your own credentials for GitHub OAuth, Sentry, etc. ## Development To start the development server for both the frontend and backend applications: ```bash pnpm dev ``` You can also start them individually: ```bash # Start only the client pnpm --filter client dev # Start only the server pnpm --filter server dev ``` The application will be available at: - Frontend: [http://localhost:3000](http://localhost:3000) - Backend: [http://localhost:3001](http://localhost:3001) ## Test All test commands can be run from both the root directory and their respective workspaces. ### Frontend Test Both the frontend server and the backend server will start automatically. To run the frontend tests: ```bash # In root directory or client workspace pnpm test:client # Run all frontend E2E tests pnpm test:client:ui # Run frontend tests with UI mode pnpm test:client:debug # Debug frontend tests pnpm test:client:report # View frontend test report # Run in client workspace only pnpm --filter client test:client ``` ### Backend Test The backend server will start automatically. To run the backend tests: ```bash # In root directory or server workspace pnpm test:server # Run backend tests against local server pnpm test:server:remote # Run backend tests against remote server pnpm test:server:watch # Run backend tests in watch mode (local server) # Run in server workspace only pnpm --filter server test:server ``` ## Build This project is configured to build both the frontend and backend applications together with caching from Turborepo. To build the entire project: ```bash pnpm build ``` However, you can also build them individually: ```bash # Build frontend pnpm build:client # Build backend pnpm build:server ``` The build artifacts of the frontend will be available in the `apps/client/.next` directory, and the backend will be available in the `apps/server/dist` directory. ## Deployment The project is configured for automatic deployment through Deploy Hooks which trigger after the GitHub Actions CI/CD pipeline completes successfully: - Frontend (client): Automatically deploys to [Vercel](https://vercel.com) - Backend (server): Automatically deploys to [Render](https://render.com) ## Scripts These are the available scripts in the project: ```bash # Development pnpm dev # Start all applications in development mode pnpm build # Build all packages pnpm build:client # Build frontend pnpm build:server # Build backend pnpm clean # Clean all builds, caches, test results, and node_modules # Testing pnpm test:client # Run frontend E2E tests (Playwright) pnpm test:client:ui # Run frontend tests with UI mode pnpm test:client:debug # Debug frontend tests pnpm test:client:report # View frontend test report pnpm test:server # Run backend tests against local server pnpm test:server:remote # Run backend tests against remote server pnpm test:server:watch # Run backend tests in watch mode (local server) # Linting and Formatting pnpm lint:check # Run ESLint checks (frontend only) pnpm lint:fix # Fix ESLint issues (frontend only) pnpm format:check # Check formatting pnpm format:fix # Fix formatting issues ``` You can also run scripts in the specific workspaces > Note: This will not use Turborepo caching ```bash # Frontend specific pnpm --filter client dev pnpm --filter client build pnpm --filter client test:e2e # Backend specific pnpm --filter server dev pnpm --filter server build pnpm --filter server test:socket ``` ## Tech Stack - **Frontend:** - [Next.js](https://nextjs.org) - [TypeScript](https://www.typescriptlang.org) - [Tailwind CSS](https://tailwindcss.com) - [shadcn/ui](https://ui.shadcn.com/) - [Monaco Editor](https://microsoft.github.io/monaco-editor/) (code editor) - [Socket.IO Client](https://socket.io) - [Sandpack](https://sandpack.codesandbox.io/) (live preview) - [MDXEditor](https://mdxeditor.dev/) (notepad) - [simple-peer](https://github.com/feross/simple-peer) (WebRTC) - [React Hook Form](https://react-hook-form.com) + [Zod](https://zod.dev/) - **Backend:** - [Node.js](https://nodejs.org) - [TypeScript](https://www.typescriptlang.org) - [Socket.IO](https://socket.io) (binded to [µWebSockets.js](https://github.com/uNetworking/uWebSockets.js) server) - **Testing:** - [Playwright](https://playwright.dev) (end-to-end testing for frontend) - [Jest](https://jestjs.io) (unit testing for backend) - [CodeQL](https://codeql.github.com/) (security analysis) - **Code Quality:** - [ESLint](https://eslint.org) (static code analysis) - [Prettier](https://prettier.io) (code formatting) - [Husky](https://typicode.github.io/husky/) (git hooks) - [commitlint](https://commitlint.js.org/) (commit message linting) - **Build & DevOps:** - [Turborepo](https://turbo.build/repo/docs) (monorepo build system) - [GitHub Actions](https://github.com/features/actions) (CI/CD) - [Vercel](https://vercel.com) (frontend deployment) - [Render](https://render.com) (backend deployment) - **Monitoring & Analytics:** - [Sentry](https://sentry.io) (error tracking) - [Vercel Analytics](https://vercel.com/docs/analytics) (web analytics) - [Cloudflare Web Analytics](https://developers.cloudflare.com/web-analytics/) (web analytics) - [Better Stack](https://betterstack.com/) (uptime monitoring and status page) - **External Services:** - [Piston](https://github.com/engineer-man/piston) (code execution) - [GitHub REST API](https://docs.github.com/en/rest) (repository management) ## Coding Style We use several tools to maintain code quality: - [ESLint](https://eslint.org/) for static code analysis (frontend only) - [Prettier](https://prettier.io/) for code formatting - [prettier-plugin-sort-imports](https://github.com/trivago/prettier-plugin-sort-imports) for import statement organization - [prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) for Tailwind CSS class sorting (frontend only) - [prettier-plugin-classnames](https://github.com/ony3000/prettier-plugin-classnames) for wrapping long Tailwind CSS class names (frontend only) - [Husky](https://typicode.github.io/husky/) for Git hooks - [lint-staged](https://github.com/okonet/lint-staged) for running checks on staged files - [commitlint](https://commitlint.js.org/) for commit message linting Check and fix code style: ```bash pnpm lint:check # Check ESLint issues pnpm lint:fix # Fix ESLint issues pnpm format:check # Check formatting issues pnpm format:fix # Fix formatting issues ``` ## Contributing Contributions are welcome! To contribute to this project, follow these steps: 1. Create a new branch for your feature: ```bash git checkout -b feat/your-feature-name ``` 2. Commit your changes following **[Conventional Commits](https://conventionalcommits.org/)**: ```bash git commit -m "(): " ``` - ``: Must be one of: - `feat`: New features (e.g., "feat: add user authentication") - `fix`: Bug fixes (e.g., "fix: resolve memory leak") - `docs`: Documentation changes (e.g., "docs: update API guide") - `style`: Code style changes (e.g., "style: fix indentation") - `refactor`: Code refactoring (e.g., "refactor: simplify auth logic") - `perf`: Performance improvements (e.g., "perf: optimize database queries") - `test`: Adding/updating tests (e.g., "test: add unit tests for auth") - `chore`: Routine tasks/maintenance (e.g., "chore: update dependencies") - `ci`: CI/CD changes (e.g., "ci: add GitHub Actions workflow") - `revert`: Revert previous changes (e.g., "revert: remove broken feature")
> For a complete commit message guidelines, see **[Conventional Commits](https://conventionalcommits.org/)**. 3. Push your changes and submit a Pull Request with a description of your changes: ```bash git push origin feat/your-feature-name ``` ## User Manual For detailed usage instructions and feature documentation, please refer to the **[User Manual](manual.md)**. ## License MIT License - see the [LICENSE](LICENSE) file for details. -------------------------------------------------------------------------------- title: "Issho - Plan with friends, faster" description: "Building a real-time collaborative calendar app that eliminates the back-and-forth of scheduling meetups" source: "https://dulapahv.dev/project/issho" -------------------------------------------------------------------------------- # Issho - Plan with friends, faster ✨ **Try now at [issho.dulapahv.dev](https://issho.dulapahv.dev)** Issho (一緒) means "together" in Japanese - and that's exactly what this app is about. It's a real-time collaborative calendar that lets you and your friends visually mark your availability and instantly find the perfect time to meet, without the endless back-and-forth messages or creating yet another account. ## The Problem After finishing my studies in the UK, I had a precious 2-month window to visit family and friends in Thailand before returning to work. I wanted to make every moment count, planning meetups efficiently to see everyone I'd missed. But coordinating was a nightmare: - "Are you free next week?" - "Which days work for you?" - "How about Thursday? Oh wait, someone can't make it..." - *Creates a poll* - *Half the group doesn't respond* - *Repeat for every single meetup* Sound familiar? I was spending more time planning than actually meeting people. There had to be a better way. ## The Solution Issho was born from this frustration. Instead of exchanging dozens of messages, what if everyone could just paint their availability on a shared calendar? No signup, no downloads, just pure simplicity. Here's how it works: 1. **Create a calendar** - Get a unique 8-character ID and 6-digit PIN instantly 2. **Share with friends** - Send them the credentials (one message!) 3. **Everyone marks their availability** - Just click and drag 4. **Find overlaps instantly** - The perfect time reveals itself ## Key Features **Real-time Collaboration** - See updates instantly as friends mark their availability. No refreshing needed. **Smart Analytics** - The app automatically shows you the best meeting windows, individual availability percentages, and when everyone's free. **No Account Required** - Share calendars with just an ID and PIN. Privacy without the hassle of signups. **Mobile-First Design** - Works perfectly on any device with responsive UI and intuitive touch controls. ## Technical Highlights Built with modern web technologies for a seamless experience: - **Next.js 15** for blazing-fast performance - **Supabase Realtime** for instant synchronization - **Prisma + PostgreSQL** for reliable data storage - **Vercel BotID** for invisible bot protection - **React Big Calendar** for familiar, intuitive interface The app features deterministic color generation (same name = same color every time), and automatic cleanup of unused calendars after 90 days. ## Impact Since launching, Issho has helped coordinate many meetups. Users love the simplicity: > "Finally, scheduling that doesn't require 20 messages" > "This app is much easier to use than I expected" The 2 months in Thailand? I managed to see everyone I wanted to, with minimal planning overhead. Issho had already paid for itself. ## Open Source The entire project is [open source on GitHub](https://github.com/dulapahv/Issho) under the Apache-2.0 license. Feel free to explore the code, suggest features, or contribute! --- **Try it yourself at [issho.dulapahv.dev](https://issho.dulapahv.dev)** - no signup required, of course. -------------------------------------------------------------------------------- title: "Kanbaru" description: "Kanban-style project management application provides customizable task organization with visual intuitiveness, date and time options, and detailed descriptions. Users can refine project planning and management with ease." source: "https://dulapahv.dev/project/kanbaru" -------------------------------------------------------------------------------- # Kanbaru Kanbaru is a kanban-style, list-making project management application, built using Python, Qt Designer, and PySide6. Kanbaru helps you organize your projects and tasks in an efficient and effective way. It allows you to visually organize your tasks into columns and quickly move them between columns. Kanbaru is free and open source, released under the MIT license. > A group project for Software Engineering Principle course, KMITL Software Engineering, Year 2, Semester 2. ## Authors ### 👤 Dulapah Vibulsanti (64011388) - Website: [Portfolio](https://dulapahv.dev) - Github: [@dulapahv](https://github.com/dulapahv) - LinkedIn: [@dulapahv](https://linkedin.com/in/dulapahv) ### 👤 Annopdanai Pammarapa (64011337) - Github: [@beam2546](https://github.com/beam2546) - LinkedIn: [@annopdanai](https://linkedin.com/in/annopdanai) ### 👤 Anucha Cheewachanon (64011338) - Github: [@SpiralNuggets](https://github.com/SpiralNuggets) - LinkedIn: [@alphacharlie](https://linkedin.com/in/alphacharlie) ## 🔰Getting Started Kanbaru requires the following libraries, which the application will prompt the user to install if they do not have the required libraries installed already and will automatically install required libraries if user chooses to do so. (Note: If user does not have `pip`, the application will attempt to install using `ensure-pip`). User can also choose to [install automatically](#install-automatically) or [manually](#install-manually). - [PySide6](https://pypi.org/project/PySide6/) at least version `6.4.3` ### Install automatically ```sh pip install -r requirements.txt ``` ### Install manually ```sh pip install PySide6 ``` ### Launching - Run the `kanbaru.py` ```sh python kanbaru.py ``` - To run in debug mode, add `--debug` as the argument ```sh python kanbaru.py --debug ``` ## Using Kanbaru Upon opening a program, you will be greeted by the [main screen](#main-screen). From here, you can view and manage all your boards, panels, and cards, as well as viewing [card description](#card-description) by clicking on it. ## Main Screen ![Main Screen](https://i.imgur.com/YC1M7cA.png) ### Adding Panel To add a panel, click on the `add a panel` button on the upper right. _Note: You cannot enter existing panel title._ ![Adding Panel](https://i.imgur.com/5wQDwXc.png) ### Adding Card To add a card, click on the `add a card` button at the bottom of the panel _Note: You cannot enter existing card title._ ![Adding Card](https://i.imgur.com/5Tmb07C.png) ### Adding Board To add a board, click on the `add a board` button on the bottom left. _Note: You cannot enter existing board title._ ![Adding Board](https://i.imgur.com/IjX0dGB.png) ### Rearranging Card(s) You can select and drag a card to from one panel to another. You can also rearrange multiple cards by selecting multiple cards at once. ![Rearraning Card(s)](https://i.imgur.com/cItouY0.png) ## Card Description From here, you can rename, edit, and delete card. _Note: You cannot rename card into existing card title._ ![Card Description](https://i.imgur.com/P8unhSr.png) ## Board Settings From here, you can rename, rearrange, and delete panel(s). You can also rename the board title here. You can rerrange and delete more than one panel at the same time. _Note: You cannot rename board and panel into their existing title._ ![Board Settings](https://i.imgur.com/vhnFLCs.png) ## App Settings From here you can rearrange and delete board(s). You can also rearrange and delete more than one board at a time. ![App Settings](https://i.imgur.com/dPInIPq.png) ## About Page This page shows the developer as well as the project's [License](#license). This page also hides an easter egg! ![About Page](https://i.imgur.com/ar36qX0.png) ## License Kanbaru is released under the MIT license. See [LICENSE](https://github.com/dulapahv/Kanbaru/blob/main/LICENSE) for more information. -------------------------------------------------------------------------------- title: "LaTeXly" description: "Open-source online LaTeX equation editor with live preview, syntax highlighting, symbol search, and export options. Currently expanding features, including a matrices builder and theme customization." source: "https://dulapahv.dev/project/latexly" -------------------------------------------------------------------------------- # LaTeXly Try now at [latexly.dulapahv.dev](https://latexly.dulapahv.dev). Full source code available on [GitHub](https://github.com/dulapahv/LaTeXly). Mathematical typesetting shouldn't require complex software installations or steep learning curves. **LaTeXly** addresses this by bringing LaTeX equation editing directly to the browser, offering a clean, accessible interface for students, researchers, and educators who need quick access to professional mathematical notation. Currently under active development, LaTeXly represents an ongoing effort to democratize mathematical typesetting through web-based tools. ## The Need for Accessible Math Typesetting Traditional LaTeX editors often present barriers for users who need to create mathematical equations quickly: - **Installation requirements** for desktop LaTeX distributions - **Complex syntax** without immediate visual feedback - **Limited accessibility** for users on different devices or operating systems - **Steep learning curves** for occasional users LaTeXly tackles these challenges by providing an immediate, browser-based solution that makes mathematical typesetting more approachable. ## Current Feature Set The platform offers a focused set of capabilities designed for efficient equation creation: ### Core Functionality - **Equation editor** with real-time LaTeX input - **Syntax highlighting** for improved code readability - **Live preview** showing rendered equations instantly - **Comprehensive symbol support** based on KaTeX's extensive library - **Symbol search** for quick discovery of mathematical notation ### User Experience Features - **Export capabilities** to both image and PDF formats - **Undo/Redo support** for iterative equation development - **Theme flexibility** with light, dark, and system-based options ### Planned Enhancements The development roadmap includes several features currently in progress: - **Matrices builder** for complex mathematical structures - **Equation optimization** tools (prettify and minify functions) - **Example library** covering Chemistry and Physics equations - **Enhanced LaTeX customization** options ## Development Approach LaTeXly follows modern web development practices with an emphasis on accessibility and performance: **Technology Foundation**: Built using contemporary web technologies with a focus on client-side rendering for immediate feedback **Open Source Philosophy**: Released under MIT License, encouraging community contributions and transparency **User-Centric Design**: Prioritizing ease of use without sacrificing the power of LaTeX typesetting ## Current Status and Transparency Development is currently paused due to academic commitments, with active work resuming after final examinations conclude at the end of May. This temporary hiatus reflects the reality of balancing personal projects with academic responsibilities. Despite being in active development, the core functionality is operational and available for testing at [latexly.dulapahv.dev](https://latexly.dulapahv.dev). ## Target Applications LaTeXly serves several key use cases: - **Academic writing** requiring mathematical notation - **Educational contexts** where students need quick equation creation - **Research documentation** with mathematical expressions - **Web publishing** requiring embedded mathematical content ## Technical Accessibility The browser-based approach eliminates common barriers: - **No installation required** - immediate access through any modern browser - **Cross-platform compatibility** across operating systems - **Immediate feedback** through live preview functionality - **Symbol discovery** through searchable interface ## Future Vision While currently focused on core equation editing capabilities, LaTeXly aims to become a comprehensive mathematical typesetting solution that maintains simplicity while expanding functionality based on user feedback and community contributions. The complete source code is available on [GitHub](https://github.com/dulapahv/LaTeXly), welcoming contributions from the mathematical and development communities. --- _LaTeXly represents an ongoing effort to make mathematical typesetting more accessible, demonstrating how web technologies can lower barriers to professional-quality mathematical notation._ -------------------------------------------------------------------------------- title: "Matrix-Arithmetic" description: "Feature-packed matrix arithmetic program that operates within the terminal. This tool encompasses addition, subtraction, multiplication, scalar multiplication, exponentiation, determinant computation, transposition, inversion, and adjoint matrix operations." source: "https://dulapahv.dev/project/matrix-arithmetic" -------------------------------------------------------------------------------- # Matrix-Arithmetic An individual project for C Programing Lecture, KMITL Software Engineering, Year 1, Semester 1 ## Project Description This project aims to create a matrix computing program that runs in the terminal. The key features are: 1. Wide variety of operations - Addition - Subtraction - Multiplication - Scalar Multiplication - Exponentiation - Determinant - Transposition - Inverse - Adjoint \*Program will also automatically detect matrix compatibility when performing certain operations. 2. User can choose to input matrix through terminal/command line or from an `input.txt` and `input.csv` file with a user-specifiable delimiter. 3. Answer is automatically output in the `output.txt` file with proper matrix brackets and also generates LaTeX code for the user. The program also outputs answers in the `output.csv` file as a comma-separated value. 4. Answer is automatically stored in `Matrix Answer` so that it can be used to compute or perform further operations later on. 5. User can view each stored matrix value ## Demo ### Defining matrix through terminal/command line and through file (_input.txt_ or _input.csv_) 1. Select `Define Matrix` ![image](https://user-images.githubusercontent.com/71577909/137595788-c4753f78-7b63-49bd-b62e-ee2c5236d20d.png) 2. Select a matrix to define. ![image](https://user-images.githubusercontent.com/71577909/137517087-dfb09958-4781-4666-8b7a-c0cdcb9c9e91.png) To input through the terminal/command line, select the first option. Then specify `rows` and `columns` and `value` of your matrix. ![image](https://user-images.githubusercontent.com/71577909/137595905-d4797eeb-1a7a-447c-9cf0-aba09a64453d.png) To input through a file, select the second option. Make sure there is only 1 input file named `input.txt` or `input.csv` in the program's directory. Then specify the delimiter and the program will automatically preview the matrix it reads from as well as defining it. \*_Maximum dimensions for reading matrix from a file is 100 x 100 with a maximum of 255 characters per delimiter (delimiter cannot contain `.` character as it will be determined as a decimal point instead)_ Suppose we have a file containing comma-separated values ![image](https://user-images.githubusercontent.com/71577909/137518709-9312f2ee-2540-4056-a50b-dc26431b66e4.png) We just specify the delimiter as a `,` and simply press enter. ![image](https://user-images.githubusercontent.com/71577909/137518814-3051b28a-15cc-41d9-851a-b9f5868095df.png) ### Viewing stored matrix 1. Select `View Matrix` ![image](https://user-images.githubusercontent.com/71577909/137595788-c4753f78-7b63-49bd-b62e-ee2c5236d20d.png) 2. Select a matrix to view and the value of that matrix will appear. ![image](https://user-images.githubusercontent.com/71577909/137520627-5dbf0bcd-f113-4a5d-aecb-ef159dce897e.png) ### Performing arithmetic 1. Select `Compute Matrix` ![image](https://user-images.githubusercontent.com/71577909/137595788-c4753f78-7b63-49bd-b62e-ee2c5236d20d.png) 2. Select an operation you would like to perform. ![image](https://user-images.githubusercontent.com/71577909/137595820-60ae7521-b5d7-4696-aa7a-dbce8199747b.png) 3. Suppose we select `Addition`, then we just select 2 matrixes to be added together and the result will appear. After pressing any key to continue, the result will be outputted into `output.txt` and `output.csv` which we will take a look [here](#looking-at-output-files). \*_Answer is automatically stored in `Matrix Answer` so that it can be used to compute or perform further operations later on._ ![image](https://user-images.githubusercontent.com/71577909/137521209-aabd5fe7-b44e-4891-9562-a4487c46b74c.png) ### Looking at output files In the `output.txt`, there will be an answer with proper matrix brackets and a generated LaTeX code for the answer. ![image](https://user-images.githubusercontent.com/71577909/137522513-86dfe040-dbd7-4590-b420-6d5088fa8e94.png) In the `output.csv`, there will be a comma-separated answer. The `output.csv` file is separated so that it can be imported into other programs right away. ![image](https://user-images.githubusercontent.com/71577909/137522612-0b0b6dcd-2a3c-49f1-8133-d625f9393e5b.png) ## Testing Scheme Suppose `matrix A` is 4 7 2 6 ### First Test (Adding and Subtracting) Adding `matrix A` together must give out 8 14 4 12 And subtracting the sum of `matrix A` with `matrix A` must give out the original value of `matrix A` 4 7 2 6 ### Second Test (Multiplying and Inverse) Finding the inverse of `matrix A` must give out 0.60 -0.70 -0.20 0.40 And multiplying the the inverse of `matrix A` with `matrix A` must give out `identity matrix` 1 0 0 1 ### Third Test (Determinant and Adjoint) Finding the determinant of `matrix A` must give out 10 Finding adjoint of `matrix A` must give out 6 -7 -2 4 Multiplying `1/det(A)` with the adjoint of `matrix A` must give out the inverse of `matrix A` 0.60 -0.70 -0.20 0.40 ### Fourth Test (Error Messages) Suppose `matrix B` is 1 2 3 4 5 6 7 8 9 Adding/subtracting/multiplying `matrix A` with `matrix B` must give out _incompatible matrix dimension error_ Incompatible matrix dimension! Finding determinant/inverse of a matrix with unequal row and column must give out _unequal matrix dimension error_ Matrix dimension must be equal! Finding the inverse of `matrix B` must give out _det equal 0 error_ because an inverse of a matrix with _det = 0_ does not exist (_singular matrix_) Cannot find inverse of singular matrix! Reading matrix from empty input file must give out _input file is empty error_ Input file is empty! Deleting `input.txt` or `input.csv` and reading matrix from it must give out _error accessing input file error_ Error accessing input file! Setting `output.txt` or `output.csv` to _read-only_ and outputting matrix to it must give out _error accessing output file error_ Error accessing output file! -------------------------------------------------------------------------------- title: "Map File Preparation Application (MFPA)" description: "Web application to identify files with geographic content that intersect or are contained within an area defined by the user, developed for defense systems company Thales UK." source: "https://dulapahv.dev/project/mfpa" -------------------------------------------------------------------------------- # Map File Preparation Application (MFPA) **Map File Preparation Application**: Explore and analyze your map data like never before. Import layers, draw boundaries by hand or coordinates, and instantly discover which layers lie within. Uncover hidden insights and relationships with ease! View the presentation [here](https://assets.dulapahv.dev/MFPA_ppt.pdf). ## 🛠 Built With ### Tech Stack
Client
  • [Electron.js](https://electronjs.org/)
  • [Next.js](https://nextjs.org/)
  • [Tailwind CSS](https://tailwindcss.com/)
  • [NextUI](https://nextui.org/)
  • [daisyUI](https://daisyui.com/)
Server
  • [Vercel](https://vercel.com/)
Database
  • [SQLite](https://sqlite.org/)
### Key Features - **Dynamic Layer Management** - **Intuitive Boundary Creation** - **Instant layer visibility** ## 🚀 Try It Out! According to the order of development time, there are three release versions of software available for running. You can see the features of each release version and try it as needed. - [Releases](https://github.com/tuckers1967/MFPA/releases) ## 💻 Getting Started To get a local copy up and running, follow these steps. ### Setup Clone this repository to your desired folder: ```sh git git@github.com:tuckers1967/MFPA.git ``` ### Install Install dependencies with: ```sh yarn install ``` or ```sh npm i ``` ### Usage To run the project, execute the following command: ```sh yarn dev ``` or ```sh npm run dev ``` ### Building Executable You can build an executable using: ```sh yarn make ``` or ```sh npm run make ``` ### Building Static Export Before building a static export, you have to uncomment these script in `next.config.js` located in the root folder. ```js /** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', distDir: 'build', images: { unoptimized: true, }, }; module.exports = nextConfig; ``` Then you can build a static export using: ```sh yarn build ``` or ```sh npm run build ``` - The default output directory will be in the `./build` directory ## 👥 Authors 👤 **Dulapah Vibulsanti (2920990v)** - Scrum Master, Developer - GitHub: [@dulapahv](https://github.com/githubhandle) - LinkedIn: [@LinkedIn](https://linkedin.com/in/dulapahv) - Email: 2920990v@student.gla.ac.uk 👤 **Mahnun Saratunti (2914049s)** - Product Owner, Developer - GitHub: [@mahnun](https://github.com/githubhandle) - LinkedIn: [LinkedIn](https://linkedin.com/in/linkedinhandle) - Email: 2914049s@student.gla.ac.uk 👤 **Bin Zhang (2941833z)** - Developer - GitHub: [@bin](https://github.com/BradyZzzZ) - LinkedIn: [@LinkedIn](https://www.linkedin.com/in/bin-zhang-304171293/) - Email: 2941833z@student.gla.ac.uk 👤 **Luowan Xu (2710660x)** - Developer - GitHub: [@luowan](https://github.com/githubhandle) - LinkedIn: [@LinkedIn](https://linkedin.com/in/linkedinhandle) - Email: 2710660x@student.gla.ac.uk 👤 **Reuben Spivey (2664429s)** - Note Taker, Developer - GitHub: [@reuben](https://github.com/githubhandle) - LinkedIn: [@LinkedIn](https://linkedin.com/in/linkedinhandle) - Email: 2664429s@student.gla.ac.uk 👤 **Zofia Bochenek (2580917b)** - Developer - GitHub: [@zofia](https://github.com/githubhandle) - LinkedIn: [@LinkedIn](https://linkedin.com/in/linkedinhandle) - Email: 2580917b@student.gla.ac.uk ## 📝 License This project is [MIT](./LICENSE) licensed. ## 📚 Project Documentation This is a detailed project [documentation](https://sh21-x-thales-uk.gitbook.io/docs/) powered by GitBook. ## ❓ FAQ and Additional Support If you have any problems or need additional help during use, please feel free to contact us by email. Find our university email in [Authors](#authors) page. -------------------------------------------------------------------------------- title: "MyStudyPlan" description: "Comprehensive academic tracking application offers a centralized dashboard for efficient viewing of class assignments, tasks, and exams. Users can access a calendar view option, streamlining academic planning and management." source: "https://dulapahv.dev/project/mystudyplan" -------------------------------------------------------------------------------- # MyStudyPlan MyStudyPlan is an app that enables you to track all your classes, tasks, assignments and exams - anywhere! > A group project for Advanced Object-Oriented Programming course, KMITL Software Engineering, Year 2, Semester 1. ## Authors 👤 **Annopdanai Pammarapa** (64011337) - Github: [@beam2546](https://github.com/beam2546) - LinkedIn: [@annopdanai](https://linkedin.com/in/annopdanai) 👤 **Anucha Cheewachanon** (64011338) - Github: [@SpiralNuggets](https://github.com/SpiralNuggets) - LinkedIn: [@alphacharlie](https://linkedin.com/in/alphacharlie) 👤 **Dulapah Vibulsanti** (64011388) - Website: [Portfolio](https://dulapahv.github.io) - Github: [@dulapahv](https://github.com/dulapahv) - LinkedIn: [@dulapahv](https://linkedin.com/in/dulapahv) ## Getting Started ### Prerequisites - A [JDK](https://java.com/download) (or [OpenJDK](https://adoptium.net/)), available from your local Oracle website or your package manager of your choice. - [Maven](https://maven.apache.org/) ### Building - Run `make build` from the project root directory. - Optionally, you can run `make all` to build and then launch the app. ### Launching - Run `make run` to launch the app. - If you're using Windows, you can run `MyStudyPlan.exe`. ### Cleaning - Run `make clean` to remove all build artifacts. ## Using MyStudyPlan Upon opening a program, you will be greeted by the login page. From here, you can login or register. You only have to log in once. ![Login page](https://raw.githubusercontent.com/dulapahv/MyStudyPlan/main/Screenshots/Login.png) After logging in or registering, you will go to the Overview page. This is where you will get a summary view of your schedule, tasks, and exams. You also have an option to add new schedule, tasks, and exams here too. ![Overview page](https://raw.githubusercontent.com/dulapahv/MyStudyPlan/main/Screenshots/Overview.png) On the left panel, there are: 1. Overview 2. Calendar 3. Tasks 4. Exams 5. Schedule 6. Logout ### Calendar page In this page you can select the day from the calendar on the left and the class, tasks, and exams on the corresponding date will appear on the right. - You can also use the search bar to search for schedule, tasks, and exams. ![Calendar page](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Calendar.png) ### Tasks page - In this page, you can view all the tasks. The tasks are separated into - Assignment - Reminder - Revision - You can also use the search bar to search for tasks. - You can create a new task by pressing the `+New Task` button on the upper right and a popup will appear. (See [Adding task](#adding-task)) ![Tasks page](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Tasks.png) #### Adding task In this page you can add a task. - You can also press the `+` button to add subject. (See [Managing Subjects](#managing-subjects)) > Title is required to create a task. ![New Task popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/New_Task.png) ### Exams page In this page, you can view all the exams. - You can also use the search bar to search for exams. - You can create a new exam by pressing the `+New Exam` button on the upper right and a popup will appear. (See [Adding exam](#adding-exam)) ![Exams page](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Exams.png) #### Adding exam In this page you can add an exam. - The app will also tell you the ending date and time for the specified time and duration. - You can also press the `+` button to add subject. (See [Managing Subjects](#managing-subjects)) ![New Exam popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/New_Exam.png) ### Schedule page In this page, you can view all the schedule. - You can also use the search bar to search for schedule. - You can create a new class by pressing the `+New Class` button on the upper right and a popup will appear. (See [Adding class](#adding-class)) - You can also manage the subjects by pressing the `Manage Subjects`. (See [Managing subjects](#managing-subjects)) ![Schedule page](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Schedule.png) #### Adding class In this page you can add a class. - You can also press the `+` button to add subject. (See [Managing Subjects](#managing-subjects)) ![New Class popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/New_Class.png) #### Managing subjects In this page, you can manage all the subjects. - To add a subject, fill in the Code, Subject, and Color and press the `+` button. - To remove a subject, click on the subject you want to remove from the list, then press `-` button. - You can also use the search bar to search for subjects. > Code, Subject, and Color is required to create a subject. ![Manage Subjects popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Manage_Subjects.png) - You can put in the hex color code and press enter, or select from a color palette. ![Color Palette chooser](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/Color_Palette.png) ### Viewing information You can view more information of each class, tasks, and exams by clicking on the label and a popup will appear. - In this page, you will not be allowed to edit any information. ![View Class popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/View_Class.png) ![View Task popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/View_Task.png) ![View Exam popup](https://github.com/dulapahv/MyStudyPlan/raw/main/Screenshots/View_Exam.png) #### Marking as done Pressing the `Mark as done` button in [viewing information](#viewing-information) popup will remove it from the list. #### Deleting Pressing the `Delete` button in [viewing information](#viewing-information) popup will delete it from the list. ## License MyStudyPlan is released under the [MIT license](https://github.com/dulapahv/MyStudyPlan/blob/main/LICENSE). -------------------------------------------------------------------------------- title: "Nekoparaiten" description: "April Fool's Day online speed-clicking game written in Python. Click as fast as possible while also competing with other people around the world! Nekoparaiten is an anime Neko romance simulation mobile game originally created by Sayori (NEKO WORKs) and developed by Yostar Games." source: "https://dulapahv.dev/project/nekoparaiten" -------------------------------------------------------------------------------- # Nekoparaiten Nekoparaiten is an anime Neko romance simulation mobile game originally created by Sayori (NEKO WORKs) and developed by Yostar Games. This is ONLY an April Fool's joke for my friend which includes a [website](https://nekoparaiten.github.io/) and a [game](https://github.com/DulapahV/Nekoparaiten). ## Download - [Release page](https://github.com/DulapahV/Nekoparaiten/releases) ## Running a Game - Simply open `nekoparaiten.exe`, no need to install any library dependencies! - Or compile `nekoparaiten.py` (the missing library dependencies will be automatically installed for you) ## Game Description Nekoparaiten (April Fool's) is an online speed-clicking game written in Python. The goal is to click as fast as possible while also competing with other people around the world! The key features are: 1. Featuring catgirl characters and voice lines from a famous franchise Nekopara! 2. Online account synchronization with built-in sign-up/login account feature 3. Online leaderboard system 4. Players can log in to view their profile stats and sync their progress anywhere/anytime in the world 5. Can also be played offline! ## Demo ### Main Menu ![Main Menu](https://github.com/DulapahV/Nekoparaiten/blob/main/images/mainmenu.png?raw=true) ### Sync Here you can **Sign Up** or **Login** and then the player database will be stored in an online database. ![Sync](https://github.com/DulapahV/Nekoparaiten/blob/main/images/sync.png?raw=true) Here player can also see how many times they have played the game. The online database hierarchy is the following. ![database](https://github.com/DulapahV/Nekoparaiten/blob/main/images/db.png?raw=true) ### Story Once you select `GAME START` at the [Main Menu](#main-menu), the game story will begin. ![story](https://github.com/DulapahV/Nekoparaiten/blob/main/images/story.png?raw=true) ### Instruction ![instruction](https://github.com/DulapahV/Nekoparaiten/blob/main/images/instruction.png?raw=true) ### Countdown ![countdown](https://github.com/DulapahV/Nekoparaiten/blob/main/images/countdown.png?raw=true) ### Game ![game](https://github.com/DulapahV/Nekoparaiten/blob/main/images/game.png?raw=true) ### Pause When you pause, the timer stop and you will not be able to click. The timer will restart and you will able to click again after closing the dialog. ![pause](https://github.com/DulapahV/Nekoparaiten/blob/main/images/pause.png?raw=true) ### Finish If you have not login, the finish screen will display `Login to save your progress!`. ![finish1](https://github.com/DulapahV/Nekoparaiten/blob/main/images/finish1.png?raw=true) If you have login and made a new personal record, the finish screen will display `New Record!`. ![finish2new](https://github.com/DulapahV/Nekoparaiten/blob/main/images/finish2new.png?raw=true) Otherwise, `Your progress has been saved!` ![finish2](https://github.com/DulapahV/Nekoparaiten/blob/main/images/finish2.png?raw=true) ### Leaderboard ![leaderboard](https://github.com/DulapahV/Nekoparaiten/blob/main/images/leaderboard.png?raw=true) Players can also press the `refresh` button on the upper-right corner to refresh the leaderboard. ## Debug You must sign out from your account first before doing these debugs as it will create unfairness between players. ### Changing Assets Folder Path If you wish to move the `assets` folder to other location, change the following setting. 1. Navigate to `//assets` 2. Open `data.txt` 3. Change `dataPath = assets` to `dataPath = [new location]` ### Changing Countdown Timer If you wish to change the countdown timer from the default of `5` seconds, change the following setting. 1. Navigate to `//assets` 2. Open `data.txt` 3. Change `countdownTimer = 5` to `countdownTimer = [integer]` ### Changing Goal If you wish to change the goal of the game from 100 clicks, change the following setting. 1. Navigate to `//assets` 2. Open `data.txt` 3. Change `targetScore = 100` to `targetScore = [integer]` ### Changing Amount Of Displayed Leaderboard If you wish to change the amount of displayed leaderboard from the default of `10`, change the following setting. 1. Navigate to `//assets` 2. Open `data.txt` 3. Change `scoreboardLimit = 10` to `scoreboardLimit = [integer]` ================================================================================ SECTION: Work Description: Companies and clients I've worked with. URL: https://dulapahv.dev/work ================================================================================ -------------------------------------------------------------------------------- title: "Full-Stack Developer Intern at Geo-Informatics and Space Technology Development Agency (GISTDA)" description: "Bangkok, Thailand" source: "https://dulapahv.dev/work/gistda-full-stack-developer-intern" -------------------------------------------------------------------------------- # Full-Stack Developer Intern at Geo-Informatics and Space Technology Development Agency (GISTDA) My internship at GISTDA focused on developing geospatial analysis tools for agricultural monitoring and fire prevention. Working with satellite data and mapping technologies, I built full-stack solutions that helped government authorities make data-driven decisions about crop residue burning incidents. ## Core Project: Agricultural Fire Analysis Platform Developed a comprehensive web application that analyzed spatial correlations between crop cultivation patterns and crop residue burning incidents. This tool provided government agencies and authorities with actionable insights for fire prevention and mitigation strategies. The platform processed geospatial data to identify patterns and hotspots, enabling proactive rather than reactive approaches to agricultural fire management. ## Technical Contributions ### Frontend Development Built the user interface using React.js and Tailwind CSS, creating intuitive data visualization components for complex geospatial information. The interface needed to make satellite data and spatial analysis accessible to non-technical government users. ### API Integration and Development Pioneered the integration of GISTDA's proprietary Sphere API Map into a React.js application as a reusable component. This work provided the public with access to example implementations and demos, expanding the reach of GISTDA's mapping technologies. Designed and developed a dynamic API system capable of executing flexible URL queries while implementing robust SQL injection protection. This security focus was critical given the sensitive nature of agricultural and environmental data. ### Infrastructure and Deployment Implemented NGINX reverse proxy deployment to enable external URL connections to internal servers. This configuration seamlessly served both the website and its associated API, optimizing user experience while maintaining security protocols. ## Challenges and Solutions **Geospatial Data Complexity**: Working with satellite data and spatial analysis required understanding both technical implementation and domain-specific agricultural patterns. Close collaboration with GISTDA researchers was essential for accurate analysis. **Government User Requirements**: Building tools for government decision-makers meant prioritizing data clarity and actionable insights over technical complexity. The interface needed to communicate complex spatial relationships simply. **Security and Access**: Balancing public access to mapping tools with protection of sensitive agricultural data required careful API design and access control implementation. ## Impact and Applications The spatial correlation analysis provided authorities with unprecedented visibility into agricultural fire patterns. By identifying relationships between crop cultivation and burning incidents, the platform enabled targeted prevention strategies rather than reactive responses. The reusable Sphere API Map component expanded GISTDA's public engagement, providing developers and researchers with practical examples of geospatial technology implementation. ## Technical Learning This internship provided hands-on experience with geospatial technologies and government-scale data processing. Working with PostgreSQL for spatial data storage and Python for analysis expanded my understanding of full-stack development beyond traditional web applications. The experience highlighted how technology can directly support environmental protection and agricultural policy, demonstrating the broader impact of software development in addressing real-world challenges. GISTDA's focus on satellite technology and spatial analysis provided unique insights into how government agencies leverage data for environmental monitoring and decision-making. -------------------------------------------------------------------------------- title: "Front-End Developer at King Mongkut's Institute of Technology Ladkrabang (KMITL)" description: "Bangkok, Thailand" source: "https://dulapahv.dev/work/kmitl-frontend-developer" -------------------------------------------------------------------------------- # Front-End Developer at King Mongkut's Institute of Technology Ladkrabang (KMITL) Working as a Front-End Developer at KMITL allowed me to contribute directly to educational technology while developing a comprehensive web platform for course pre-registration. This role bridged my academic experience with practical software development in a university environment. ## Project Overview The main project involved creating a university website that streamlined course pre-registration for prospective students across different academic levels - high school students exploring options, undergraduates planning transfers, and graduate students seeking advanced courses. This platform addressed a real institutional need by simplifying the traditionally complex process of course credit evaluation and transfer planning. ## Technical Implementation ### User Interface Development Built the frontend using Next.js and TypeScript, leveraging Tailwind CSS for styling and NextUI for component consistency. The focus was creating an intuitive user experience that could accommodate users with varying technical backgrounds. The interface needed to handle complex academic data while remaining accessible to high school students who might be unfamiliar with university systems. ### Admin Dashboard Developed an administrative console featuring Chart.js visualizations for platform management. This dashboard provided university staff with insights into registration patterns, popular courses, and user engagement metrics. The admin interface became crucial for understanding how students interacted with the pre-registration system and identifying areas for improvement. ### Authentication and Security Implemented a comprehensive authentication system including email verification and Cloudflare Turnstile CAPTCHA integration. The token-based session management eliminated repetitive login requirements while maintaining security standards appropriate for educational data. Security considerations were particularly important given the sensitive nature of student academic information and future planning data. ## Performance Optimization ### Component Architecture Introduced reusable component patterns that significantly improved both development efficiency and runtime performance. This modular approach reduced load times and made the codebase more maintainable for future developers. The component library approach proved especially valuable as the platform expanded to serve different user types with overlapping but distinct needs. ### User Experience Impact The performance improvements translated into measurable user experience benefits. Faster load times were particularly important for mobile users and those with limited internet connectivity - common scenarios in educational settings. ## Challenges and Solutions **Complex Academic Requirements**: University course systems involve intricate prerequisites, credit calculations, and transfer policies. Translating these academic rules into clear user interfaces required close collaboration with academic advisors. **Multi-user Needs**: Serving high school students, current undergraduates, and graduate students meant designing flexible interfaces that could adapt to different knowledge levels and use cases. **Scalability Planning**: As a university platform, the system needed to handle peak usage during registration periods while remaining responsive during normal operations. ## Educational Impact The platform streamlined a process that previously required multiple in-person visits and manual paperwork. Students could explore course options, understand credit transfer implications, and make informed decisions about their academic paths. For the university, the system provided valuable data about student interests and demand patterns, informing course planning and resource allocation decisions. ## Technical Growth Working in an educational technology context highlighted the importance of user-centered design. Academic systems often prioritize functionality over usability, but this project demonstrated how thoughtful frontend development could make complex processes accessible. The experience reinforced how technical solutions can directly impact educational outcomes by removing barriers to student planning and decision-making. This role provided practical experience in building production systems while contributing to educational accessibility - a combination that strengthened both my technical skills and understanding of technology's role in education. -------------------------------------------------------------------------------- title: "Teaching Assistant (C/C++) at King Mongkut's Institute of Technology Ladkrabang (KMITL)" description: "Bangkok, Thailand" source: "https://dulapahv.dev/work/kmitl-teaching-assistant-c-cpp" -------------------------------------------------------------------------------- # Teaching Assistant (C/C++) at King Mongkut's Institute of Technology Ladkrabang (KMITL) As a Teaching Assistant for C and C++ programming courses at KMITL, I guided first-year students through fundamental programming concepts while developing my own teaching and mentorship skills. ## Teaching Responsibilities ### Lab Session Management Supervised lab sessions for 50-60 first-year students, providing hands-on technical assistance with C and C++ programming challenges. These sessions focused on practical application of programming concepts, debugging techniques, and problem-solving approaches. The large class size required efficient time management and the ability to quickly diagnose common programming errors while providing personalized guidance. ### Student Assessment Evaluated homework assignments, lab exercises, and examination papers, providing comprehensive feedback to help students improve their programming skills. This assessment work contributed directly to students' technical proficiency and academic progress. Feedback focused not just on correctness but on coding style, efficiency, and understanding of underlying concepts. ## Student Support ### Technical Guidance Provided both in-lab support and additional assistance outside regular hours, helping students overcome programming challenges and understand complex concepts. Many first-year students were encountering programming for the first time, requiring patient explanation of fundamental concepts. ### Skill Development Helped students develop debugging skills, proper coding practices, and logical thinking approaches essential for programming success. These foundational skills proved crucial for their continued studies in software engineering. ## Teaching Impact Working with 50-60 students per cohort provided insights into different learning styles and common programming misconceptions. This experience improved my ability to explain technical concepts clearly and adapt explanations to individual student needs. The role reinforced the importance of practical, hands-on learning in programming education, where students learn best through doing rather than just theory. ## Professional Development Teaching programming to beginners strengthened my own understanding of C and C++ fundamentals while developing communication and mentorship skills valuable for future collaborative work environments. The experience of managing large groups and providing individual guidance proved excellent preparation for technical leadership roles. -------------------------------------------------------------------------------- title: "Teaching Assistant (Rust) at King Mongkut's Institute of Technology Ladkrabang (KMITL)" description: "Bangkok, Thailand" source: "https://dulapahv.dev/work/kmitl-teaching-assistant-rust" -------------------------------------------------------------------------------- # Teaching Assistant (Rust) at King Mongkut's Institute of Technology Ladkrabang (KMITL) Served as a Teaching Assistant for Rust programming courses, guiding 50-60 first-year students through systems programming concepts and Rust's unique ownership model. ## Teaching Focus ### Rust Fundamentals Supervised lab sessions covering Rust's core concepts including ownership, borrowing, and lifetimes. These concepts proved challenging for students new to systems programming, requiring clear explanations and practical examples. Helped students understand Rust's memory safety guarantees and how they differ from traditional programming languages like C and C++. ### Lab Management Facilitated hands-on programming sessions where students worked through Rust exercises and projects. The language's strict compiler provided immediate feedback, which became a valuable teaching tool for demonstrating proper programming practices. ## Student Assessment Evaluated homework submissions, lab assignments, and examination papers, focusing on both code correctness and understanding of Rust's ownership principles. Provided detailed feedback to help students grasp the language's unique approach to memory management. ## Unique Challenges Teaching Rust to first-year students presented distinct challenges compared to traditional programming languages. The ownership system and borrow checker required students to think differently about memory management from the start. This experience improved my ability to break down complex programming concepts and explain Rust's safety features in accessible terms. ## Impact Working with Rust strengthened my own understanding of systems programming principles while developing skills in explaining advanced concepts to programming beginners. The role demonstrated how modern languages can teach good programming habits from the foundation level. -------------------------------------------------------------------------------- title: "Graduate Software Engineer at NatWest Group" description: "Edinburgh, United Kingdom" source: "https://dulapahv.dev/work/natwest-group-software-engineer-graduate" -------------------------------------------------------------------------------- # Graduate Software Engineer at NatWest Group > [!Note] > Stay tuned for more details about this exciting opportunity! -------------------------------------------------------------------------------- title: "Software Engineer Intern at NatWest Group" description: "Edinburgh, United Kingdom" source: "https://dulapahv.dev/work/natwest-group-software-engineer-intern" -------------------------------------------------------------------------------- # Software Engineer Intern at NatWest Group My summer internship at NatWest Group provided hands-on experience in enterprise software development within one of the UK's largest banking institutions. Working across multiple projects, I contributed to frontend development, automation, and data analysis initiatives. ## Key Projects and Contributions ### UI Boilerplate Development I built a comprehensive React.js boilerplate for the bank's web applications, including forms with TanStack integration, landing page components, and API hooks. This template became a foundation for other development teams, enabling them to quickly develop websites using the boilerplate as a starting point and ensuring consistency across applications. ### Release Automation One of my significant contributions was developing automation for the Schedule of Events (SoE) process. Previously, developers manually coordinated application releases, which was time-consuming and error-prone. I created a Bash script and GitLab CI/CD pipelines that automated release scheduling, significantly reducing manual overhead for development teams. This automation streamlined the entire release coordination process. ### Data Analysis and Integration I analyzed and integrated open-source data from government platforms like GOV.UK and ONS with internal banking datasets. This work involved data cleaning, correlation analysis, and generating actionable insights for business stakeholders. The challenge was reconciling different data formats while extracting meaningful patterns that could inform business decisions. The comprehensive findings and recommendations provided valuable intelligence for the bank. ### Java Validation Features For the "Consent to Let" project, I led the implementation of key validation features in Java. This included defining comprehensive testing criteria, developing validation logic, and creating test classes to ensure seamless integration within the user journey for mortgage applications. ## Technical Environment Working at NatWest exposed me to enterprise-scale development practices. The technology stack included React.js, Python, Express.js, MongoDB, and Java, with GitLab managing CI/CD workflows. The scale and security requirements in banking present unique challenges. Every code change undergoes rigorous review processes, and compliance considerations significantly influence technical decisions. ## Challenges and Learnings **Enterprise Complexity**: Banking software operates under strict regulatory requirements, making seemingly simple features complex to implement. Understanding these constraints early proved crucial for successful delivery. **Cross-team Collaboration**: Working with multiple development teams highlighted the importance of clear documentation and standardized practices. The UI boilerplate project succeeded because it addressed real pain points experienced across teams. **Data Quality**: Integrating external datasets revealed how data inconsistencies compound in large systems. Robust validation and error handling became essential skills for reliable data processing. ## Impact and Reflection The internship demonstrated how technology drives efficiency in traditional industries. The automated release scheduling alone saved hours of manual work weekly across multiple teams, while the UI boilerplate accelerated development cycles. While the banking sector moves more cautiously than startups, this conservative approach ensures system reliability when handling customer finances. The experience provided valuable perspective on balancing innovation with stability requirements. The projects I contributed to continued beyond my internship, with other developers building upon the established foundations. This reinforced the importance of writing maintainable, well-documented solutions that can evolve over time. Working at NatWest strengthened my understanding of full-stack development in regulated environments and demonstrated how thoughtful automation can significantly improve developer productivity while maintaining the high standards required in financial services.