revamp について
revampは、旅行者と観光事業者向けのアルメニア旅行マーケットプレイスです。公開中のカタログを基に旅程を作成でき、事業者は審査を経て宿泊施設やツアーを掲載できます。決済機能はまだありません。
主な機能
- 01旅行カタログの検索と絞り込み
- 02地図とアルメニアアトラスでの閲覧
- 03公開中の掲載情報から日別旅程を作成
- 04事業者による宿泊施設・ツアーの管理
- 05投稿内容の審査と公開
活用シーン
- 01地域ごとに宿泊施設、飲食店、ツアーを探す
- 02公開情報を使って日別の旅行を計画する
- 03宿泊施設やツアーの掲載情報を登録・更新する
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://mcp.revampvacations.com/mcpclaude mcp add --transport http com-revampvacations-revamp https://mcp.revampvacations.com/mcp{"mcpServers":{"com-revampvacations-revamp":{"type":"http","url":"https://mcp.revampvacations.com/mcp"}}}Cursor で開く{"servers":{"com-revampvacations-revamp":{"type":"http","url":"https://mcp.revampvacations.com/mcp"}}}VS Code で開く{"mcpServers":{"com-revampvacations-revamp":{"type":"http","url":"https://mcp.revampvacations.com/mcp"}}}{"mcpServers":{"com-revampvacations-revamp":{"serverUrl":"https://mcp.revampvacations.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
4| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| type | enum | いいえ | 掲載タイプを 1 種類に限定します。stay | tour | experience | eat | place |
| limit | integer | いいえ | 結果の最大数(デフォルトは 10)。 |
| query | string | いいえ | タイトル、説明、タグ、料理の種類、都市を対象に全文検索します。 |
| region | string | いいえ | アルメニアの地域または都市。例:'Yerevan'、'Tavush'、'Dilijan'。 |
| cuisine | string | いいえ | レストランの場合:料理の種類または店舗タイプ。例:'Armenian'、'Fast food'。 |
詳細
Revamp トラベルマーケットプレイス
Revamp Travel は、アルメニアの双方向型トラベルマーケットプレイスです。旅行者は、特集記事、検索、インタラクティブなアルメニア地図を通じて、宿泊施設、レストラン、ツアー、地域の体験を探せます。事業者は自分のアカウントを作成して、宿泊施設やツアーの掲載情報を登録できます。任意で、ほかの場所にある既存の掲載情報へのリンクを使ってすばやく入力を補完することもできます。掲載情報は、ほかの場所に表示される前に簡単な審査を受けます。AI 旅行プランナーは、公開中の最新カタログに基づいた旅程を作成します。
現在の状況
このリポジトリはフルスタックアプリケーションです。React SPA が、アカウントと掲載情報を管理するSupabase(Postgres+Auth+Row-Level Security)に直接接続し、その手前に小規模な Express API を配置しています。API の役割は 2 つです。Anthropic を利用した旅行プランナーと、事業者ダッシュボードでのリンクインポート入力補完です。これはマイルストーン Aです。実際のアカウント、事業者が所有する掲載情報、RLS によって強制される所有権、審査・公開のゲートを備えていますが、実際の決済にはまだ対応していません。予約 CTA はそのことを正直に表示します。サインアウト中は「予約するにはサインインしてください」と表示し、サインイン中は無効状態の「決済は近日対応予定」を表示します。表示される料金は実際の値(各掲載情報の price_cents)ですが、まだ請求は行われません。これはマイルストーン B(Stripe)で、CLAUDE.md に範囲が記載されていますが、まだ実装されていません。
| 領域 | 含まれる機能 |
|---|---|
| ホームでの検索・発見 | ヒーロー、統合検索、カテゴリへの導線、注目の掲載情報、地域、地図プレビュー、締めくくりの CTA。 |
| マーケットプレイスカタログ | テキスト検索、カテゴリフィルター、地域フィルター、結果なしの状態、レスポンシブカード、デスクトップ/モバイル向けの地図表示。 |
| 掲載情報 | 宿泊施設/レストラン共通の詳細テンプレートと、GetYourGuide 風の専用ツアー詳細レイアウト。どちらにも、ギャラリー、基本情報、設備、認証状態を考慮した予約 CTA、地図上の位置、関連情報を備えています。 |
アカウント(/login、/signup) | Supabase Auth を利用した、旅行者または事業者としてのセルフサービス登録。 |
事業者ダッシュボード(/dashboard) | 自分の宿泊施設やツアーの掲載情報を追加、編集、削除できます。任意で、貼り付けたリンクから入力を始めることもできます(そのページ独自の公開メタデータから、タイトル、説明、写真への参照を可能な範囲で補完します。スクレイピングは行わず、第三者の写真を自動保存することもありません)。新規掲載情報と再申請は、ほかのユーザーに表示される前に審査に回されます。すでに公開中の掲載情報への編集は即時保存されます。書き込みは Supabase に直接行われ、Row-Level Security によってサインイン中の事業者に制限されます。クライアント側の制御には依存しません。レストランの掲載情報は編集部が管理し、シードデータのみです。 |
審査キュー(/admin) | 審査待ちの掲載情報を承認するか、差し戻せます。管理者アカウントは 1 つです(SQL で自分を管理者に昇格させます。登録画面に切り替え機能はありません)。承認すると即時公開されます。メモを添えて差し戻すと、事業者は修正して再申請できます。 |
AI 旅行プランナー(/plan) | 日ごとの旅程を生成する機能です。Anthropic API をサーバー側から呼び出し、サイトの公開中の最新の宿泊施設、ツアー、レストランのカタログに基づいて旅程を作成します。ANTHROPIC_API_KEY が必要です(下記の「環境」を参照)。 |
| マップ | 価格マーカーと選択状態の同期に対応した、決定的な SVG ベースのアルメニア地図です。外部のマップキーは必要ありません。 |
| ブランド | Revamp のブランドブックを実装しています。小文字の revamp. ワードマーク、re. コンパクトマーク、オレンジの #F15822、チャコールの #212121、白、丸みのある形状、サンセリフ体を採用しています。 |
技術
クライアントは React 19、TypeScript、Vite 7、Tailwind CSS 4、Wouter、Radix UI/shadcn コンポーネント、Lucide アイコン、Sonner を使用し、認証と掲載情報の管理には Supabase(@supabase/supabase-js)に直接接続します。Express、Zod、公式の @anthropic-ai/sdk は、ブラウザーに保持できないシークレットを必要とする唯一のルート、つまり AI 旅行プランナーのために、引き続きサーバー側で使用します。掲載情報の保存に JSON ファイルやプロセス内ストアは、もう使用していません。
要件
Node.js 22 以降、pnpm 10 以降、および Supabase プロジェクトを用意してください(無料プランで問題ありません)。
node --version
pnpm --version
ローカル環境のセットアップ
pnpm install
cp .env.example .env
# fill in VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEY to run against real accounts + listings
# fill in ANTHROPIC_API_KEY to enable /plan
pnpm dev
Supabase の変数を設定しなくても、アプリは起動し、静的な shared/listings.ts のシードデータを読み取り専用のフォールバックとして使って閲覧できます(ListingsContext は offline: true を報告します)。UI の確認には十分ですが、アカウント登録、サインイン、書き込みはすべて失敗します。実際のデータを利用するには、以下の「Supabase のセットアップ」を参照してください。
pnpm dev は concurrently を使って 2 つのプロセスを同時に実行します。Vite(HMR 対応のクライアント)と Express API(tsx watch 経由で server/index.ts を実行し、API_PORT で待ち受けます。デフォルトは 3001 です)です。API プロセスは現在、/api/plan-trip のみを提供します。Vite は /api/* リクエストを API にプロキシするため、Vite が表示する URL を開いてください。API 独自のポートに直接アクセスする必要はありません。
Supabase のセットアップ
-
supabase.com でプロジェクトを作成します。API 設定から Project URL と anon/public key をコピーし、
.envのVITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEYに設定します。 -
supabase/migrations/0001_init.sql、続いてsupabase/migrations/0002_review_gate_and_admin.sqlを、それぞれ 1 回ずつ順番に実行します。SQL Editor に貼り付けるか、CLI でsupabase db push/psqlを使用してください。これらを実行すると、profiles、listings、レビューゲートのトリガー、およびアプリが依存するすべての Row-Level Security ポリシーが作成されます。 -
アプリを起動し(
pnpm dev)、/signupで Operator を選択して実際のアカウントを登録します。このアカウントが、シードカタログを所有するハウスアカウント「Revamp」になります。 -
ローカル環境に限り、同じ API 設定ページから取得した
SUPABASE_SERVICE_ROLE_KEY(秘密にしてください)、SEED_OPERATOR_EMAIL、SEED_OPERATOR_PASSWORD(手順 3 で作成したアカウント)を.envに追加し、次を実行します。pnpm seed:catalogこれにより、
shared/listings.tsのシードデータに含まれる宿泊施設、ツアー、レストランが、そのオペレーターアカウントのもとで実際のlistingsテーブルに取り込まれます。すでに審査済みのコンテンツの一括インポートがレビューキューに入らないよう、自動承認され、すぐに公開されます。再実行しても安全です。既存の行は slug で照合され、スキップされます。レストランのインポートにサービスロールキーが必要な理由については、scripts/seed-catalog.tsの先頭のコメントを参照してください。 -
実際の投稿を審査するには、自分用の別のアカウント(ハウスアカウントではありません)を登録し、管理者に昇格させます。通常どおり
/signupで登録し、Supabase ダッシュボード(Authentication → Users)でユーザー ID を確認してから、SQL Editor で次を実行します。update public.profiles set role = 'admin' where id = '<your-user-id>';セルフサービスで管理者登録できないのは仕様です。そのアカウントでサインインし、
/adminを開くと、保留中のリスティングを承認したり、メモを添えて差し戻したりできます。
検証と本番ビルド
pnpm check
pnpm build
pnpm preview
pnpm build はクライアントを dist/public にビルドし、Express サーバーを dist/index.js にバンドルします。pnpm preview(Vite の静的プレビュー)で配信されるのはクライアントのみです。ビルド後に実際のアプリを実行するには、次のコマンドを使います。
pnpm start
この単一のプロセスが、ビルド済み SPA と /api/plan-trip ルートを、1 つの PORT(デフォルトは 3000)で提供します。
プロジェクト構成
client/
index.html
public/
brand/revamp-mark.svg
images/ # self-hosted brand illustrations (see Assets below)
src/
components/
ui/
ArmeniaMap.tsx
BookingCta.tsx # auth-aware booking CTA, shared by every listing detail layout
BrandMark.tsx
ListingCard.tsx
RequireRole.tsx # route guard for /dashboard
SearchBar.tsx
SiteFooter.tsx
SiteHeader.tsx # includes the auth-aware account menu
TourCard.tsx
TourDetail.tsx
contexts/
ThemeContext.tsx
AuthContext.tsx # Supabase Auth session/profile state (traveler | operator | admin)
ListingsContext.tsx # live catalog: reads/writes the Supabase `listings` table directly
data/
listings.ts # thin compatibility barrel over shared/listings.ts
lib/
api.ts # fetch wrapper for /api/plan-trip and /api/import-listing
supabase.ts # browser Supabase client
slug.ts # slugify() for new listing titles
tourFacts.ts
pages/
Explore.tsx
Home.tsx
ListingPage.tsx
Dashboard.tsx # operator-only: add/edit/delete own stay & tour listings, link-prefill
AdminReview.tsx # admin-only: approve/reject pending listings
Login.tsx
Signup.tsx
MapPage.tsx
Plan.tsx # AI trip planner
Tours.tsx
NotFound.tsx
App.tsx
index.css
main.tsx
server/
index.ts # Express app: JSON body parsing, API routes, static SPA serving
routes.ts # POST /api/plan-trip and POST /api/import-listing — listings CRUD is gone (Supabase + RLS replaced it)
supabase.ts # anon-key server client: planner catalog digest + verifyUser() for import-listing auth
urlPrefill.ts # best-effort OpenGraph/meta-tag fetch for the link-prefill assist, with an SSRF guard
planner.ts # Anthropic API call + prompt/response handling for the trip planner
supabase/
migrations/
0001_init.sql # profiles + listings schema, triggers, and every RLS policy
0002_review_gate_and_admin.sql # pending/review-note columns, admin role, review-gate trigger
scripts/
seed-catalog.ts # one-time import of shared/listings.ts into the live `listings` table
shared/
listings.ts # canonical Listing type, seed data, and constants (client + server + scripts)
const.ts
CLAUDE.md
brandbook-implementation.md
marketplace-spec.md
ENVIRONMENT.md
プロダクトのルート
| URL | 用途 |
|---|---|
/ | 編集者おすすめのホームと統合検索。 |
/explore | 検索とフィルターを使った、すべてのリスティングの一覧。 |
/explore/stay | 宿泊施設カテゴリー。 |
/explore/eat | レストランカテゴリー。 |
/explore/tour | ツアーカテゴリー(GetYourGuide 風の専用ブラウザー)。 |
/map | 地図を中心とした探索。 |
/listing/:slug | 個別リスティングの詳細。 |
/plan | AI 旅行プランナー。 |
/dashboard | オペレーター専用:自分の宿泊施設やツアーのリスティングを追加、編集、削除できます。 |
/admin | 管理者専用:保留中のリスティングを審査し、承認したり、メモを添えて差し戻したりできます。 |
/login | サインイン。 |
/signup | 旅行者またはオペレーターとして登録。 |
Inventory の編集
作業内容に応じて、次の 2 つの方法があります。
- 日常の運用/実際のオペレーター向け:
/signupでオペレーターとして登録し、/dashboardを開いてフォーム UI を使用します。必要に応じて「リンクから入力」を選ぶと、貼り付けた URL の公開メタデータからタイトルと説明を入力できます。書き込みは Supabase のlistingsテーブルに直接行われ、Row-Level Security によって各自のアカウントに適用されます(supabase/migrations/0001_init.sql、0002_review_gate_and_admin.sql)。クライアントだけではこの制御を適用できませんし、適用していません。新規リスティングや再提出されたリスティングはpending状態になり、管理者が/adminで承認するまで他の場所には表示されません。公開済みのリスティングを編集すると、再審査を経ずに保存され、すぐに反映されます(カード、フィルター、地図マーカー、関連コンテンツ、スラッグベースの詳細ページに反映されます。これらはすべてclient/src/contexts/ListingsContext.tsxのListingsContextを通じてライブデータを読み込みます)。 - 新規インストールへのデータ投入:
shared/listings.tsは、pnpm seed:catalog(scripts/seed-catalog.ts)が Supabase のlistingsテーブルにインポートする一度限りのソースです。インポート先は、専用の「Revamp」オペレーターアカウントです。前述の Supabase のセットアップを参照してください。その後にshared/listings.tsを編集しても、影響するのは次回のpnpm seed:catalog実行時のみです(安全に再実行でき、既存の行はスラッグで照合されてスキップされます)。すでに公開中の行には影響しません。レストラン(type: "eat")はシード/編集者専用です。RLS にはtype = 'eat'の挿入ポリシーが一切ないため、専用アカウントを含め、どのオペレーターも通常のアプリから作成、編集、削除できません(shared/listings.tsのEDITABLE_LISTING_TYPESに含まれるのはstayとtourのみです)。
どちらの方法でも、座標はアルメニア国内(lat 38–42、lng 43–47)に収めてください(データベースのチェック制約で適用されます)。また、実在しない顧客評価、レビュー、推薦文、予約数、認証済みであるとの主張は追加しないでください。
ブランドガイドライン
ビジュアルを変更する前に brandbook-implementation.md を読んでください。正式なブランドシステムは、ミニマルで厳格に管理されています。末尾のピリオドを含む小文字の revamp. ワードマーク、コンパクトな re. マーク、オレンジ #F15822、チャコール #212121、ホワイト #FFFFFF を使用してください。指定ブランドフォントは Circular Std です。ライセンス済みのウェブセーフな代替フォントとして、Circular Std が環境にない場合はコードで Manrope を使用します。
アセットとポータビリティ
画像 URL は shared/listings.ts で定義されています。提供される画像はすべて、client/public/images/ にあるセルフホストのブランドイラストです(プレーンな SVG で、外部へのリクエストはありません)。マーケットプレイスには外部画像への依存が一切なく、画像は完全にオフライン/エアギャップ環境でも動作します。実際の写真が用意できたら、いつでも差し替えてください。shared/listings.ts の先頭にある assets マップを更新して再シードするか、/dashboard から各リスティングに image URL を設定します(stay/tour のみ)。
環境
カタログと閲覧機能は、シークレットがなくても読み取り専用で動作します(フォールバックとして静的シードを使用します)。ただし、アカウントと実際の書き込みには VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY が必要です。AI 旅行プランナーには ANTHROPIC_API_KEY が必要です(サーバー側のみで使用され、ブラウザーに送信されることはありません)。リンクからの入力支援機能(POST /api/import-listing)に新しいシークレットは不要です。同じ anon-key の Supabase クライアントを再利用して呼び出し元のサインイン状態を確認し、貼り付けられた URL を直接取得します。シードスクリプト専用の Supabase service-role キーや、任意の ANTHROPIC_MODEL/API_PORT 上書きを含む変数の全一覧は ENVIRONMENT.md を参照してください。
Claude Code
Claude Code は最初に CLAUDE.md を読む必要があります。このファイルには、アーキテクチャ、必ず守るべきコンテンツ/ブランド/支払いの正確性に関する制約、Supabase のデータモデルと RLS の設計、ルートの動作、コンポーネントの規約、アセットのモデル、品質ゲート、よくある変更手順が記載されています。
デプロイに関する注意
このサーバーは、意図的に引き続き2つの役割を担います(CLAUDE.mdを参照してください)。旅行プラン作成のためにAnthropic APIを呼び出すことと、リンク入力の補助として、貼り付けられたURLの公開メタデータを取得することです(サインイン確認とSSRF対策の背後で実行されます)。それ以外のすべて、つまりアカウント、掲載情報、所有権、レビュー/公開のゲートはSupabaseが担い、アプリケーションコードではなくRow-Level Securityとデータベーストリガーで保護されています。実際の決済処理や予約確認はまだありません。これはマイルストーンBとして、この変更と同じく意図的に段階を踏んで追加するアップグレードであり、場当たり的にBookingCta.tsxへ追加するものではありません。単一のNodeプロセスとしてデプロイするには、Supabaseの2つのマイグレーション(0001_init.sql、続いて0002_review_gate_and_admin.sql)を順番に実行し、シードスクリプトを一度実行してから、自分のアカウントをadminに昇格させ(上記のSupabaseのセットアップを参照してください)、pnpm buildでビルドし、PORT、VITE_SUPABASE_URL、VITE_SUPABASE_ANON_KEY、ANTHROPIC_API_KEYを設定してpnpm startを実行します。
Netlify(サーバーレス)
このリポジトリはNetlifyへのデプロイ用に設定されています。APIは常時稼働するプロセスではなく、サーバーレス関数として実行されます。
netlify.toml—pnpm buildでビルドし、dist/publicを公開します。関数ディレクトリはnetlify/functionsです。/*を対象とするprerenderエッジ関数、/api/* → /.netlify/functions/api/:splatのリライト、/robots.txtと/sitemap.xmlの関数へのリライト、wouter用のSPAフォールバック(/* → /index.html)、および/dashboard//adminに対するX-Robots-Tag: noindexヘッダーを設定します。netlify/functions/api.ts—serverless-httpで共有Expressapp(server/app.ts)をラップします。APIはPOST /api/plan-trip、POST /api/import-listing、POST /api/sync-ical、動的なrobots.txt/sitemap.xml、およびGET /api/prerenderです。アカウント、掲載情報、レビューゲートは、RLSのもとでブラウザーからSupabaseへ直接アクセスします。netlify/edge-functions/prerender.ts— SEO/クローラーからの検出性を担います。Denoエッジ関数が、JavaScriptを実行しないクローラー(Googlebot、GPTBot、ClaudeBot、PerplexityBot、Twitterbot、…)にはserver/prerender.tsから実際のサーバーレンダリング済みHTMLを渡し(/api/prerender経由)、通常の訪問者には変更を加えていないSPAを返します。ブラウザーおよびJavaScriptを実行するクローラー向けのページごとの実際の<title>/meta/OG/JSON-LDは、client/src/hooks/useDocumentMeta.tsから取得します。新しい依存関係も環境変数も不要です。レンダラーは手書きのHTMLで、robotsとsitemapのオリジンは各リクエストから取得します。- 環境変数(Site configuration → Environment variables):
VITE_SUPABASE_URL、VITE_SUPABASE_ANON_KEY— ビルド時(Viteがクライアントにインライン化します)と関数の実行時(プランナーが公開済みカタログを読み込み、/api/import-listingがanon keyを使って呼び出し元のベアラートークンを検証します)の両方で必要です。初回ビルドの前に設定してください。値には完全なhttps://<project-ref>.supabase.coが必要です。そうでない場合、クライアントは読み取り専用のshared/listings.tsシードにフォールバックします。これらを変更した場合は、変数を保存するだけではなく、新たにビルド(再デプロイ)する必要があります。ANTHROPIC_API_KEY(および任意のANTHROPIC_MODEL)—/api/plan-trip用の実行時のみの設定です。- Netlifyには
SUPABASE_SERVICE_ROLE_KEYを設定しないでください。これはローカルで一度だけ実行するpnpm seed:catalog専用です。
- GitHubリポジトリをNetlifyに接続すると、
mainへのプッシュごとに継続的にデプロイされます。Supabaseのマイグレーション(0001~0005。0005には運営者による写真アップロード用のlisting-photosStorageバケットが含まれます)、pnpm seed:catalog、および管理者への昇格は、それぞれ別途一度だけ実行する手順です(Supabaseのセットアップを参照してください)。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。