I got an admit offer from NYU Courant for their MS CS program this fall, and as I was waiting for my visa interview, I came across the NYU community WhatsApp groups. It's a great community — people are genuinely helpful, and there's usually someone around who has already figured out the thing you're stuck on.
There is a housing group as well in the community. I ended up scrolling through that group a lot, mostly just to get a feel for what off-campus housing looks like in the US before I got there. I wasn't actively looking for a place yet — more like reading the room.
After a few days of scrolling, I started to notice some patterns. The same listing would show up again and again because people were posting it daily so it wouldn't disappear under newer messages. A lot of posts just said “DM me for pictures.” And sometimes people would ask what a lease takeover or a guarantor was — things that aren't obvious if you haven't rented in the US before, and that mostly get explained in the group itself.
A few days of doing that, and an idea started to form in my head. I thought it might be nice to have a shared listing board for NYU students — somewhere the same information could sit in one place, without turning into a whole booking or messaging app. Interested people could still contact the poster the usual way.
Diving deeper
Once I was serious about making something, I went back to the groups with a different eye. Not just scrolling for curiosity this time — deliberately looking for the friction people hit when they're actually trying to find or list a place.
That second pass surfaced different issues. If you're seriously considering a listing, there's often no way to tell whether it's still available unless you message. Keeping two or three options in your head means jumping between chats and half-remembering rent, commute, or lease details. And the daily reposting I'd noticed earlier pointed at a bigger question for a board: what happens when a listing sits around after the place is already taken?
Before writing much code, I spent some time writing those things down. That felt a little formal for a side project, but it helped me stay focused. Roughly: only NYU emails should get in, there should be a way to browse and compare listings, a way to add or remove your own, some notion of listings going inactive over time, and a short glossary for renting terms. No separate profiles — if you'd signed in with your NYU email, that was enough.
I also had that writeup reviewed a few different ways — staleness, empty states, security, scope. A few more gaps showed up there, especially how someone comes back later to manage something they posted.
OTP sounded right, until it didn't
The first auth idea was simple: enter your NYU email, get a one-time code, and you're in. Sending those emails turned out to be harder than I expected. The free Resend onboarding sender doesn't deliver to arbitrary addresses the way I hoped — it mostly only works for your own account. Getting codes to real students would have meant buying a domain or going through NYU IT, and neither felt like a good starting point for a small volunteer project.
So I switched to Google sign-in, limited to nyu.edu. Google handles the
identity check; the site only confirms the domain. After that, a session cookie lasts about
five days, which felt like a comfortable middle ground — you don't have to sign in every
time you close the tab, but you also don't stay logged in forever.
One useful detail along the way: putting the Google Cloud project under NYU's org “Personal
Projects” folder let me use an Internal OAuth audience. Any @nyu.edu account
can sign in without the usual 100-user Testing-mode limit. That only works because of the
NYU org folder — not just because I happen to have an NYU email on a personal project.
Putting it together
The stack I ended up with:
- Next.js 16 (App Router) + TypeScript + Tailwind
- Prisma + Neon Postgres
- Google OAuth for
nyu.eduaccounts - Vercel Cron for listing expiry
Most of it came together in Cursor sessions — I stayed close on the product choices, and leaned on the agent for boilerplate, migrations, and the usual deploy mysteries. Google sign-in, a public GitHub repo, and a Vercel deploy all came together fairly quickly once the shape of the thing was clear.
Some of those mysteries were less about code and more about setup: accepting Neon terms in
the browser, connecting GitHub to Vercel once, and learning that deleting an env var from
the wrong place can quietly affect Preview and Production if the values were shared. I keep
main as production and dev as preview, each with its own database
and secrets. Mixing those is a good way to get “works on preview, empty on prod.”
What it looks like now
After login there are three tabs: Available listings, My listings, and Glossary. You can filter by area (NYC boroughs plus a few Jersey City PATH areas), campus/distance, rent, bedrooms, lease type, and a few other things. You can also compare up to three listings side by side.
Listings don't stay live forever. Active ones move to Inactive after 15 days, and posters can bring them back from My listings. Inactive ones eventually get cleaned up by a daily cron job.
I also rewrote some of the early homepage copy. The first version sounded a bit like I was launching a product. What I wanted was quieter — just an unofficial tool made by a student, for other students.
A security pass, and a photo detour
A few days after the first deploy, I asked for a security and privacy pass. There were no secrets in the repo, which was reassuring. Hosting photos ourselves on Vercel Blob felt like more surface area than I needed, and poster emails were showing up in public API responses when they didn't have to.
The first reaction was to drop Blob and let posters paste a Google Drive link instead. On paper that looked simpler. In practice the Drive embeds didn't work properly — images often failed to show inside the iframe — so I reverted and went back to uploading photos to Vercel Blob.
I also turned on Postgres RLS and stripped a few unnecessary fields from public responses. At one point I tried encrypting contact details at rest, then undid that. For a solo project like this, holding encryption keys I couldn't recover from felt like the wrong kind of complexity.
A few things I learned along the way
Building with an agent made the loop faster, which also meant ordinary shipping bugs showed
up sooner — a missing export that made the compare modal look broken, tab switches that felt
slow because they were doing full navigations, date inputs that followed the OS locale and
showed up as dd/mm/yyyy. None of that is unique to AI. It just arrives earlier
when you're moving quickly.
A few other notes from the process:
- What you notice while casually scrolling is different from what you notice when you're deliberately looking for issues to fix.
- Writing things down first helped once auth, personal details, and listing expiry entered the picture.
- Email OTP can fail you before the UI ever gets a chance.
- Preview and Production secrets are worth keeping separate.
- Sometimes the “simpler” security fix doesn't survive contact with the browser — Drive embeds were a good example.
- The tone of the site matters more than I expected.
The board is live for @nyu.edu accounts at
nyuoffcampushousing.vercel.app,
and the code is on
GitHub.
It's still just a showcase — students find listings there, then reach out the usual way.
Until next time!