muralMaDrs is a server-rendered mural directory for finding public art, sharing new murals, and leaving reviews.
This version is the post-refactor codebase. The old Express app, the Bun runtime, and the one-off Vercel experiments are gone. The project now runs on Node, pnpm, Hono, and TypeScript.
- Node 22
- pnpm
- Hono
- TypeScript
- MongoDB with Mongoose
- Tailwind CSS v4
- Mapbox GL JS
- Cloudinary for hosted uploads, with a local fallback for development
- moved the app from npm to pnpm
- replaced Express with Hono
- converted the app from JavaScript to TypeScript
- cleaned up the project layout into
config,middleware,services,routes, andviews - tightened environment validation and response headers
- switched Vercel to a bundled Hono serverless entry so deploys are predictable
- refreshed the UI direction with modern typography and an image-led homepage hero
- Node 22 or newer
- pnpm 9 or newer
- MongoDB
- Optional Mapbox token for maps and geocoding
- Optional Cloudinary credentials for production-safe image uploads
- Install dependencies.
pnpm install- Copy the example environment file.
cp .env.example .env- Fill in your values.
At minimum you need:
DB_URLSECRET
- Start the app.
pnpm run dev- Open
http://localhost:3000.
If you are actively changing Tailwind styles, use this instead:
pnpm run dev:fullpnpm run devstarts the local server in watch modepnpm run dev:fullstarts the server and the CSS watcher togetherpnpm run startstarts the local server without watch modepnpm run typecheckruns TypeScript checkspnpm run lintruns ESLintpnpm run lint:fixruns ESLint with automatic fixespnpm run build:csscompiles and minifies the Tailwind outputpnpm run build:css:watchwatches and rebuilds CSSpnpm run build:vercelbuilds the Vercel function entry used in production
| Variable | Required | Notes |
|---|---|---|
NODE_ENV |
No | Defaults to development locally. Vercel will run with production. |
PORT |
No | Local server port. Defaults to 3000. |
DB_URL |
Yes | MongoDB connection string. |
SECRET |
Yes | Session signing secret. Use a long random value in production. |
SESSION_COOKIE_NAME |
No | Cookie name for the session and flash data. |
SESSION_TTL_DAYS |
No | Session lifetime in days. |
MAPBOX_TOKEN |
No | Enables interactive maps and geocoding. Without it, the map UI falls back cleanly. |
CLOUDINARY_CLOUD_NAME |
No | Required if you want persistent hosted uploads. |
CLOUDINARY_KEY |
No | Required if you want persistent hosted uploads. |
CLOUDINARY_SECRET |
No | Required if you want persistent hosted uploads. |
src/
index.ts # Hono app, middleware, and routes
vercel.ts # Vercel serverless entrypoint
dev-server.ts # local Node server bootstrap
config/
middleware/
models/
routes/
services/
views/
public/
images/
javascripts/
stylesheets/
api/
index.ts # thin Vercel wrapper
api/app.mjs is generated during the Vercel build and is not checked in.
- Import the repository into Vercel.
- Set
Framework PresettoOther. - Add the environment variables from
.env.example. - Make sure
DB_URLis reachable from Vercel. The serverless entry now opens and reuses the Mongo connection automatically for each function instance. - If you want image uploads in production, add the Cloudinary credentials. The local upload fallback writes to
public/uploads, which is fine for local development but not for a serverless filesystem. - Deploy.
The repo already includes a vercel.json file that:
- runs the bundle build for the Vercel function
- routes app traffic through the tracked
api/index.tswrapper - leaves static assets in
public/
Production notes:
- Mongoose indexes are not built automatically in production. If you add or change indexes, create them explicitly in Mongo before relying on them.
- The Vercel build generates
api/app.mjsduring deploy. You should not commit build output to git just to deploy this app.
You do not need to add custom install, build, or output settings in the Vercel dashboard unless you want to override what is already in the repo.
- Homepage hero image source: https://www.pexels.com/photo/mosaics-on-urban-wall-9221566/
- Pexels license: attribution is appreciated but not required.
MIT