キャンプ場のレビュー投稿サイトをフルスタックで実装した学習プロジェクトです。
ユーザー登録・ログイン、キャンプ場のCRUD、レビュー投稿、画像アップロード、地図表示など、Webアプリケーションに必要な機能を一通り実装し、「認証・認可」「データモデリング」「外部API連携」をまとめて経験することを目的としています。
コンセプト:
キャンプ場を探しているユーザーが、場所・写真・レビューを見ながらキャンプ場を比較できるサービス。
主な機能:
- ユーザー管理
- サインアップ / ログイン / ログアウト(Passport.js)
- ログイン必須ページへのアクセス制御
- キャンプ場管理
- キャンプ場の新規作成 / 編集 / 削除 / 詳細表示
- 位置情報(Mapbox)と画像(Cloudinary)を紐づけて表示
- レビュー機能
- 各キャンプ場へのレビュー投稿 / 削除
- レビューのバリデーションと権限チェック
- 地図表示
- Mapbox を用いたキャンプ場位置のマッピング
- 画像アップロード
- Cloudinary への画像アップロード・削除とDBの同期
バックエンド
- Node.js / Express
- MongoDB / Mongoose
- Passport.js(ローカル認証)
- Joi(リクエストバリデーション)
- Express-session / connect-flash(セッション管理・フラッシュメッセージ)
フロントエンド
- EJS(テンプレートエンジン)
- Bootstrap(UIコンポーネント・レスポンシブ対応)
- カスタムCSS
外部サービス / インフラ
- Cloudinary(画像ストレージ)
- Mapbox(地図表示)
- (デプロイ先想定:Heroku / Render)
ディレクトリ構成(抜粋)
app.js
アプリケーションエントリポイント。Expressの初期化、ミドルウェア設定、ルーティング、エラーハンドリングを定義。routes/
ルーティング層。campgrounds,reviews,usersなどのリソースごとに分割。controllers/
各ルートのビジネスロジックを担当。ルーティングとロジックを分離し、見通しを良くする構成。models/
Mongoose スキーマ・モデル定義(User, Campground, Review)。views/
EJS テンプレート。レイアウト・パーシャルを活用して共通化。middleware.js
認証チェック、権限チェック、エラーハンドリングなどの共通ミドルウェア。schemas.js
Joi によるリクエストバリデーションスキーマ。
設計上意識した点
- RESTfulなルーティング
/campgrounds,/campgrounds/:id,/campgrounds/:id/reviewsなど、リソース指向のURL設計- HTTPメソッド(GET/POST/PUT/DELETE)と役割を明確に対応付け
- 責務分離
- ルート定義とビジネスロジックを
routes/とcontrollers/に分離 - 認証・認可ロジックを
middleware.jsに集約
- ルート定義とビジネスロジックを
- バリデーションの二重化
- Joi によるサーバーサイドバリデーション
- フロント側の入力チェックも併用し、ユーザー体験と安全性を両立
- Passport.js を用いてローカル認証を実装
- 「ログインしていないユーザーは投稿できない」「投稿者本人のみ編集・削除可能」といった権限管理をミドルウェアで共通化
- 認証状態をテンプレートに渡し、ヘッダーの表示内容(ログイン/ログアウトボタンなど)を動的に切り替え
- Campground – Review – User の関係を Mongoose でモデリング
- Campground に Review の参照を持たせ、削除時に関連レビューも削除
- Joi を使って、キャンプ場作成・レビュー投稿時の入力をサーバー側で検証
- 「フロントだけでなくサーバー側でも必ず検証する」という実務的な観点を意識
- 画像アップロード時に Cloudinary に保存し、そのURLをDBに保持
- キャンプ場削除時には Cloudinary 側の画像も削除し、データの整合性を保つように実装
- Mapbox でキャンプ場の位置を地図上に表示し、ピン・ポップアップ・ズームなどのUIを実装
- 共通エラーハンドラを用意し、予期せぬエラーでもユーザーにフレンドリーなメッセージを表示
connect-flashを使って、成功・失敗メッセージを画面上部に表示し、操作結果が分かりやすいUIを意識- 非同期処理は
async/awaitに統一し、エラー時の挙動を追いやすく整理
※ 実際の値は .env などで管理する想定です。
CLOUDINARY_CLOUD_NAMECLOUDINARY_KEYCLOUDINARY_SECRETMAPBOX_TOKENDB_URL(MongoDB接続URL)SESSION_SECRET
git clone https://github.com/cloudtechmkkh/YelpCamp.git
cd YelpCamp
npm install
npm run start
# または
node app.js