Mesto (Место — "place" in Russian) is a Tinder-style restaurant discovery app for Moscow and St. Petersburg, built as a Telegram Mini App.
Swipe through curated restaurants, save your favorites, and explore them on a map.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| API | tRPC 11 — end-to-end type-safe API |
| Database | PostgreSQL + Drizzle ORM |
| Validation | Zod 4 |
| Styling | Tailwind CSS 4 + shadcn/ui |
| Animation | Motion (Framer Motion) |
| State | Zustand + TanStack Query |
| Telegram | @tma.js/sdk-react |
| Runtime | Bun |
- Swipe discovery — card stack with drag gestures and spring physics
- Restaurant detail — photo carousel, Michelin/award badges, full info
- Saved list — "want to go" / "been there" tabs, swipe to remove
- Map view — all restaurants on Yandex Maps with search and filters
- Telegram auth — deeplink login via bot, session cookies
- i18n — Russian and English via
next-intl
src/
├── app/[locale]/ # Next.js pages (Server Components by default)
│ ├── (app)/ # Main tabs: map, saved, profile
│ └── (detail)/ # Restaurant detail page
├── server/
│ ├── api/routers/ # tRPC routers (restaurants, favorites, auth, users)
│ ├── auth/ # Telegram verification, sessions, tokens
│ └── db/schema.ts # Drizzle schema (PostgreSQL)
├── components/ # React components (swipe, map, restaurant, etc.)
├── hooks/ # Custom hooks (favorites, filters, platform)
└── trpc/ # tRPC client setup + React Query integration
Type safety flows end-to-end: Drizzle schema → tRPC routers → React Query hooks — no manual types needed at API boundaries.
- Bun (v1.3+)
- Docker (for PostgreSQL)
- A Telegram Bot token from @BotFather (optional, for auth)
Note: This project uses Bun as the package manager and runtime — not npm/yarn.
# Clone and install
git clone https://github.com/AHTOOOXA/mesto.git
cd mesto
bun install
# Configure environment
cp .env.example .env
# Edit .env with your DATABASE_URL and TELEGRAM_BOT_TOKEN
# Start PostgreSQL
./start-database.sh
# Push schema to database
bun run db:push
# Start dev server
bun run devOpen http://localhost:3000.
bun run dev # Dev server (Turbopack)
bun run build # Production build
bun run typecheck # TypeScript check
bun run lint # ESLint
bun run db:push # Push schema changes
bun run db:studio # Drizzle Studio (DB browser)
bun run db:generate # Generate migrations
bun run db:migrate # Run migrationsPostgreSQL with Drizzle ORM. All tables are prefixed with mesto_ for multi-project support.
Core tables: cities, restaurants, badges, favorites, skipped, users, sessions, auth_tokens.
See src/server/db/schema.ts for the full schema.
Dark "inverted journal" aesthetic — black canvas with cream typography, inspired by French bistro menus.
- Fonts: Cormorant Garamond (display) + Inter (UI)
- Palette: Paper black
#0A0A0A, ink cream#F5F0E6, warm copper#B87333, wine#722F37 - Mobile-first, dark mode only
- Native mobile app via Capacitor (iOS + Android)
- User reviews and ratings
- Restaurant recommendations based on swipe history
- Push notifications for new restaurants
- Offline support with service worker