Earlier projects
Smaller and older work, newest first. ClubSync is the biggest of these and is still being moved to a new stack. The rest are short builds from 2023 and 2024 that each use a tool I kept using afterward.
ClubSync
A coordination platform for student clubs, ASB leaders, schools, and administrators across Washington. It started as a big Flask app and is partway through a move to Next.js.
A lot of student clubs run on unmonitored group chats, and administrators want a more controlled option. ClubSync is meant to be a safer, school-centered place for that coordination. Students find clubs, service hours, internships, and mentorship. Clubs recruit members and plan joint events. ASB leaders get approvals and event coordination, and administrators get visibility without having to join a dozen chats.
The Flask version got big quickly: 73 page templates covering club elections and voting, finances and fundraisers, volunteer-hour verification, ASB school maps and chats, polls, analytics, and separate dashboards for students, clubs, ambassadors, ASB, and admins. The rebuild moves all of that onto a typed stack that's easier to maintain.
- Flask version
-
Aug 24, 2025First Flask app
All 73 templates landed in one commit: the full set of role dashboards and club tools.
-
Aug 26 – Sep 6, 2025Landing page and login polish
Seven commits on the landing and login pages, then a change to the feed on Sep 6.
- Next.js migration
-
May 21, 2026Scaffolded the new app
A fresh Next.js App Router project.
-
Jun 13, 2026First real port, deployed to Vercel
The landing page, login and signup screens with password strength and match checks, a Firebase auth provider, and the StuImpact design system ported to Tailwind 4. Three more commits that evening sorted out the Vercel build and Firebase config.
-
Jun 14, 2026Documented the migration
A README that lists what's ported and what isn't.
Routes for home, login, signup, and an in-progress page; auth UI; Firebase setup; a theme toggle that sets the theme before first paint.
Real auth actions, environment-based config, the Flask workflows as API routes or server actions, the role dashboards, saved club applications, and tests.
College Search Data Scraper
A Python pipeline that walks college search results, opens each school's profile, and writes admissions, academics, and campus-life details into one CSV.
Search results load dynamically, so the scraper drives a real browser with Selenium to get through them. Profile pages are static, so those go through plain HTTP requests and BeautifulSoup, which is much faster than a browser. Profiles are inconsistent (some schools leave whole sections blank), so every field has a fallback and the CSV keeps the same columns for every row.
It uses the same tools as the Essay Prompts prototype, which came two weeks later.
-
Jul 29, 2024Pipeline and dataset
The scraper and its CSV output, with admissions, academics, campus life, housing, activities, and student-body fields.
-
Jun 13–14, 2026Cleaned up for review
Tidied the repo and added a README with a responsible-use note.
Launchpad SGA
A static marketing site for a startup growth agency idea, with pricing, contact, and updates pages, and nothing to build or deploy beyond the files themselves.
The goal was a complete site: four linked pages, responsive Bootstrap layouts, SEO and social metadata for sharing, plus a sitemap, a robots file, and a web app manifest. It runs on any static host.
-
Feb 17, 2024Site up
All four pages with their assets. Most of the 60k added lines are vendored libraries and icon fonts.
-
Feb 17–21, 2024Copy and layout passes
Eleven small edits across the home, pricing, contact, and updates pages.
-
Mar 18 – Apr 24, 2024Trimmed the home page
Two later updates, the second of which cut 213 lines from the home page.
StoreHighlightedText
A Google Docs add-on: highlight text, pull it into a sidebar, and keep it as a saved snippet for later.
It adds a menu to Google Docs that opens a sidebar. Select text, click Get Text, and it uses the Docs selection API to grab what you highlighted. Snippets are stored per user with PropertiesService, and the sidebar talks to the script through google.script.run. It dates from the same summer I was building Google add-ons at Cledge.
It's rough around the edges and the README says so: getSelectedText is defined twice, there's no manifest with explicit scopes, and deleting a snippet means typing its index instead of clicking it.
-
Aug 19, 2023Published in one sitting
The Apps Script back end (94 lines) and the sidebar (156 lines), five commits in four minutes.
-
Jun 13, 2026Documented
A README with the user flow, setup steps, and known issues.