Why this project exists
The problem
- Food, services, and community news are mixed together in one feed
- There are no categories or filters, such as "free delivery" or "open for orders"
- Posts sink quickly, so a good shop disappears under newer posts
- Finding a pharmacy, fresh fish, or an air-conditioning technician means scrolling post by post
The approach
- Admin-seeded listings first. No user accounts, no posting system, and no user-generated feed. Listings are added by an admin or submitted through a simple form and approved before they appear.
- Contact is the goal. Every listing ends in a call, LINE, or Facebook button. Contact clicks were chosen as the main success metric, rather than page views.
- Explicitly out of scope: comments, chat, payments, delivery management, recommendation engines, and AI chat.
What was built
- Category index, keyword search, and filters for free delivery, home delivery, and open-for-orders
- Listing pages with a photo gallery, a fact sheet (price, hours, delivery), and a contact bar that stays at the bottom of the screen on mobile
- An interactive map of pinned shops, with directions through Google Maps
- Visitor ratings and reviews, shown only after approval
- A public form so shop owners can submit their own listing, including photos and a map pin
- An overview of live, pending, and per-category listing counts, with an approval queue
- Approve or reject submissions and reviews, from the dashboard or with one tap from a Telegram alert
- Listing and category editing, including a map picker that accepts a pasted Google Maps link or the device's GPS
- Next.js and React for the public site and admin, server-rendered for search engines, with structured data (LocalBusiness, breadcrumbs, ratings, coordinates) and a sitemap built from real edit dates
- FastAPI, SQLAlchemy, and PostgreSQL for the API, with Alembic migrations
- MapLibre GL with OpenFreeMap tiles for the maps: no API key and no per-view cost, loaded only on pages that show a map
- Spam control without accounts: every submission and review is moderated, and reviews are also rate-limited per IP (stored only as a keyed hash) and protected with a honeypot field
- GitHub Actions running lint, type checks, a production build, a migration round-trip, and the backend test suite on every push
- Self-hosted on Ubuntu with Nginx and HTTPS
Results so far
- 11 live listings, all with photos, across 7 categories. Five categories have at least one listing.
- 2 listings pinned on the map. The map launched in October 2026.
- Live since June 2026.
What this project demonstrates
- Taking a real problem in one's own community from a written problem statement to a deployed product, including deciding what not to build
- Full-stack delivery across a public site, an admin, an API, and a database, with moderation designed for a site without user accounts
- Running a live system responsibly: automated checks on every change, data migrations, and auditing your own metrics rather than trusting them
Need a directory, booking system, or internal tool for your business? Book a discovery call to discuss your workflow, scope, and support needs.
