HungryHub Restaurant Registration System
Description / Background
The HungryHub Restaurant Registration System is a comprehensive platform for onboarding new restaurant partners. It streamlines the process of bringing new restaurants onto the HungryHub platform by providing a user-friendly registration form for partners and an internal operations portal for staff to review, enrich, and submit applications to the HungryHub production system.
The system consists of two main portals that work together to ensure efficient and accurate restaurant onboarding:
- Partner Onboarding Portal - Public-facing form for restaurant partners to register
- Operations Team Portal - Internal admin tool for reviewing and submitting restaurant applications
This system supports multi-country operations (Thailand, Singapore, Malaysia) with country-specific fields and localization.
Objectives
- Simplify the restaurant partner onboarding process
- Provide a structured 4-step registration flow for restaurant partners
- Enable operations staff to review and enrich restaurant data before submission
- Integrate with Google Places API for accurate location data
- Support multiple countries with localized fields and options
- Automate data submission to HungryHub production system via N8N workflows
- Maintain data consistency through database-driven tags and dropdowns
- Send automated confirmation emails to partners upon registration
Scope
Partner Onboarding Portal Features
- Multi-language support (Thai/English toggle)
- Google Places integration for address autocomplete
- Country-specific fields (Thailand, Singapore, Malaysia)
- 4-step registration process:
- Business Information
- Restaurant Details
- Banking Information
- Review & Submit
- Real-time form validation
- Confirmation page with next steps
Operations Team Portal Features
- Application list view with status tracking
- Detailed restaurant data entry with additional fields
- Data enrichment via N8N integration
- Submit to HungryHub API with HMAC authentication
- Advanced scheduling with inventory groups
- SEO metadata management in multiple languages
Admin Manager Features
- Form section management
- Question configuration
- Tag management for dropdowns
Location
Base URL: (https://onboarding.hungryhub.com)
- Partner Onboarding Portal:
/(Home page) - Operations Team Portal:
/operations-team - Admin Manager:
/admin_manager - Login Page:
/login
How to find Restaurant Applications
As Operations Staff:
- Navigate to
/operations-team - Login with credentials (default:
admin@hungryhub.com/Admin@123) - View all pending restaurant applications in the list
- See submission date, restaurant name, country, and status
- Click on any application to load detailed information
As Restaurant Partner:
- Navigate to the home page
/ - Complete the 4-step registration form
- Submit application
- Receive confirmation email with application details
How to Register a New Restaurant
Step 1: Business Information
- Select country (Thailand, Singapore, or Malaysia)
- Enter booking alert email and SMS number
- Provide primary contact person details:
- Name
- Phone number
- Search restaurant via Google Places
- Enter basic restaurant information:
- Restaurant name (English/Thai)
- Phone number
- Full address
- Latitude/Longitude (auto-filled from Google Places)
Step 2: Restaurant Details
- Set operating hours schedule:
- Select days of the week
- Add multiple time slots per day
- Select cuisine types (multi-select)
- Select dining styles (multi-select)
- Select facilities (multi-select)
- Choose location tags and popular zones
- Select city, MRT station, and nearby malls
- Enter restaurant descriptions:
- English description
- Thai description
- Add SEO metadata:
- Meta title
- Meta description
- Meta keywords
Step 3: Banking Information
- Enter bank details for payments:
- Bank name
- Account number
- Account holder name
- Provide company registration information:
- Company name
- Tax ID
- Registration number
- Add accounting team contact details:
- Name
- Phone number
Step 4: Review & Submit
- Review all entered information
- Edit any section if needed
- Submit application
- View confirmation page with next steps
- Receive confirmation email
Sequence Diagram / Flow
Partner Registration Flow
Operations Team Flow
ERD
Main Tables
restaurants_applications
- id (Primary Key)
- submission_date
- country
- status
- restaurant_name_en
- restaurant_name_th
- contact_name
- contact_email
- contact_phone
- booking_alert_email
- booking_alert_sms
- address
- latitude
- longitude
- google_place_id
- operating_hours (JSONB)
- cuisines (Array)
- dining_styles (Array)
- facilities (Array)
- location_tags (Array)
- popular_zones (Array)
- city_id
- mrt_station_id
- mall_id
- description_en
- description_th
- meta_title
- meta_description
- meta_keywords
- bank_name
- account_number
- account_holder_name
- company_name
- tax_id
- registration_number
- accounting_contact_name
- accounting_contact_email
- accounting_contact_phone
- created_at
- updated_at
users
- id (Primary Key)
- password_hash
- role
- failed_login_attempts
- lockout_until
- created_at
- updated_at
form_sections
- id (Primary Key)
- name
- display_order
- active
form_questions
- id (Primary Key)
- section_id (Foreign Key)
- question_text
- field_type
- required
- display_order
database_tags
- id (Primary Key)
- tag_type (cuisine, dining_style, facility, location_tag, popular_zone, city, mrt_station, mall, bts_station)
- name_en
- name_th
- country_code
- active
- display_order
Frontend Implementation
Technology Stack
- Framework: React 18 with TypeScript
- Build Tool: Vite
- Styling: Tailwind CSS + Shadcn/UI components
- Routing: Wouter
- Data Fetching: TanStack Query
- Form Management: React Hook Form
- State Management: React Context API
Key Components
Partner Portal Components:
OnboardingForm.tsx- Main registration form wrapperStep1BusinessInfo.tsx- Business information stepStep2RestaurantDetails.tsx- Restaurant details stepStep3BankingInfo.tsx- Banking information stepStep4Review.tsx- Review and submit stepGooglePlacesAutocomplete.tsx- Google Places integrationOperatingHoursScheduler.tsx- Schedule managementCountrySelector.tsx- Country selection with flagsLanguageToggle.tsx- Thai/English language switcher
Operations Portal Components:
ApplicationList.tsx- List of pending applicationsApplicationDetail.tsx- Detailed application viewRestaurantDataForm.tsx- Comprehensive data entry formEnrichDataButton.tsx- Data enrichment triggerSubmitToAPI.tsx- HungryHub API submissionInventoryGroupManager.tsx- Advanced scheduling
Admin Manager Components:
FormSectionManager.tsx- Section CRUD operationsQuestionManager.tsx- Question configurationTagManager.tsx- Tag management interface
Country-Specific Behavior
Thailand:
- Shows BTS stations dropdown
- Displays Thai language fields
- Thai popular zones and cities
- Thai MRT stations
Singapore:
- Hides Thai-specific fields
- Shows Singapore MRT stations
- Singapore popular zones and cities
- SGD currency
Malaysia:
- Hides Thai-specific fields
- Shows Malaysian cities and MRT stations
- Malaysian popular zones
- MYR currency
Validation Rules
- Email format validation
- Phone number format (country-specific)
- Required field validation
- Address validation via Google Places
- Operating hours validation (no overlapping slots)
- Bank account number format
- Tax ID format (country-specific)
Backend Implementation
Core Features
- Added Admin HMAC authentication middleware for secure API access
- Implemented
Api::Admin::BaseControllerwith error handling and authentication - Created
POST /api/admin/restaurantsendpoint for restaurant onboarding - Built
RestaurantService::CreateFromApiservice for creating restaurants with nested data (owner, tags, locations) - Implemented
RestaurantService::TagAssignmentfor robust tag assignment with search index updates - Auto-confirm owner email on API onboarding by setting
confirmed_at: Time.currentin owner creation - Added request body read and rewind functionality in
EncryptableHelperfor HMAC signature verification - Removed obsolete documentation files (RESTAURANT_ONBOARDING_API.md, RESTAURANT_ONBOARDING_VALIDATION_RULES.md)
Technology Stack
- Framework: Ruby on Rails (HH-Server), Express.js with TypeScript (Onboarding Portal)
- Database: PostgreSQL (Neon)
- ORM: Drizzle ORM (Portal), Active Record (Rails)
- Authentication: Session-based with bcrypt (Portal), HMAC authentication (Admin API)
- Security: HMAC authentication for HungryHub API calls
PRD & Task
- GitHub Repository: [hungryhub-onboarding-system]
- N8N Workflows:
- Confirmation Email Workflow
- Data Enrichment Workflow
- Restaurant Creation Workflow
Design
Partner Portal Design
- Clean, modern interface with step indicators
- Progress bar showing completion percentage
- Responsive design for mobile and desktop
- Country flag icons for country selection
- Thai/English language toggle in header
- Google Maps integration for visual confirmation
- Multi-select dropdowns with search functionality
- Time picker for operating hours
- Drag-and-drop for image uploads (future enhancement)
Operations Portal Design
- Dashboard-style layout
- Sidebar navigation
- Data table with sorting and filtering
- Tabbed interface for different data sections
- Inline editing capabilities
- Action buttons (Enrich Data, Save to HungryHub)
- Status badges for application states
- Toast notifications for actions
Admin Manager Design
- CRUD interface for all manageable entities
- Drag-and-drop for reordering
- Inline editing
- Bulk actions support
- Import/export functionality
API Blueprint
Partner Portal APIs
| Method | Path | URL | Description | Payload |
|---|---|---|---|---|
| POST | /api/onboarding/submit | Full URL | Submit restaurant application | { businessInfo, restaurantDetails, bankingInfo } |
| GET | /api/tags/:tagType | Full URL | Get tags by type | Query: type=cuisine|dining_style|facility|etc |
| GET | /api/tags/country/:countryCode | Full URL | Get country-specific tags | Path: countryCode=TH|SG|MY |
Operations Portal APIs
| Method | Path | URL | Description | Payload |
|---|---|---|---|---|
| GET | /api/applications | Full URL | List all applications | Query: status, country, page, limit |
| GET | /api/applications/:id | Full URL | Get application details | Path: id |
| POST | /api/applications/:id/enrich | Full URL | Trigger N8N enrichment | { applicationId } |
| POST | /api/applications/:id/submit | Full URL | Submit to HungryHub API | { restaurantData, googleReserveData, seoData } |
| PUT | /api/applications/:id | Full URL | Update application | { ...updatedFields } |
Authentication APIs
| Method | Path | URL | Description | Payload |
|---|---|---|---|---|
| POST | /api/auth/login | Full URL | User login | { email, password } |
| POST | /api/auth/logout | Full URL | User logout | None |
| GET | /api/auth/check | Full URL | Check authentication | None |
Webhook Integration
Partner Portal Webhook
- URL:
https://n8n.hungryhub.com/webhook/confirmation_email - Method: POST
- Purpose: Sends confirmation email to partner after submission
- Trigger: When partner submits application via onboarding form
- Payload:
{
"restaurantName": "string",
"contactName": "string",
"contactEmail": "string",
"applicationId": "string",
"submissionDate": "ISO 8601 date"
}
Operations Team Webhook
- URL:
https://n8n.hungryhub.com/webhook/add_restau_to_db - Method: POST
- Purpose: Formats data and creates restaurant in HungryHub system
- Trigger: When operations staff clicks “Save to HungryHub System”
- Authentication: HMAC signature in headers
- Headers:
{
"X-App-Id": "HungryHub App ID",
"X-Timestamp": "Unix timestamp",
"X-Signature": "HMAC SHA-256 signature"
}
- Payload: Complete restaurant data in HungryHub API format
DB Schema / Database Migration
Database Tags
The system uses database-driven tags for all dropdown options:
| Tag Type | Count | Description |
|---|---|---|
| Cuisine | 40 | Restaurant cuisine types (Italian, Japanese, Thai, etc.) |
| Dining Style | 31 | Restaurant styles (Casual, Fine Dining, Rooftop, etc.) |
| Facility | 29 | Amenities (Parking, WiFi, Pet Friendly, Wheelchair Access, etc.) |
| Location Tag | 188 | Geographic areas and neighborhoods |
| Popular Zone | 128+ | Popular areas by country |
| City | 84+ | Cities across Thailand, Singapore, Malaysia |
| MRT Station | 172+ | Train stations across all countries |
| Mall | 194+ | Shopping malls for proximity tagging |
| BTS Station | 62 | Bangkok Skytrain stations (Thailand only) |
Migration Scripts
Initial Schema:
CREATE TABLE restaurants_applications (
id SERIAL PRIMARY KEY,
submission_date TIMESTAMP DEFAULT NOW(),
country VARCHAR(2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
restaurant_name_en VARCHAR(255) NOT NULL,
restaurant_name_th VARCHAR(255),
contact_name VARCHAR(255) NOT NULL,
contact_email VARCHAR(255) NOT NULL,
contact_phone VARCHAR(50) NOT NULL,
booking_alert_email VARCHAR(255),
booking_alert_sms VARCHAR(50),
address TEXT NOT NULL,
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
google_place_id VARCHAR(255),
operating_hours JSONB,
cuisines TEXT[],
dining_styles TEXT[],
facilities TEXT[],
location_tags TEXT[],
popular_zones TEXT[],
city_id INTEGER,
mrt_station_id INTEGER,
mall_id INTEGER,
description_en TEXT,
description_th TEXT,
meta_title VARCHAR(255),
meta_description TEXT,
meta_keywords TEXT,
bank_name VARCHAR(255),
account_number VARCHAR(100),
account_holder_name VARCHAR(255),
company_name VARCHAR(255),
tax_id VARCHAR(100),
registration_number VARCHAR(100),
accounting_contact_name VARCHAR(255),
accounting_contact_email VARCHAR(255),
accounting_contact_phone VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'operations',
failed_login_attempts INTEGER DEFAULT 0,
lockout_until TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE database_tags (
id SERIAL PRIMARY KEY,
tag_type VARCHAR(50) NOT NULL,
name_en VARCHAR(255) NOT NULL,
name_th VARCHAR(255),
country_code VARCHAR(2),
active BOOLEAN DEFAULT true,
display_order INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_applications_status ON restaurants_applications(status);
CREATE INDEX idx_applications_country ON restaurants_applications(country);
CREATE INDEX idx_applications_submission_date ON restaurants_applications(submission_date);
CREATE INDEX idx_tags_type ON database_tags(tag_type);
CREATE INDEX idx_tags_country ON database_tags(country_code);
Environment Variables
Required Secrets
| Variable | Description | Example |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | postgresql://user:pass@host:5432/dbname |
VITE_GOOGLE_MAPS_API_KEY | Google Maps API key | AIza... |
HUNGRYHUB_APP_ID | HungryHub API app ID | hh_app_123 |
HUNGRYHUB_APP_SECRET | HungryHub API secret | secret_key_xyz |
HUNGRYHUB_API_URL | HungryHub API base URL | https://api.hungryhub.com |
SESSION_SECRET | Express session secret | random_secret_string |
N8N_WEBHOOK_URL | N8N webhook base URL | https://n8n.hungryhub.com/webhook |
User Roles
| Role | Access | Capabilities |
|---|---|---|
| Partner | Public | Submit restaurant application, receive confirmation |
| Operations Staff | Login required | Review, edit, enrich, and submit applications to HungryHub |
| Admin | Login required | Manage form fields, tags, and system configuration |
Improvement:
| Feature Name | Date | What Changed | Description |
|---|---|---|---|