Find and explore night markets across Malaysia
A comprehensive web application to discover nearby pasar malam (night markets), browse markets on an interactive map or list, and view essential details to plan your visit. Built with modern web technologies and designed for both desktop and mobile users.
- πΊοΈ Interactive Map: Precise market locations with Leaflet integration
- π List View: Quick browsing of all markets with search and filters
- π Smart Filters: Filter by state, day of the week, and amenities
- π± Responsive Design: Mobile-first approach with modern UI components
- π Multilingual: Full support for English and Malay (Bahasa Malaysia)
- π Location Services: Find nearest markets based on your location
- π¨ Modern UI: Built with Shadcn UI, Radix UI, and Tailwind CSS
- Node.js 18.0 or higher
- npm (comes with Node.js) or pnpm (recommended)
- Docker Desktop (required for local Supabase development)
- Supabase CLI (installed via npx, no separate installation needed)
-
Clone the repository
git clone https://github.com/yourusername/caripasarmalam.git cd caripasarmalam -
Install dependencies
# Using npm npm install # Or using pnpm (recommended) pnpm install
-
Set up environment variables
# Copy the example environment file # Create .env.local file (see Local Development section below for details)
-
Start local Supabase (see Local Development section for details)
npx supabase start
-
Start the development server
# Using npm npm run dev # Or using pnpm pnpm dev
-
Open your browser Navigate to http://localhost:3000
# Build the application
npm run build
# or
pnpm build
# Start the production server
npm start
# or
pnpm start- Framework: Next.js 15 (App Router, React Server Components)
- Language: TypeScript
- Database: Supabase (PostgreSQL with JSONB)
- Styling: Tailwind CSS
- UI Components: Shadcn UI + Radix UI
- Maps: Leaflet
- Internationalization: Custom i18n implementation
- Icons: Lucide React
caripasarmalam/
βββ app/ # Next.js App Router pages
β βββ about/ # About page
β βββ contributors/ # Contributors page
β βββ markets/ # Markets listing and detail pages
β βββ map/ # Map view page
βββ components/ # React components
β βββ ui/ # Reusable UI components (Shadcn)
β βββ *.tsx # Feature-specific components
βββ lib/ # Utility functions and data
β βββ markets-data.ts # Market TypeScript types (deprecated functions)
β βββ db.ts # Database query functions (Supabase)
β βββ db-transform.ts # Database row transformation utilities
β βββ supabase.ts # Supabase server client
β βββ supabase-client.ts # Supabase browser client
β βββ geolocation.ts # Coordinate to state mapping
β βββ i18n.ts # Internationalization
β βββ utils.ts # General utilities
βββ supabase/ # Supabase local development configuration
β βββ config.toml # Supabase local configuration
β βββ migrations/ # Database migration files
β β βββ 20251108115510_remote_schema.sql
β βββ seed.sql # Database seed data
β βββ tests/ # Database tests
βββ dataset/ # Data processing scripts
βββ hooks/ # Custom React hooks
βββ types/ # TypeScript type definitions
βββ scripts/ # Utility scripts
βββ public/ # Static assets
We welcome contributions from the community! Here's how you can help:
Google Form (Recommended for non-developers)
- Use our Google Form to submit new market information
- This is the easiest way for community members to contribute
- Use GitHub Issues to report bugs or request features
- Provide detailed information about the issue
- Include steps to reproduce if it's a bug
- Fork the repository
- Create a feature branch
git checkout -b feature/your-feature-name
- Make your changes
- Follow the existing code style
- Add TypeScript types where needed
- Test your changes locally
- Commit your changes
git commit -m "Add: your feature description" - Push to your fork
git push origin feature/your-feature-name
- Create a Pull Request
- Code Style: Follow the existing TypeScript and React patterns
- Components: Use functional components with TypeScript interfaces
- Styling: Use Tailwind CSS classes, prefer mobile-first approach
- Internationalization: All user-facing text should support both English and Malay
- Performance: Minimize client-side JavaScript, prefer React Server Components
# Run the development server
npm run dev
# or
pnpm dev
# Check for linting issues
npm run lint
# or
pnpm lint
# Build to check for TypeScript errors
npm run build
# or
pnpm buildThe application supports both English and Malay languages. When contributing:
- All user-facing text should be added to the translation files in
lib/i18n.ts - Use the
useTranslations()hook in components - Test both language versions of your changes
Markets are stored in the pasar_malams table in Supabase with the following schema:
CREATE TABLE "public"."pasar_malams" (
"id" character varying(128) NOT NULL PRIMARY KEY,
"name" character varying(256) NOT NULL,
"address" character varying(512) NOT NULL,
"district" character varying(128) NOT NULL,
"state" character varying(64) NOT NULL,
"status" character varying(32) DEFAULT 'Active' NOT NULL,
"description" text,
"area_m2" numeric(12,2),
"total_shop" integer,
"parking_available" boolean DEFAULT false NOT NULL,
"parking_accessible" boolean DEFAULT false NOT NULL,
"parking_notes" text,
"amen_toilet" boolean DEFAULT false NOT NULL,
"amen_prayer_room" boolean DEFAULT false NOT NULL,
"location" jsonb, -- Contains: { "lat": number, "lng": number, "gmaps_link": text }
"schedule" jsonb DEFAULT '[]' NOT NULL, -- Array of schedule objects
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
"shop_list" text -- eg: apam balik, kebab, burger, kuih, nasi berlauk, dll
);The schedule field is a JSONB array with the following structure:
type Schedule = Array<{
day: string; // e.g., "Monday", "Tuesday", etc.
start_time?: string; // e.g., "17:00"
end_time?: string; // e.g., "22:00"
notes?: string; // Optional notes about the schedule
}>The location field contains geographic coordinates:
type Location = {
lat: number; // Latitude
lng: number; // Longitude
}The status field accepts one of the following values:
'Active'(default)'Inactive''Suspended''Closed'
The table includes several indexes for performance:
idx_pasar_malams_state- Index on state columnidx_pasar_malams_state_active- Partial index on state where status = 'Active'idx_pasar_malams_state_district- Composite index on state and districtidx_pasar_malams_status- Partial index on status where status = 'Active'idx_pasar_malams_parking- Index on parking fieldsidx_pasar_malams_amenities- Index on amenity fieldsidx_pasar_malams_schedule_gin- GIN index on schedule JSONB for efficient querying
This guide will help you set up the project for local development using Supabase CLI and Docker.
- Docker Desktop must be installed and running
- Node.js 18.0 or higher
- pnpm (recommended) or npm
pnpm install
# or
npm installCreate a .env.local file in the root directory:
# Supabase Configuration for Local Development
# These values will be provided after running 'npx supabase start'
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_local_anon_key_here
SUPABASE_SERVICE_ROLE_KEY=your_local_service_role_key_here
# Optional Configuration
NEXT_PUBLIC_SUGGEST_MARKET_URL=https://forms.gle/9sXDZYQknTszNSJfA
NEXT_PUBLIC_SITE_URL=http://localhost:3000Note: After running
npx supabase start, copy the API keys from the output and paste them into your.env.localfile.
The project uses Supabase CLI for local development. Supabase CLI runs all services (PostgreSQL, API, Auth, Storage, etc.) in Docker containers.
# Start all Supabase services locally
npx supabase startThis command will:
- Start Docker containers for all Supabase services
- Apply database migrations from
supabase/migrations/ - Run seed data from
supabase/seed.sql(if enabled) - Display connection details including API keys
Expected output:
Started supabase local development setup.
API URL: http://127.0.0.1:54321
GraphQL URL: http://127.0.0.1:54321/graphql/v1
DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
Studio URL: http://127.0.0.1:54323
Inbucket URL: http://127.0.0.1:54324
JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
anon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Copy the API keys from the output and update your .env.local file:
anon keyβNEXT_PUBLIC_SUPABASE_ANON_KEYservice_role keyβSUPABASE_SERVICE_ROLE_KEY
After starting Supabase, you can access the local Supabase Studio dashboard at:
- Studio URL: http://127.0.0.1:54323
This provides a web interface to:
- View and manage your database tables
- Run SQL queries
- Test authentication
- Manage storage buckets
- View API documentation
pnpm dev
# or
npm run devThe application will be available at http://localhost:3000
For a complete reference, see the Supabase CLI Documentation.
# Initialize Supabase in your project (already done in this repo)
npx supabase init
# Start local Supabase services
npx supabase start
# Stop all local Supabase services
npx supabase stop
# Check status of local services
npx supabase status# Pull remote database schema to local
npx supabase db pull
# Push local migrations to remote database
npx supabase db push
# Reset local database (applies all migrations and seed data)
npx supabase db reset
# Create a new migration file
npx supabase migration new migration_name
# Generate TypeScript types from local database
npx supabase gen types typescript --local > types/database.types.ts# Login to Supabase (if using remote project)
npx supabase login
# Link local project to remote Supabase project
npx supabase link --project-ref your-project-ref
# Pull schema from linked remote project
npx supabase db pull --linkedIf npx supabase start fails:
- Ensure Docker Desktop is running
- Check if ports 54321-54327 are available
- Try stopping and restarting Docker Desktop
If you encounter port conflicts:
- Supabase API: 54321
- Database: 54322
- Studio: 54323
- Inbucket (Email): 54324
You can modify these in supabase/config.toml if needed.
If you need to reset your local database:
npx supabase db resetThis will:
- Drop all tables
- Re-apply all migrations
- Re-run seed data
# View Supabase service logs
npx supabase status-
Make database changes: Create a new migration file
npx supabase migration new add_new_column
-
Edit the migration file in
supabase/migrations/ -
Apply the migration:
npx supabase db reset # Resets and applies all migrations -
Generate TypeScript types (if schema changed):
npx supabase gen types typescript --local > types/database.types.ts -
Test your changes in the Next.js app
The application is designed to be deployed on platforms like Vercel, Netlify, or any Node.js hosting service.
For production deployment, create a .env.production file or set environment variables in your hosting platform:
# Supabase Configuration (Production)
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_production_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_production_service_role_key
# Optional
NEXT_PUBLIC_SUGGEST_MARKET_URL=https://forms.gle/9sXDZYQknTszNSJfA
NEXT_PUBLIC_SITE_URL=https://pasarmalam.app- Create a Supabase project at supabase.com
- Get your credentials from Project Settings β API:
NEXT_PUBLIC_SUPABASE_URL: Project URLNEXT_PUBLIC_SUPABASE_ANON_KEY: anon/public keySUPABASE_SERVICE_ROLE_KEY: service_role key (keep secret!)
- Push local migrations to remote:
npx supabase login npx supabase link --project-ref your-project-ref npx supabase db push
- Seed production data (if needed):
# Use Supabase SQL Editor or run seed script
This project is open source and available under the MIT License.
- Thanks to all contributors who help maintain the market data
- Built with amazing open-source tools and libraries
- Inspired by CariTaman, CariSTPM, CariSurau, Sedekah.je
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with π€ for the Malaysian community