システム概要
本プロジェクトは、Spring Boot(Java)をバックエンド基盤とし、Vue.js と Element Plus を用いたリアクティブなフロントエンドを備えた不動産販売管理システムです。MySQL を永続化ストアとして利用し、RBAC(役割ベースアクセス制御)に基づく多段階権限設計を実装しています。
アーキテクチャと技術スタック
- バックエンド: Spring Boot 2.7.x / MyBatis-Plus 3.5.x / Lombok / Spring Security
- フロントエンド: Vue 3(Composition API)/ Element Plus / Axios / Vue Router
- データベース: MySQL 8.0(InnoDB)、UTF8MB4 文字セット対応
- ビルド・デプロイ: Maven(v3.8+)、npm(v16+)
ユーザータイプと機能範囲
| 役割 | 主な機能 |
|---|---|
| 一般ユーザー | 物件検索・フィルタリング、お気に入り登録、予約申請、評価投稿、プロフィール管理 |
| 営業担当者 | 担当物件のステータス更新、来訪予約承認/拒否、顧客メモ追加、成約状況可視化ダッシュボード |
| システム管理者 | 全ユーザー管理、物件カテゴリ/間取り/地域マスタ登録、注文履歴監査、権限グループ設定、ログ監視 |
環境要件
- JDK 11 以上(推奨:OpenJDK 17)
- MySQL 8.0.26+(タイムゾーン設定:
SYSTEMorAsia/Shanghai) - Node.js v16.14+(pnpm 推奨)
- IDE: IntelliJ IDEA(Spring Boot Plugin)または VS Code(Vue Language Features)
セットアップ手順
- データベース初期化
mysql -u root -p < database/init_schema.sqlを実行し、スキーマと初期データを読み込む。 - バックエンド起動
mvn clean compile spring-boot:run -Dspring.profiles.active=dev(application-dev.yml を事前に編集) - フロントエンド構築
cd frontend && pnpm install && pnpm run serve - アクセスURL
フロントエンド: http://localhost:5173
管理者ダッシュボード: http://localhost:5173/admin
(デフォルトアカウント:admin/Admin@123)
主要API設計例(Spring Bootコントローラー)
// 物件検索(ページネーション付き)
@PostMapping("/api/v1/properties/search")
@ResponseBody
public PageResult<PropertyDto> searchProperties(@RequestBody PropertyQuery query) {
return propertyService.searchWithPagination(query);
}
// 営業担当者の担当物件一覧(権限付与済み)
@GetMapping("/api/v1/sales/{salesId}/properties")
@ResponseBody
public List<PropertySummary> listAssignedProperties(@PathVariable Long salesId) {
return propertyService.findBySalesId(salesId);
}
// 予約ステータス更新(原子的トランザクション)
@PutMapping("/api/v1/appointments/{id}/status")
@Transactional
public Result updateAppointmentStatus(
@PathVariable Long id,
@RequestBody @Valid AppointmentStatusUpdate update) {
appointmentService.updateStatus(id, update.getNewStatus(), update.getRemarks());
return Result.success();
}
Vueコンポーネント例(物件リスト表示)
<template>
<el-table :data="propertyList" stripe>
<el-table-column prop="name" label="物件名" width="220" />
<el-table-column prop="area" label="面積(m²)" width="100" />
<el-table-column prop="price" label="価格(万円)" :formatter="formatPrice" />
<el-table-column label="ステータス">
<template #default="{ row }">
<el-tag :type="row.status === 'AVAILABLE' ? 'success' : 'warning'">
{{ statusMap[row.status] }}
</el-tag>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { fetchProperties } from '@/api/property'
const propertyList = ref([])
const statusMap = { AVAILABLE: '在庫あり', SOLD: '成約済', RESERVED: '仮押さえ' }
onMounted(async () => {
propertyList.value = await fetchProperties({ page: 1, size: 10 })
})
const formatPrice = (row) => (row.price / 10000).toFixed(1) + '万'
</script>
注意事項
- プロジェクトディレクトリパスに日本語・空白・特殊文字を含めないでください(ファイルアップロード失敗の原因になります)
- MySQL の strict mode を無効化する場合は、
sql_modeからSTRICT_TRANS_TABLESを除外してください - Element Plus のテーマカスタマイズは
src/styles/element-variables.scssで管理 - JWT トークンの有効期限はデフォルトで 2 時間に設定されています(
application.ymlで変更可能)