Marketing landing page and admin backend for GoService, a service-reminder
app for motorcycle & car owners in Indonesia (Android, package
com.zrifapps.goservice).
Built with Next.js 16 (App Router), Tailwind CSS v4, lucide-react, motion, and Supabase.
- Landing page (
/) — hero, features, how-it-works, component intervals, privacy, FAQ, and a Google Play CTA. Fully server-rendered and SEO-tuned (metadata, JSON-LD, sitemap, robots, manifest, dynamic OG image). - Legal pages —
/privacyand/terms, mirrored from the in-app screens. - Feedback API (
POST /api/feedback) — public endpoint the mobile app calls to submit feedback / bug reports. - Admin (
/admin) — Supabase-authenticated dashboard to review, resolve, and soft-delete (mark invalid / spam) reports. Guarded by a route proxy.
yarn install
yarn dev # http://localhost:3000Other scripts: yarn build, yarn start, yarn lint.
This project uses Yarn with the
node-moduleslinker (.yarnrc.yml) because Turbopack — the default builder in Next 16 — does not resolve Yarn PnP.
Create .env.local (see .env.local for the live values):
NEXT_PUBLIC_SITE_URL=https://your-domain.com # canonical/OG/sitemap base (defaults to a placeholder)
NEXT_PUBLIC_SUPABASE_URL=https://<ref>.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_... # browser/SSR auth (RLS)
SUPABASE_SECRET_KEY=sb_secret_... # server only — feedback insertsAnything sent to crawlers (canonical URL, Open Graph, sitemap) uses
NEXT_PUBLIC_SITE_URL; set the real domain before deploying.
Database migrations, RLS policies, and how to create the admin account are
documented in supabase/README.md. Schema changes live
as ordered files in supabase/migrations/.
Quick version:
- Apply the files in
supabase/migrations/(in order) via the Supabase SQL Editor orsupabase db push. - Add
SUPABASE_SECRET_KEYto.env.local. - Create an admin user in Authentication → Users and disable public signup.
POST /api/feedback — Content-Type: application/json
Responses: 201 { ok, id } · 422 { error } (validation) · 400 (bad JSON).
The route inserts using the secret key server-side, so the app never holds a
write key and the table stays locked by RLS.
src/
app/
page.tsx landing page
privacy/ terms/ legal pages
api/feedback/ public submission endpoint
admin/ auth-guarded review dashboard
layout.tsx metadata, fonts, JSON-LD
sitemap.ts robots.ts manifest.ts opengraph-image.tsx icon.svg
components/ landing + admin UI
lib/
site.ts legal.ts content (single source of truth)
feedback.ts feedback types + validation
supabase/ server & admin clients, session proxy
proxy.ts admin route guard (Next 16 proxy convention)
supabase/ migrations/ + setup guide
Deploys cleanly to Vercel. Set the env vars above in the project settings
(SUPABASE_SECRET_KEY as a non-public secret).
{ "type": "bug", // or "feedback" (default) "message": "…", // required, 1–5000 chars "email": "user@mail.com", // optional "app_version": "1.0.0", // optional context "platform": "android", "device_model": "…", "os_version": "14", "metadata": {} // optional free-form object }