پرش به محتوای اصلی
友田 陽大

A restaurant-matching & booking platform for inbound travelers

Swipe UI × 5 languages × a generative-AI data pipeline | Go/Echo clean architecture + Next.js 16 + AWS serverless | full-stack across frontend / API / auth / data pipeline

Client

A tourism / inbound service (a restaurant concierge for inbound travelers, accessed via a QR code in the hotel room) | Setup: GitHub-based team development | Coverage: partner restaurants in central Tokyo

My role

In GitHub-based team development, joined as a full-stack engineer spanning the frontend (Next.js 16 / React 19), the backend API (Go / Echo), the auth foundation (Cognito custom auth), and the data pipeline (Python / generative AI). Worked on designing and implementing the multilingual domain model, the swipe UI, passwordless auth, and the AI-driven restaurant-data localization pipeline.

Challenge (Situation & Task)

Inbound travelers, hampered by the language barrier and information asymmetry, struggle to find "a restaurant that fits my taste," can't read menus, and find the booking channels (phone, Japanese-only sites) hard to use. Meanwhile hotels are too busy to give every guest careful, multilingual recommendations and booking support.

"Breaking the language barrier" had to run through not just the UI copy but the data, the auth, and operations. The essential difficulties were four.

  1. Multilingual down to the data (5 languages): in Japanese, English, Simplified Chinese, Traditional Chinese, and Korean — not just UI copy but restaurant names, addresses, descriptions, courses, signature dishes, and allergens (28 kinds) had to be localized. Translating thousands of restaurants by hand breaks on cost, quality, and freshness alike.

  2. A language-agnostic discovery experience: Japanese gourmet sites are information-dense and hard for foreigners. It had to combine an operation anyone can use intuitively regardless of native language (swiping) with practical suggestions that account for time of day, current location, budget, and cuisine.

  3. Eliminating login friction: forcing password management on travelers who leave within days causes drop-off, and Cognito's standard password auth didn't fit the low-friction, multilingual requirement.

  4. Production quality kept by a small team: the scalability to absorb traffic from room QR codes, the freshness of restaurant data, and the consistency and notification of reservation status all had to fit into a form a small team can maintain.

Why these technologies (Rationale)

  • Go 1.24 + Echo v4 + google/wire (clean architecture × DI): clearly separated domain / usecase / infrastructure / handler and wired them with DI. Runs on ARM64 Lambda for low cost and fast starts, and can also run as a local HTTP server on :8080 — a dual-mode setup that preserves DX.

  • MySQL 8.0 + sqlc (type-safe raw SQL): complex restaurant-search SQL (19 queries, ~2,250 lines) type-checked at compile time. Avoids ORM opacity and keeps queries explicit and safe.

  • A MultiLanguageText type embedded in the domain model: 5 languages (ja / en / Simplified / Traditional / Korean) placed at the center of the design rather than bolted on, so every text field is structurally multilingual.

  • A swipe UI with @react-spring/web + @use-gesture/react: language-agnostic, intuitive operation with near-native gesture physics (Like / Nope / SuperLike).

  • Passwordless auth (Cognito CUSTOM_AUTH): an email magic link delivers low-friction sign-in that never asks travelers for a password.

  • A generative-AI data pipeline (OpenAI GPT-4o structured outputs): 5-language enrichment of restaurant data, cuisine-domain-aware contextual translation, and phonetic-reading generation — type-safe via Pydantic schemas. Achieves scale and quality impossible by hand.

  • Next.js 16 App Router + Vercel: multi-environment (dev / staging / prod) automatic deployment, with image optimization and dynamic imports for perceived speed.

What I did (Action)

  • [5-language coverage down to the data] Localized the entire dataset — not just UI copy but restaurant names, addresses, descriptions, courses, signature dishes, allergens (28 kinds), and discovery hashtags (84 kinds) — into 5 languages. The frontend relies on no external i18n library: JSON dictionaries + a custom getTranslator / useTranslation hook + a Zustand language store implement dot-notation keys, parameter interpolation, and English fallback.

  • [A language-agnostic discovery experience] Implemented swiping (Like / Nope / SuperLike) with @react-spring/web + @use-gesture/react, designing an image-centric, minimal-text UX anyone can use intuitively regardless of native language.

  • [Practical recommendation logic] The backend's restaurant selection determines the business-day boundary (5 a.m.), holidays / holiday eves, and same-day vs. advance booking, narrows candidates by walking-distance from the current location, budget range, and cuisine, then samples randomly to keep suggestions diverse.

  • [Passwordless auth] Implemented Cognito CUSTOM_AUTH's 3 triggers (DefineAuthChallenge / CreateAuthChallenge / VerifyAuthLink) in Go. Sends a 5-language email magic link via SES and updates email_verified on link verification. Link parameters are sanitized with url.QueryEscape to prevent injection.

  • [Generative-AI data pipeline] Collected and normalized publicly available restaurant data (rate-limited, deduplicated down to a few thousand restaurants) and enriched it with GPT-4o structured outputs for 5-language localization, contextual translation, and phonetic readings. Staff review it in a Streamlit screen before submission to the API, and images are organized systematically in S3.

  • [Type safety and tests] On the Go side, type-safe SQL via sqlc and 39 test files with table-driven tests + gomock; CI runs -race -shuffle to catch data races and order dependence. The frontend guards component quality with TypeScript strict + zod + Storybook / Vitest.

  • [Serverless operations] Split the API, reservation-status updates (EventBridge Scheduler), and Slack notifications (SQS) into 3 ARM64 Lambdas. Structured JSON logs carry request / trace IDs, and secrets are managed as SecureString in SSM Parameter Store. CI/CD runs on GitHub Actions + golangci-lint (~40 rules).

The design philosophy running through the product was to guarantee "breaking the language barrier" structurally — through data, auth, and operations, not just surface UI.

Putting multilingual at the center of the domain: The backend embeds a MultiLanguageText type (5 languages) in the domain model, structurally localizing every text field down to restaurants, courses, and allergens. The frontend relies on no external i18n library, achieving lightweight language switching with a custom hook + Zustand. Translation at the thousands-of-restaurants scale — impossible by hand — combines quality and scale via OpenAI GPT-4o structured outputs (typed with Pydantic) plus cuisine-domain contextual translation and phonetic-reading generation.

Friction-free auth and language-independent operation: Optimizing for short-stay travelers, implemented Cognito CUSTOM_AUTH's passwordless email magic link as 3 Go Lambda triggers. The discovery experience is a swipe built on @react-spring/web + @use-gesture/react, going all-in on image-centric, minimal text.

Type safety and serverless to keep production quality with a small team: Go combines an Echo + google/wire clean architecture with sqlc's type-safe SQL, running 39 tests in CI with -race -shuffle to prevent regressions. By splitting the API, reservation-status updates (EventBridge), and notifications (SQS) into 3 ARM64 Lambdas — and building in structured logs, trace IDs, and SSM secret management — production-grade quality is maintainable even by a small team.

Key technical decisions

  • Go + Echo + google/wire: a DI-wired clean architecture (dual-mode: ARM64 Lambda / local HTTP)

  • MySQL 8.0 + sqlc: raw SQL type-checked at compile time, keeping complex restaurant search safe

  • MultiLanguageText (5 languages) embedded in the domain: localized down to the data, not just the UI

  • @react-spring/web + @use-gesture/react: a language-agnostic swipe UX

  • Cognito CUSTOM_AUTH passwordless: an email magic link removes login friction

  • OpenAI GPT-4o structured outputs: type-safe 5-language enrichment, contextual translation, and phonetic readings for restaurant data

Responsibilities

  • Frontend development (Next.js 16 / React 19 / styled-components / TanStack Query / Zustand)
  • Backend API development (Go / Echo / google/wire / sqlc / MySQL)
  • Auth-foundation implementation (Cognito custom auth, passwordless, SES)
  • Generative-AI data-pipeline implementation (Python / OpenAI GPT-4o / Streamlit / S3)
  • Multilingual domain design (5-language MultiLanguageText) and swipe-UX design
  • Serverless operations (AWS Lambda / EventBridge / SQS) and tests / CI/CD

Technologies

Go
Echo
google/wire
sqlc
MySQL
Next.js
React
TypeScript
styled-components
@react-spring/web
@use-gesture/react
TanStack Query
Zustand
zod
react-hook-form
Python
OpenAI GPT-4o
Streamlit
Pydantic
AWS Lambda
Amazon Cognito
Amazon SES
Amazon SQS
Amazon EventBridge
Amazon S3
AWS SSM Parameter Store
Google Maps
Terraform
Vercel
GitHub Actions
golangci-lint
Vitest
Storybook
gomock

Results in numbers

Languages supported
5languagesJA, EN, Simplified Chinese, Traditional Chinese, Korean — localized down to restaurant data, not just UI copy.
Automated tests (API)
39filesTable-driven + gomock; CI runs -race / -shuffle to catch data races and order dependence.

Results

  • Localized not just UI copy but restaurants, courses, and allergens into 5 languages (JA, EN, Simplified, Traditional, Korean), breaking the language barrier structurally
  • Enriched and structured thousands of restaurants with generative AI (GPT-4o structured outputs), building a content foundation impossible by hand
  • Realized a language-agnostic swipe UI (@react-spring/web + @use-gesture/react) that lets anyone choose intuitively regardless of native language
  • Removed login friction for short-stay travelers with passwordless auth (email magic link / Cognito CUSTOM_AUTH)
  • Implemented a regression-resistant API with a Go/Echo clean architecture + sqlc type-safe SQL + 39 tests (CI runs `-race -shuffle`)
  • Split the API, reservation-status updates (EventBridge), and notifications (SQS) into 3 ARM64 serverless Lambdas for low-cost operation
  • Optimized perceived speed with Next.js 16 / Vercel multi-environment CI/CD (dev / staging / prod), image optimization, and dynamic imports

同様の課題、抱えていませんか?

あなたのビジネス課題も、最新の技術で解決できます。 まずは30分の無料技術相談から、状況をお聞かせください。

自社の課題もSaaS化できるか相談する

プロジェクト単位(請負)・技術顧問、どちらにも対応可能です

View all case studies