mdesk.tech — Designing and hosting your digital future
Modern website built with Next.js 16, React 19, and Tailwind CSS 4. It features server components, dynamic streaming, sleek UI components, and a production‑ready contact workflow with Discord notifications and MongoDB‑backed rate limiting.
GitHub Copilot is used to help optimize page performance
Live site: mdesk.tech
Requirements
- Node.js 20+
- pnpm (project is pinned to pnpm via
packageManager)
Quick Start
# 1) Enable corepack (recommended to match the pinned pnpm version)
corepack enable
# 2) Install dependencies
pnpm install
# 3) Configure environment
cp .env.example .env
# Then edit .env with your values (see Environment below)
# 4) Run the dev server (Turbopack)
pnpm dev
# Open http://localhost:3000Environment
Define these variables in .env:
- DISCORD_WEBHOOK_URL: Discord webhook to receive contact submissions (required for
POST /api/contact) - MONGODB_URI: Connection string used for IP‑based rate limiting (required if using contact form)
- NEXT_PUBLIC_SITE_URL: Base site URL for canonical/OG metadata (e.g.
http://localhost:3000in dev) - NEXT_PUBLIC_GA_ID: Optional GA4 Measurement ID (loads only in production)
Notes
- If
DISCORD_WEBHOOK_URLorMONGODB_URIare missing, the contact endpoint will return an error when called. - The rate‑limit window is 1 hour per IP and uses a TTL index in MongoDB (
lib/db.ts).
Scripts
pnpm dev— Start dev server with Turbopackpnpm build— Production build with Turbopackpnpm start— Start production serverpnpm lint— Run ESLintpnpm prettier— Format with Prettierpnpm check-types— Type‑check with TypeScriptpnpm prepare— Initialize Husky (run once after install, if needed)
Pre‑commit
.husky/pre-commitrunspnpm check-types && pnpm lint-stagedlint-stagedformats and fixes staged files
Project Structure
app/page.tsx— Home with lazy‑loaded sections (Features, Services, About, Contact)app/contact/page.tsx— Contact page with form and Discord submissionapp/api/contact/route.ts— API route posting to Discord + MongoDB IP rate limitingapp/about/page.tsx,app/services/page.tsx,app/open-source/page.tsx— Additional pagesapp/sitemap.ts,app/robots.ts— SEO helperscomponents/— UI and layout (Navbar, Footer, PageTransition, rich UI effects)lib/db.ts— MongoDB client + TTL index setup for rate limitinglib/utils.ts—cnutility combiningclsxandtailwind-mergehooks/— Common hooks (e.g.,use-outside-click.tsx)
API
-
POST /api/contact(file:app/api/contact/route.ts)- Body:
{ name: string; email: string; subject?: string; message: string; isOpenSourceForm?: boolean }
- Body:
-
Rate limit: 1 request per IP per hour (MongoDB TTL index)
-
Side effect: sends a Discord embed to
DISCORD_WEBHOOK_URL -
Responses:
200 { success: true },429 { error, message },400/500 { error }
SEO & Analytics
- Metadata and OG/Twitter cards set in
app/layout.tsx - Sitemap at
app/sitemap.tsand robots atapp/robots.ts - Vercel Analytics + Speed Insights enabled in production; GA4 loads when
NEXT_PUBLIC_GA_IDis set
Styling & UI
- Tailwind CSS v4 via PostCSS plugin (
postcss.config.mjs) - Modern UI Components: 3D cards, glare/shine effects, hover text, world map, etc.
- page transitions configured via
components/pagetransition.tsx
Deployment
- recommended: vercel
- set the same environment variables in your vercel project
- ensure a mongodb instance is reachable from your deployment if using the contact form
- build command uses turbopack by default. if you hit issues, try removing
--turbopackfrom scripts
Troubleshooting
- discord webhook errors: verify
discord_webhook_urland webhook permissions - MongoDB connection errors: Verify
MONGODB_URIand network access; the TTL index is created automatically - GA not reporting: Ensure
NEXT_PUBLIC_GA_IDis defined; analytics load only in production
Contributing
- Fork and create a feature branch
- Run
pnpm check-types,pnpm lint, andpnpm prettierbefore opening a PR - Thanks to Renovate (
renovate.json) for automated dependency updates
License
- GPL‑3.0 — see
LICENSE
Acknowledgements
- Next.js, React, Tailwind CSS, Vercel Analytics/SI
- lucide-react, motion, and other open‑source libraries listed in
package.json