WallpaperMachine
당신이 사랑하는 배경화면, 맥에서 새롭게 만나보세요
Tapovan, Rishikesh 오늘 밤: 라이브 음악·춤·음향 치유·키르탄·워크숍 등. 날짜·가격·지역별 필터 가능
What's on tonight in Tapovan, Rishikesh: live music, ecstatic dance, sound healing, kirtan, workshops and more. Every flyer in one place, filterable by date, price and area.
라이프스타일TypeScript · CSSGitHub @suhmantics-droid온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Every flyer in Tapovan, on one map. A website where organisers pin their event flyers (₹50 for 4 weeks), and travellers filter what's on by date, vibe, price and area, see it on a map, and get alerts for the musicians, cafes and kinds of events they love.
Built for rishikesh.suhmantics.com.
| For visitors | For organisers | For you (admin) |
|---|---|---|
| Flyer wall, day-by-day agenda, and a flyer map: every flyer pinned where it's happening | Snap a flyer → details are read from the photo (optional AI); straighten a wall photo in one drag | Post flyers yourself and record cash in one tap |
| Filter: today / tomorrow / weekend / date, category, area, price, time of day | ₹50 = 4 weeks; recurring events show on every date | Approve organiser submissions once they've paid |
| Follow artists, venues, vibes → phone notifications or email | Private link to edit, renew, and see views, "interested", WhatsApp and directions taps | Visitors per day, most-viewed flyers, revenue |
| /today — the day's list, shareable to WhatsApp with a picture preview | Followers are notified the moment the flyer goes live | Fix map pins, feature/hide listings, handle reports |
| Ganga Aarti times and directions; add to calendar; directions | Listed in Google's event results | Upload the site's photos; CSV exports |
| Class timetables (Tapashala, Divine Circle…) by day, kept apart from one-off events | Post a whole weekly timetable as one listing | Starter pack: 12 real Tapovan flyers ready to publish |
| QR codes on flyers become tappable buttons (WhatsApp group, booking form, map pin) | QR codes are read automatically | Batch upload: snap a whole wall, post them one by one later |
| Near me (walking minutes), On now / in 25 min badges | A QR poster for their own wall | Story image of today's flyers for Instagram / WhatsApp status |
| My plan: save flyers (no account), reminder an hour before | Duplicate warnings; fix pins by pasting a Google Maps link |
The site runs on Vercel's free plan: Vercel runs the app, Turso (free) holds the database, and Vercel
Blob holds the flyer photos. Every push to main on GitHub deploys itself; your data lives in Turso and Blob, so
deploys never touch it. (Prefer one server of your own? See the folded section below.)
In Vercel: Add New → Project → import github.com/suhmantics-droid/rishikesh. Then, in the project:
BLOB_READ_WRITE_TOKEN for you.iad1), and copy its URL and a token.| Name | Value |
|---|---|
ADMIN_PASSWORD | your password for /admin — make it long |
SESSION_SECRET | any long random string (signs the admin login) |
TURSO_DATABASE_URL, TURSO_AUTH_TOKEN | from Turso |
CRON_SECRET | any long random string — Vercel's daily cron sends it to /api/cron |
CRON_GITHUB_REPO | suhmantics-droid/rishikesh — lets the 15-minute GitHub job run the site's jobs |
SITE_URL | https://rishikesh.suhmantics.com once the domain is connected (until then the Vercel address is used) |
Redeploy after changing variables (Deployments → ⋯ → Redeploy).
Vercel → project → Settings → Domains → add rishikesh.suhmantics.com. Vercel shows the DNS record to add
(a CNAME named rishikesh); add exactly that wherever suhmantics.com's DNS is managed. On Cloudflare, set it
to DNS only (grey cloud). HTTPS is set up automatically. Then set SITE_URL (above) and redeploy, so links in
emails, share previews and QR posters use the real address. For GitHub's 15-minute job, also set a repository
variable SITE_URL (GitHub → repo → Settings → Secrets and variables → Actions → Variables) if the site
isn't at rishikesh.suhmantics.com.
ADMIN_PASSWORD.The same code runs as one Docker container plus Caddy for HTTPS, with the database (SQLite) and photos on the server's disk — leave the Turso and Blob variables empty. The server installs itself from a script pasted into a web form and pulls new code from GitHub every 15 minutes.
The code lives at github.com/suhmantics-droid/rishikesh. If the repo is private, create a read-only token
for the server: GitHub → Settings → Developer settings → Fine-grained tokens → Generate → Repository access:
only rishikesh → Permissions: Contents: Read-only. Copy the token. (A public repo needs no token — the
code contains no passwords or keys.)
deploy/cloud-init.sh, then edit its top four lines: your admin password, and the
GitHub token if the repo is private.0.0.0.0/0, IP protocol TCP, Destination port range 80,443 → Add.The server now installs itself (about 10–15 minutes).
Wherever suhmantics.com's DNS is managed (your registrar's website, or Cloudflare), add a record:
| Type | Name | Value |
|---|---|---|
A | rishikesh | the server's public IP |
On Cloudflare, set it to DNS only (grey cloud). Within a few minutes https://rishikesh.suhmantics.com loads, with HTTPS set up automatically.
From a terminal, any Ubuntu server works (Hetzner, DigitalOcean, a ₹500/month VPS):
git clone https://github.com/suhmantics-droid/rishikesh.git && cd rishikesh
bash deploy/setup.sh # installs Docker, asks for an admin password, builds and starts
bash deploy/update.sh pulls and rebuilds by hand; bash deploy/backup.sh takes a backup now.
| You want to… | Do this |
|---|---|
| Post a flyer someone WhatsApped you | Sign in → Post a flyer → upload → check → Cash received (₹50) — publish now |
| Post a whole wall of flyers from a walk | Admin → 📸 Add photos → pick them all → later, Check & post each one from Photos to post |
| Fix a venue's map pin | In Google Maps tap the place → Share → Copy link → Admin → Venues & pins → paste → Use → Save |
| Post today's flyers to Instagram / WhatsApp status | Admin → Post today's story → Today (or Tomorrow / Weekend) and pick the app |
| Give a cafe its own poster | Admin → Venues & pins → 🖨 Print their QR poster (or /v/<venue>/poster) |
| Post one for free | Same, but Publish free |
| Approve an organiser who submitted online and paid you cash | Admin → To do → ✓ Received — publish |
| Fix a wrong date/price | Click the listing in Admin → Listings → Edit details |
| Feature a listing at the top | Admin → Listings → Feature |
| Take something down | Admin → Listings → Hide (or from a report in To do) |
| See what emails went out | Admin → Email log |
Organisers get a private manage link (by email, and on screen) to edit, see views and renew. If you posted it for them, open it from Admin → Listings and send them the link.
Automatic jobs, every 15 minutes: the morning "what's on today" email from 07:30 IST, a renewal reminder to
organisers 2 days before their listing ends, "starting soon" reminders for flyers people saved to their plan, and
clearing out full-size upload photos after 3 days (they're kept only for straightening). On Vercel they're run by
the GitHub job in .github/workflows/jobs.yml (plus Vercel's own daily cron as a backstop); on your own server, by
the app itself. GitHub pauses scheduled jobs in a repository with no commits for 60 days — if the morning emails
stop, re-enable Scheduled jobs under the repo's Actions tab. Admin → Send today's digests runs them by hand.
Updates: on Vercel, every push to main deploys in a couple of minutes, and a failed build leaves the previous
version running. (Your own server checks GitHub every 15 minutes and rebuilds.) Your data is never touched by
updates.
Backups: Admin has CSV downloads of listings, payments and subscribers. On your own server a full backup runs
nightly at 03:15 into deploy/backups/ (last 14 kept).
?when=tomorrow / ?when=weekend) is a 1080×1920 picture of the flyers with
times, venues and the site address. "Share as a story" on /today and in Admin sends it straight to a phone's
share sheet. One a day on Instagram and in WhatsApp status is the cheapest way to grow.Everything below is set in /admin → Settings (no server access needed). A value in the server's .env
file overrides the admin page.
Add a Claude API key (from https://console.anthropic.com). Uploading a flyer then fills in the title, dates (including "every Saturday"), times, venue, price, artists and contact details for the organiser to check. It uses Claude Opus 5.5 at low effort with an automatic fallback model; expect roughly ₹1–2 per flyer read. Results are cached per upload.
Add a Resend API key from https://resend.com (free tier: 3,000 emails/month) and verify suhmantics.com in Resend (it gives you DNS records to add). Until then, emails are only recorded in Admin → Email log, not sent.
Payment mode picks how organisers pay:
| Mode | How it works | Needs |
|---|---|---|
cash (now) | Organiser submits; you collect cash and tap Received in Admin | nothing |
upi | Organiser scans a QR for your UPI ID and enters the UTR; you approve in Admin. No fees. | UPI ID and payee name |
razorpay | UPI, cards, netbanking; goes live instantly, no manual step. ~2% fee. | Razorpay key ID and secret, plus a webhook to /api/webhooks/razorpay (events payment.captured, order.paid) and its secret |
Price and length are set in the server's .env: LISTING_PRICE_PAISE (5000 = ₹50) and LISTING_DAYS (28).
The map uses OpenStreetMap tiles, which is fine for a small site. If traffic grows, get a free key from MapTiler or
Stadia Maps and set NEXT_PUBLIC_MAP_TILES (rebuild needed). Directions always open in Google Maps.
npm install
npm run seed:demo # optional: 14 sample flyers at fictional venues (marked "Sample")
npm run dev # http://localhost:3000 — admin password in dev is "admin"
npm test # unit + listing-lifecycle tests
npm run seed:demo -- --clear removes the samples (or use the button in Admin).
@libsql/client: hosted by Turso when TURSO_DATABASE_URL is set, otherwise a file in
data/app.db. Flyers resized to WebP with sharp, stored in Vercel Blob when BLOB_READ_WRITE_TOKEN is set,
otherwise in data/uploads/ — src/lib/storage.tszxing-wasm; Web Push (web-push, VAPID keys generated on first use) for phone notificationsnext/og; type set in Fraunces (headings) and Inter@anthropic-ai/sdk, structured outputs) for reading flyers — src/lib/extract.tssrc/lib/email.tssrc/lib/payments.ts (cash / UPI QR / Razorpay)src/app/ pages: / (browse), /map (flyer map), /e/[slug] (event), /v/[slug] (venue) + /poster, /a/[slug] (artist),
/today (+ /today/story image), /plan, /venues, /artists, /post, /manage/[token], /alerts, /admin,
/about, /poster; api/ routes
src/components/ Browse (filters + views), MapView, FlyerCard, PostFlow, PayWidget, AlertsForm …
src/lib/ db (schema), data (queries), listings (incl. timetables), payments, alerts, extract,
qr (QR codes → links), warp (straightening), collage (map layout), starter, uploads (batch
queue, duplicates), maplink (Google Maps links → pins), push (incl. plan reminders), storage
(disk or Vercel Blob), cron, site
seed/starter/ the starter pack: flyers.json plus the straightened flyer images
deploy/ cloud-init.sh (browser setup), setup.sh, auto-update.sh, backup.sh, update.sh, Caddyfile
tests/ node:test suites (dates, utils, listing lifecycle, filters, payments)
Product settings (name, tagline, areas, categories, map centre) are in src/lib/site.ts.