Skip to content

[Phase 2] feat(fe): 지도 매물 API 연동 및 마커 표시 - #12

Merged
HOKAGO-MEMORIES merged 5 commits into
developfrom
phase/2-property-map-fe
Jun 18, 2026
Merged

[Phase 2] feat(fe): 지도 매물 API 연동 및 마커 표시#12
HOKAGO-MEMORIES merged 5 commits into
developfrom
phase/2-property-map-fe

Conversation

@HOKAGO-MEMORIES

@HOKAGO-MEMORIES HOKAGO-MEMORIES commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

변경 내용

  • Spring Boot Property API 호출용 Axios 클라이언트와 매물 API helper 추가
  • Naver Maps SDK 로더 추가 및 VITE_NAVER_MAP_CLIENT_ID 기반 로딩
  • 지도 bounds 기반 GET /api/v1/properties 호출, 필터 연동, 마커 표시 구현
  • 마커/목록 선택 시 GET /api/v1/properties/{propertyId} 상세 조회 구현
  • Phase 2 작업 문서 추가 및 frontend pnpm workspace 설정 보정

연결 이슈

closes #11

테스트

  • npx pnpm@9 install --frozen-lockfile
  • npx pnpm@9 build

환경 변수

  • VITE_NAVER_MAP_CLIENT_ID: 네이버 지도 SDK Client ID
  • VITE_API_BASE_URL: Spring Boot API base URL, 로컬 기본값 http://localhost:8080

Summary by CodeRabbit

  • New Features
    • Added an API-driven Naver map experience with interactive markers, bounds-based filtering, and a slide-in property details drawer.
  • Bug Fixes
    • Improved loading/error handling between property listings and property details.
    • Enabled verified local-origin CORS preflight support for property endpoints.
  • Documentation
    • Expanded environment templates with VITE_API_BASE_URL and Naver Maps client guidance.
    • Updated the Phase 2 property map frontend integration guide.
  • Style
    • Added Tailwind-based styling for filter fields and property detail stats.
  • Tests
    • Added an integration test covering CORS preflight behavior.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 036d3193-9790-4577-a701-d6687f00d0cb

📥 Commits

Reviewing files that changed from the base of the PR and between af0c726 and 7946907.

📒 Files selected for processing (5)
  • backend/.env.example
  • frontend/src/store/mapStore.js
  • frontend/src/utils/naverMaps.js
  • frontend/src/views/MapExplorer.vue
  • phases/property-map-fe/phase2-property-map-fe.md
✅ Files skipped from review due to trivial changes (1)
  • phases/property-map-fe/phase2-property-map-fe.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • backend/.env.example
  • frontend/src/utils/naverMaps.js
  • frontend/src/views/MapExplorer.vue
  • frontend/src/store/mapStore.js

📝 Walkthrough

Walkthrough

Phase 2 of the property map frontend replaces the static mock store and SVG map with a live Naver Maps integration. New files add an Axios HTTP client, property API helpers, and a memoized Naver Maps SDK loader. The Pinia store is rewritten with API-driven state and request-sequencing to guard against stale responses. MapExplorer.vue is refactored to render live markers, filters, and a detail panel synchronized with the map viewport. Supporting environment variables are documented for frontend and backend configurations, and backend CORS is configured to enable cross-origin frontend requests.

Changes

Phase 2: Property Map Frontend

Layer / File(s) Summary
Axios client, property API helpers, workspace, and frontend environment config
frontend/.env.example, frontend/pnpm-workspace.yaml, frontend/src/api/http.js, frontend/src/api/properties.js
Adds the shared Axios instance using VITE_API_BASE_URL (defaulting to http://localhost:8080) with a 10s timeout and JSON headers, fetchProperties (with cleanParams to remove null/undefined/empty values) and fetchPropertyDetail helpers targeting /api/v1/properties, the frontend env examples for Naver Maps client ID and API base URL, and the pnpm workspace configuration.
Naver Maps SDK memoized loader
frontend/src/utils/naverMaps.js
Introduces a browser-only loadNaverMaps function that memoizes a single promise, validates VITE_NAVER_MAP_CLIENT_ID, reuses or injects the SDK <script id="naver-map-sdk"> tag, and resolves/rejects based on window.naver.maps presence after script load.
Pinia store refactor
frontend/src/store/mapStore.js
Replaces the static mock store with DEFAULT_BOUNDS/DEFAULT_CENTER constants, API-oriented state (bounds, center, zoom, searchKeyword, typed filters, loading/error states, requestSeq for request sequencing), rewritten getters (filteredProperties with keyword filtering, regionStatus reflecting load/error/totalCount, hasActiveFilters), and new actions (setBounds, setCenter, setZoom, setFilter, resetFilters, fetchProperties with stale-response guarding via requestSeq, selectProperty with detail fetch and loading state, closeProperty).
MapExplorer view and component styles
frontend/src/views/MapExplorer.vue, frontend/src/assets/main.css
Rewrites the template with a Naver map container, loading/error overlays, filter/search forms, a scrollable property list with formatted price/type/area, and a slide-in detail panel; replaces script setup to initialize the Naver map on mount, handle map "idle" events to fetch properties by viewport bounds, manage marker lifecycle (render/clear/click), pan to selected properties, and provide display formatting helpers. Adds .filter-field and .detail-stat Tailwind component CSS rules.
Phase 2 specification document
phases/property-map-fe/phase2-property-map-fe.md
Adds the implementation plan defining goals, file-level task assignments, acceptance criteria, architecture constraints (REST-only, env-driven config, MVP scope), and environment-variable-driven implementation instructions.

Backend CORS Configuration

Layer / File(s) Summary
Spring WebConfig CORS mapper and environment configuration
backend/src/main/java/com/ssafy/salmanhae/config/WebConfig.java, backend/.env.example
Introduces WebConfig class implementing WebMvcConfigurer that parses the app.cors.allowed-origins property (defaulting to localhost frontend origins) and registers CORS mappings for /api/** with standard HTTP methods, all headers, and a 3600-second max age. Adds backend/.env.example with Spring Boot datasource and CORS configuration examples for local development.
CORS preflight integration test
backend/src/test/java/com/ssafy/salmanhae/controller/property/PropertyHttpIntegrationTest.java
Adds HTTP imports and implements propertyApiAllowsLocalFrontendOrigin integration test that verifies the properties endpoint responds to CORS preflight (OPTIONS) requests with correct Access-Control-Allow-Origin headers.

Environment Configuration

Layer / File(s) Summary
Root environment documentation
.env.example
Updates root .env.example with grouped sections for Naver Maps credentials (server-side use), MOLIT batch service key, and Supabase configuration (JDBC datasource URL, username, password, and service role key with frontend exposure warning).

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant MapExplorer as MapExplorer.vue
  participant naverMaps as loadNaverMaps
  participant mapStore as Pinia mapStore
  participant propertiesAPI as properties.js
  participant SpringBoot as Spring Boot API

  rect rgba(100, 149, 237, 0.5)
    note over MapExplorer,naverMaps: Map initialization on mount
    MapExplorer->>naverMaps: loadNaverMaps()
    naverMaps-->>MapExplorer: window.naver.maps
    MapExplorer->>MapExplorer: new Map(container, { center, zoom })
    MapExplorer->>MapExplorer: map.addListener("idle", onIdle)
  end

  rect rgba(144, 238, 144, 0.5)
    note over MapExplorer,SpringBoot: Property fetch on map idle
    MapExplorer->>mapStore: setBounds(map.getBounds())
    MapExplorer->>mapStore: fetchProperties()
    mapStore->>mapStore: requestSeq++, isLoading=true
    mapStore->>propertiesAPI: fetchProperties(bounds + filters)
    propertiesAPI->>propertiesAPI: cleanParams(merged)
    propertiesAPI->>SpringBoot: GET /api/v1/properties?...
    SpringBoot-->>propertiesAPI: { data: { data: [...] } }
    propertiesAPI-->>mapStore: properties[]
    alt requestSeq matches current
      mapStore->>mapStore: properties=data, totalCount
    else stale response
      mapStore->>mapStore: discard
    end
    mapStore-->>MapExplorer: filteredProperties updated
    MapExplorer->>MapExplorer: clear markers, render new markers
  end

  rect rgba(255, 165, 0, 0.5)
    note over User,SpringBoot: Property selection and detail load
    User->>MapExplorer: click marker or list item
    MapExplorer->>mapStore: selectProperty(id)
    mapStore->>mapStore: isDetailLoading=true
    mapStore->>propertiesAPI: fetchPropertyDetail(id)
    propertiesAPI->>SpringBoot: GET /api/v1/properties/{id}
    SpringBoot-->>propertiesAPI: { data: { data: {...} } }
    propertiesAPI-->>mapStore: property detail
    mapStore->>mapStore: selectedProperty=detail, isDetailLoading=false
    mapStore-->>MapExplorer: selectedProperty updated
    MapExplorer->>MapExplorer: map.panTo(coords), show detail panel
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • [Phase 1] property-api-be #9 — The changes integrate with the Phase 1 Property API Backend that defined the endpoints (GET /api/v1/properties with bounds/filters, GET /api/v1/properties/{propertyId}) and establish CORS configuration (WebConfig.java) to enable frontend-backend communication.

Possibly related PRs

  • ssafy-salman/salmanhae#10 — The frontend property API helpers (frontend/src/api/properties.js and mapStore.fetchProperties/selectProperty) directly call the backend endpoints /api/v1/properties and /api/v1/properties/{propertyId} that were implemented in that PR's PropertyController with the same response envelope.

Poem

🐇 Hopping through the Seoul skyline, markers bloom,
The Naver map awakens, banishing the gloom.
Axios calls the Spring Boot near,
cleanParams wipes the null and drear,
A memoized SDK loads without a fuss—
The property map's alive, thanks to all of us! 🗺️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR title clearly describes the main change: frontend map property API integration and marker display (Phase 2).
Description check ✅ Passed PR description covers all required template sections with implementation details, test results, and environment variable documentation.
Linked Issues check ✅ Passed Code changes fully implement all Phase 2 objectives including API integration, Naver Maps SDK, property filtering, detail lookup, and error handling.
Out of Scope Changes check ✅ Passed All changes are within scope of Phase 2 property map frontend feature; no out-of-scope work detected beyond required objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase/2-property-map-fe

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
phases/property-map-fe/phase2-property-map-fe.md (1)

27-28: ⚡ Quick win

Clarify the initial map bounds and seeded data behavior.

The implementation instruction to "Keep the initial map centered around the seeded Seoul property data" lacks specificity. It should clarify:

  • What map bounds and center coordinates define "seeded Seoul property data"?
  • What happens if the backend returns no seeded properties (fallback bounds)?
  • Should the map pan/zoom to fit the seeded data, or is a fixed initial viewport sufficient?

This will help implementers avoid ambiguity and ensure consistent behavior across deployments.

📝 Suggested clarification
-Use `VITE_API_BASE_URL` for the Spring Boot base URL and `VITE_NAVER_MAP_CLIENT_ID` for the browser map SDK. Keep the initial map centered around the seeded Seoul property data, then fetch by map viewport after the SDK is ready and whenever the map becomes idle after movement or zoom.
+Use `VITE_API_BASE_URL` for the Spring Boot base URL and `VITE_NAVER_MAP_CLIENT_ID` for the browser map SDK. Initialize the map with a default viewport centered on Seoul (e.g., 37.5665, 126.9780 with an appropriate zoom level). After SDK readiness, fetch properties by map bounds and continue fetching whenever the map becomes idle after movement or zoom. If a "seeded" initial property set should be displayed before user interaction, define those bounds explicitly in the store constants or accept them from an environment variable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@phases/property-map-fe/phase2-property-map-fe.md` around lines 27 - 28, The
implementation instruction in the phase2-property-map-fe.md file needs to be
clarified regarding the initial map setup behavior. Update the instruction that
mentions "Keep the initial map centered around the seeded Seoul property data"
to explicitly specify the exact initial map bounds and center coordinates for
Seoul, define the fallback map bounds to use if the backend returns no seeded
properties, and clarify whether the map should dynamically pan and zoom to fit
the seeded data bounds or use a fixed initial viewport. This will eliminate
ambiguity for implementers and ensure consistent behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/store/mapStore.js`:
- Around line 46-47: The issue is that detail requests can complete out of
order, causing older responses to overwrite newer selections or repopulate
selectedProperty after the panel is closed. Guard against stale responses by
using the requestSeq field already initialized in the store state. Increment
requestSeq each time a new detail request is initiated in the selectProperty
action or method, pass this sequence number with the request, and only update
selectedProperty if the response's sequence number matches the current
requestSeq value. This ensures only the most recent request's response updates
the state while stale responses are ignored.

In `@frontend/src/utils/naverMaps.js`:
- Around line 21-27: The code does not check if the existing naver-map-sdk
script tag has already finished loading or failed, causing event listeners to
never fire on already-settled scripts, leaving the loader pending indefinitely.
Additionally, failed loads keep a rejected memoized sdkPromise that prevents
retries in the same session. Check the script's readyState property and whether
window.naver.maps exists when the existing script is found to resolve or reject
immediately instead of waiting for events. For failed loads, reset the memoized
sdkPromise to null before rejecting so subsequent calls can attempt a fresh
load. Apply the same logic to the new script tag creation section around lines
33-45 to ensure consistency.

In `@frontend/src/views/MapExplorer.vue`:
- Around line 125-133: The article element in the v-for loop with the
`@click`="store.selectProperty(property.id)" handler is not keyboard-accessible
because it lacks focus management and keyboard event handlers. Add tabindex="0"
to make the article element focusable, then add `@keydown.enter` and
`@keydown.space` event handlers that call the same
store.selectProperty(property.id) method to enable keyboard users to select
properties using the Enter or Space keys.

In `@phases/property-map-fe/phase2-property-map-fe.md`:
- Around line 6-12: Add the missing `frontend/pnpm-workspace.yaml` file entry to
the Files section in the phase2-property-map-fe.md document. Include this file
in the list alongside the other configuration and API setup files (such as
`frontend/.env.example` and the API helpers) with a brief description indicating
it corrects the frontend pnpm workspace settings, as referenced in the PR
objectives.

---

Nitpick comments:
In `@phases/property-map-fe/phase2-property-map-fe.md`:
- Around line 27-28: The implementation instruction in the
phase2-property-map-fe.md file needs to be clarified regarding the initial map
setup behavior. Update the instruction that mentions "Keep the initial map
centered around the seeded Seoul property data" to explicitly specify the exact
initial map bounds and center coordinates for Seoul, define the fallback map
bounds to use if the backend returns no seeded properties, and clarify whether
the map should dynamically pan and zoom to fit the seeded data bounds or use a
fixed initial viewport. This will eliminate ambiguity for implementers and
ensure consistent behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8eb570a9-6088-4a0a-9a46-78c8c1caba9f

📥 Commits

Reviewing files that changed from the base of the PR and between 582a7e2 and ad5a86b.

📒 Files selected for processing (9)
  • frontend/.env.example
  • frontend/pnpm-workspace.yaml
  • frontend/src/api/http.js
  • frontend/src/api/properties.js
  • frontend/src/assets/main.css
  • frontend/src/store/mapStore.js
  • frontend/src/utils/naverMaps.js
  • frontend/src/views/MapExplorer.vue
  • phases/property-map-fe/phase2-property-map-fe.md

Comment thread frontend/src/store/mapStore.js Outdated
Comment thread frontend/src/utils/naverMaps.js
Comment thread frontend/src/views/MapExplorer.vue
Comment thread phases/property-map-fe/phase2-property-map-fe.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.env.example (1)

12-14: ⚡ Quick win

Reorder Supabase variables to follow alphabetical key ordering.

The dotenv-linter rule UnorderedKey flags that SUPABASE_DB_PASSWORD should appear before SUPABASE_DB_URL to maintain consistent alphabetical ordering within grouped configuration sections.

🔧 Proposed reordering
 # Spring Boot datasource. Use the Supabase PostgreSQL JDBC connection string.
 # Example:
 # SUPABASE_DB_URL=jdbc:postgresql://aws-0-ap-northeast-2.pooler.supabase.com:6543/postgres?sslmode=require
-SUPABASE_DB_URL=
-SUPABASE_DB_USERNAME=
 SUPABASE_DB_PASSWORD=
+SUPABASE_DB_URL=
+SUPABASE_DB_USERNAME=
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example around lines 12 - 14, Reorder the three Supabase database
configuration variables in the .env.example file to follow alphabetical
ordering. The variables SUPABASE_DB_URL, SUPABASE_DB_USERNAME, and
SUPABASE_DB_PASSWORD should be rearranged alphabetically by their full key names
so that SUPABASE_DB_PASSWORD appears first, followed by SUPABASE_DB_URL, and
then SUPABASE_DB_USERNAME to comply with the UnorderedKey linting rule.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.env.example:
- Around line 12-14: Reorder the three Supabase database configuration variables
in the .env.example file to follow alphabetical ordering. The variables
SUPABASE_DB_URL, SUPABASE_DB_USERNAME, and SUPABASE_DB_PASSWORD should be
rearranged alphabetically by their full key names so that SUPABASE_DB_PASSWORD
appears first, followed by SUPABASE_DB_URL, and then SUPABASE_DB_USERNAME to
comply with the UnorderedKey linting rule.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4c456b4-eef2-4682-92ae-e5586f33a02e

📥 Commits

Reviewing files that changed from the base of the PR and between ad5a86b and a4612b5.

📒 Files selected for processing (2)
  • .env.example
  • frontend/.env.example
✅ Files skipped from review due to trivial changes (1)
  • frontend/.env.example

@HOKAGO-MEMORIES HOKAGO-MEMORIES changed the title [Phase 2] feat(fe): 지도 매물 API 연동 및 마커 표시 [ai] [Phase 2] feat(fe): 지도 매물 API 연동 및 마커 표시 Jun 18, 2026
@HOKAGO-MEMORIES
HOKAGO-MEMORIES merged commit 769c1da into develop Jun 18, 2026
1 check passed
@HOKAGO-MEMORIES
HOKAGO-MEMORIES deleted the phase/2-property-map-fe branch June 25, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 2] property-map-fe

1 participant