Skip to content
Rain Zhang
Full-Stack Developer · Simon Fraser University · Vancouver, BC, Canada

I build and maintain web applications, from design to production.

I’m Rain, a fourth-year computer science student at SFU. Over the past year I’ve built and maintained software for a security-key company and a property management company. I work mostly in Python, TypeScript and Rust.

Resume

Experience

  • Aug 2026 – Present

    MNT Realty

    MNT Realty · Vancouver, BC, Canada

    I’m responsible for software and IT at a property and strata management company. I work with staff to understand what the office needs, then build and maintain the internal systems they use, connected to the company’s Microsoft 365 accounts and data.

    Work
    • Planned and rebuilt the MNT Realty platform from scratch as one application for three sites: a public website, an owner portal for residents, and an admin console for staff.
    • Designed and built MNT Control Center, an internal platform in Next.js, Node.js and PostgreSQL that replaces the separate tools the office used before.
    • Set up organization sign-in and role-based access with Microsoft Entra ID, the Graph API and OAuth 2.0.
    • Automated the recurring office tasks that took staff the most time: sorting incoming email, looking up owner information, and answering staff questions from company documents with an internal assistant.
    Operations
    • Manage hosting, deployment, domains and DNS, and the release process on Vercel and GitHub Actions.
    • Write tests and documentation so that someone else can take over the systems later.
    Technologies
    PythonTypeScriptNext.jsReactNode.jsTailwind CSSPostgreSQLMicrosoft 365Microsoft Entra IDMicrosoft Graph APIOAuth 2.0DockerVercelGitHub Actions
    Related work
  • Sep – Dec 2025

    FEITIAN Technologies

    FEITIAN Technologies · International Department · Beijing, China

    I planned, built and ran three systems for FEITIAN’s post-quantum FIDO2 work: a public WebAuthn developer platform, a software security key in Rust, and a customer demo site.

    Work
    • Built the company’s first WebAuthn/FIDO2 developer platform, because the team’s third-party tools could not show post-quantum credentials. Developers can register, sign in, inspect and debug credentials in one place.
    • Wrote a CTAP2 authenticator in Rust that Linux presents as a virtual USB security key, so browsers and libfido2 could test ML-DSA credentials before the hardware was ready.
    • Built a self-service demo site where customers can try passwordless sign-in and security keys without contacting support.
    • Worked with FEITIAN’s hardware and security engineers so the tools matched the real devices and the data they returned.
    Operations
    • Deployed with Docker on Linux servers and Google Cloud Run, with GitHub Actions running tests, builds and a daily update of the FIDO metadata.
    • Still maintain all three systems after the internship ended in December 2025.
    Technologies
    PythonFlaskJavaScriptHTMLRustTypeScriptReactTailwind CSSDockerGoogle CloudGitHub ActionsWebAuthn / FIDO2CTAP2.1ML-DSAliboqs
    Related work

Selected Work

  • Aug 2026 – Present

    One Next.js application serving three sites for a property management company: a public website, an owner portal for residents, and an admin console for staff.

    Next.jsTypeScriptReact
    mntrealty.vercel.app
    What it is

    MNT Realty’s website and online services. Prospective clients see the public website. Residents of the stratas MNT manages sign in to the owner portal to read notices, book amenities and download documents. Staff manage all of it from the admin console.

    How it works

    The three sites come from one build, each on its own subdomain. A proxy sends each subdomain to its own pages (admin to the console, owners to the portal), and the public site returns a not-found page for those paths. Each site has its own layout and its own host-only session cookie. Public pages are prerendered, and the console and the portal are rendered on each request. All reads and writes go through one data store interface, so changes staff make show up for residents right away, and the store can later be switched to the drafted PostgreSQL schema without changing any screens.

    Technical challenges

    Access rules are defined once, in a table that the navigation, the page guards and the file route all read. A section outside a user’s role returns not-found rather than forbidden, so the portal does not reveal what other roles can see. Each strata is kept separate: while one is open, nothing from another can be reached. MNT’s own business details, such as company information, the fee schedule for strata documents and the template for amenity booking slots, are versioned data that an administrator edits under Settings, not values in the code. Any saved version can be restored.

    The MNT Realty home page, with the Owner portal and Request a proposal buttons above a photo of the Vancouver skyline
    Stack
    Next.jsReactTypeScriptTailwind CSSNode.jsPostgreSQLVitestVercelGitHub Actions
    Status

    All three sites are built and deployed. The next steps are cloud data storage and backend workflows. The source code belongs to MNT Realty and is not public.

  • Oct 2025 – Present

    A CTAP2 security key that runs in software. Linux presents it as a USB device, so browsers can test post-quantum credentials without real hardware.

    RustLinux
    Repository
    What it is

    A Rust workspace that works like a FIDO2 security key, but in software. FEITIAN’s engineers and partners needed to build and test software that uses ML-DSA credentials before the hardware was ready. It started in my own repository and has since moved to FEITIAN’s GitHub organization, where I still maintain it.

    How it works

    The authenticator core implements CTAP2.1 (credential management, PIN/UV protocols 1 and 2, and reset) on the Trussed framework with littlefs2 storage. A runner creates a virtual USB HID device through Linux uhid and uses the CTAPHID protocol, so Chrome, Firefox and libfido2 treat it as an ordinary security key. It supports ES256 and ML-DSA-44, -65 and -87, and comes with a small command-line tool (attach, detach, status, reset, pin) that can run in the background.

    Technical challenges

    Browsers only accept devices that follow the protocol closely, so the HID transport and the CTAP state machine had to be exact before Chrome or Firefox would use the key. CTAP and COSE structures were designed for classical keys, and post-quantum keys do not fit them easily. The first version called liboqs through a C FFI; it later moved to the pure-Rust fips204 crate, with secret keys zeroized when they are dropped.

    Stack
    RustLinux UHIDTrussedlittlefs2CTAP2.1fips204liboqsclap
    Status

    Works on Linux and is used alongside the developer platform. It is still in active development, and CI runs rustfmt, clippy and the test suite.

  • Sep 2025 – Present

    A public tool for testing FIDO2/WebAuthn flows, including post-quantum ML-DSA credentials.

    PythonFlaskJavaScript
    webauthnlab.techRepository
    What it is

    A Flask web application for developers who work with FIDO2. The third-party tools the team used could not show post-quantum credentials, so I built one that could. Developers can register and sign in with real or virtual authenticators, edit the raw WebAuthn request as JSON, decode the response, and look up any authenticator in the FIDO Alliance metadata service. I started it during my internship at FEITIAN and still maintain it.

    How it works

    It has four tabs: simple sign-in, an advanced mode with an editable request, a codec for attestation objects and CBOR/CTAP structures, and a metadata explorer that checks root certificates. The server uses a modified copy of Yubico’s python-fido2 library, with ML-DSA-44, -65 and -87 added through liboqs. Each visitor gets a separate session store, on local disk or in Google Cloud Storage, and a store that goes unused for 14 days is deleted.

    Technical challenges

    python-fido2 had no post-quantum support, so I added the COSE identifiers, key handling and attestation checks for ML-DSA while keeping the classical algorithms working. Including liboqs in the container image made Cloud Run slow to start, so I added a lazy warm-up and set gunicorn to run a single worker. The FIDO metadata goes out of date, so a daily GitHub Action re-verifies the snapshot and commits it automatically.

    The FIDO MDS Authenticators tab of the WebAuthn developer platform, with a searchable table of authenticators from the FIDO Metadata Service
    Stack
    PythonFlaskJavaScriptDockerGoogle CloudGitHub Actionspython-fido2liboqsJinjapytestVitest
    Status

    Live at webauthnlab.tech and maintained in FEITIAN’s GitHub organization. CI runs about 120 server test files, plus front-end and post-quantum tests.

  • Nov – Dec 2025

    A demo site where FEITIAN’s customers can try passwordless and post-quantum sign-in.

    ReactPython
    demo.ftsafe.com
    What it is

    A demo for FEITIAN’s customers and sales team. The developer platform is for engineers; this site is for people evaluating FEITIAN’s products. Visitors can register a security key, sign in, and see a post-quantum credential work without reading a specification.

    How it works

    A React front end on top of the same authentication service and ML-DSA support as the developer platform. Instead of raw requests and responses, it guides visitors through each step.

    The Info page of the authentication demo platform, with a Password section and an Add Security Key button
    Stack
    ReactJavaScriptPythonFlaskWebAuthn / FIDO2ML-DSAliboqs
    Status

    Live at demo.ftsafe.com. The source code belongs to FEITIAN and is not public.

Other Work

  • Feb 2025 – Present

    A statically generated portfolio site in English and Japanese. It shares a small design system with my resume and cover letter.

    Next.jsTypeScript
    rainzhang.meRepository
    What it is

    My portfolio at rainzhang.me: a home page and a resume page, both in English and Japanese. It uses its own small design system: one typeface, one accent colour, no borders or shadows, and a light and a dark theme. My resume and cover letter use the same design, so the three look like one set.

    How it works

    The Next.js App Router prerenders both languages at build time from one typed content model, so the English and Japanese home pages have the same structure and only the text differs. Tailwind reads the design system’s tokens instead of raw values, and Albert Sans is self-hosted through next/font. Middleware shows a first-time visitor from Japan the Japanese version, and after that the site remembers the language each reader last used.

    Features

    Experience and project rows expand in place. The site also has a language switch, a theme switch (System, Light and Dark), a short entrance animation in plain CSS, a contact form that sends through Formspree with a honeypot field and a request timeout, and a button that copies my email address. The pages still load and their links still work without JavaScript, and every animation follows the reader’s reduced-motion setting.

    Stack
    Next.jsTypeScriptReactTailwind CSSPlaywrightVitestVercelGitHub Actions
    Status

    Live at rainzhang.me. CI runs Vitest unit tests and Playwright end-to-end tests in Chromium, Firefox and WebKit, plus an emulated iPhone.

  • Jan – Apr 2025

    A course project with three classmates: a trip planner that suggests a destination based on a traveller’s passport and visas, then fills in hotels, restaurants and an itinerary.

    What it is

    A group project for CMPT 276. Users answer a short questionnaire or choose a place, pick their dates, and get hotels, restaurants, attractions and a day-by-day plan. A chat assistant answers follow-up questions.

    My part

    I built the React and Tailwind front end, the passport and visa questionnaire that asks OpenAI for a destination, the date steps and their validation, and the chat widget. A teammate wrote the Express service that connects to the Tripadvisor API.

    Looking back

    The app calls the OpenAI API directly from the browser. If I built it again, I would move that call to the backend.

    The Travel Advisor start page, with a short description and a Start Your Journey button
    Stack
    ReactJavaScriptTailwind CSSViteOpenAI APITripadvisor APICypressVercel
    Status

    Finished in April 2025 and still live.

Background

Sep 2023 – Dec 2027

Simon Fraser University

BSc, Computer Science · Vancouver, BC, Canada · Expected to graduate in December 2027

CGPA 3.44 / 4.33. Dean’s Honour Roll in Fall 2024 and Summer 2025.

Languages
PythonTypeScriptJavaScriptRustCC++Java
Web
ReactNext.jsNode.jsFlaskTailwind CSSHTMLCSSPostgreSQL
Infrastructure and tools
DockerGoogle CloudVercelGitHub ActionsGitGitHubLinuxWebAuthn / FIDO2Microsoft 365Microsoft Entra ID

Contact

If you’re hiring or would like to talk about my work, I’d be glad to hear from you.