원클릭으로
migrate-map
Migrate Leaflet maps from legacy MVC to Angular using neptune-map and layer components.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Migrate Leaflet maps from legacy MVC to Angular using neptune-map and layer components.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | migrate-map |
| description | Migrate Leaflet maps from legacy MVC to Angular using neptune-map and layer components. |
| allowed-tools | ["Read","Glob","Grep","Edit","Write","Bash(dotnet build:*)","Bash(npm run gen-model:*)"] |
| argument-hint | <EntityName> |
When the user invokes /migrate-map <EntityName>:
This skill guides the migration of Leaflet maps from legacy MVC views to Angular using the neptune-map component and associated layer components.
First, examine the legacy MVC implementation:
Neptune.WebMvc/Views/{Entity}/
<div id="*Map*"> or similar map containersleaflet or map-related classesNeptune.WebMvc/Scripts/ for map initialization
L.map(), L.geoJSON(), L.tileLayer() callsNeptune.WebMvc/Controllers/{Entity}Controller.cs
For entity boundaries or spatial data, create endpoints returning FeatureCollection:
// In EntityController.cs
[HttpGet("{entityID}/boundary")]
[UserViewFeature]
public ActionResult<FeatureCollection> GetBoundary([FromRoute] int entityID)
{
var features = Entities.GetBoundaryAsFeatureCollection(DbContext, entityID);
return Ok(features);
}
// In Entities.cs
public static FeatureCollection GetBoundaryAsFeatureCollection(
NeptuneDbContext dbContext, int entityID)
{
var entity = dbContext.Entities
.AsNoTracking()
.Where(x => x.EntityID == entityID && x.EntityGeometry != null)
.Select(x => new { x.EntityID, x.EntityGeometry })
.SingleOrDefault();
if (entity?.EntityGeometry == null)
return new FeatureCollection();
var feature = new Feature(entity.EntityGeometry, new AttributesTable
{
{ "EntityID", entity.EntityID }
});
return new FeatureCollection(new[] { feature });
}
Add boolean flags to the detail DTO to indicate if map data exists:
// In EntityDto.cs
public bool HasBoundary { get; set; }
public BoundingBoxDto? BoundingBox { get; set; }
| Component | Selector | Purpose |
|---|---|---|
NeptuneMapComponent | neptune-map | Base map container |
DelineationsLayerComponent | delineations-layer | BMP delineation polygons |
JurisdictionsLayerComponent | jurisdictions-layer | Stormwater jurisdiction boundaries |
LandUseBlockLayerComponent | land-use-block-layer | Land use block polygons |
InventoriedBmpsLayerComponent | inventoried-bmps-layer | Inventoried BMP locations |
OvtaAreaLayerComponent | ovta-area-layer | Single OVTA area |
OvtaAreasLayerComponent | ovta-areas-layer | Multiple OVTA areas |
ParcelLayerComponent | parcel-layer | Parcels |
PermitTypeLayerComponent | permit-type-layer | Permit type boundaries |
TrashGeneratingUnitLayerComponent | trash-generating-unit-layer | Trash generating units |
StormwaterNetworkLayerComponent | stormwater-network-layer | Stormwater network |
WqmpsLayerComponent | wqmps-layer | Water quality management plans |
RegionalSubbasinsLayerComponent | regional-subbasins-layer | Regional subbasins |
LoadGeneratingUnitsLayerComponent | load-generating-units-layer | Load generating units |
GenericWmsWfsLayerComponent | generic-wms-wfs-layer | Generic WMS/WFS with OverlayMode |
import { OverlayMode } from "src/app/shared/components/leaflet/layers/generic-wms-wfs-layer/overlay-mode.enum";
import { Component } from "@angular/core";
import { Observable } from "rxjs";
import { Map } from "leaflet";
import { NeptuneMapComponent } from "src/app/shared/components/leaflet/neptune-map/neptune-map.component";
import { DelineationsLayerComponent } from "src/app/shared/components/leaflet/layers/delineations-layer/delineations-layer.component";
import { JurisdictionsLayerComponent } from "src/app/shared/components/leaflet/layers/jurisdictions-layer/jurisdictions-layer.component";
@Component({
// ...
imports: [
NeptuneMapComponent,
DelineationsLayerComponent,
JurisdictionsLayerComponent,
// other layer components as needed
],
})
export class EntityDetailComponent {
public map: Map;
public layerControl: L.Control.Layers;
public mapIsReady: boolean = false;
handleMapReady(event: MapInitEvent): void {
this.map = event.map;
this.layerControl = event.layerControl;
this.mapIsReady = true;
}
}
@if (entity.HasBoundary) {
<div class="card">
<div class="card-header"><span class="card-title">Map</span></div>
<div class="card-body">
<neptune-map
[mapHeight]="'400px'"
[boundingBox]="entity.BoundingBox"
(onMapLoad)="handleMapReady($event)">
<!-- Delineation layer -->
@if (mapIsReady) {
<delineations-layer
[map]="map"
[layerControl]="layerControl"
[treatmentBMPID]="entity.TreatmentBMPID">
</delineations-layer>
}
<!-- Jurisdiction reference layer -->
@if (mapIsReady) {
<jurisdictions-layer
[map]="map"
[layerControl]="layerControl">
</jurisdictions-layer>
}
</neptune-map>
</div>
</div>
}
Neptune uses vGeoServer* views for WMS/WFS layers served by GeoServer. Common views:
vGeoServerTreatmentBMP — BMP locationsvGeoServerDelineation — BMP delineation polygonsvGeoServerTrashGeneratingUnit — Trash generating unitsvGeoServerLandUseBlock — Land use blocksvGeoServerOnlandVisualTrashAssessmentArea — OVTA areasvGeoServerRegionalSubbasin — Regional subbasinsvGeoServerWaterQualityManagementPlan — WQMPsvGeoServerStormwaterNetwork — Stormwater network| Input | Type | Default | Description |
|---|---|---|---|
mapHeight | string | '500px' | CSS height of map container |
selectedTileLayer | string | 'Terrain' | Default base layer ('Terrain', 'Street', 'Satellite') |
boundingBox | BoundingBoxDto | Orange County, CA | Initial bounds |
showLegend | boolean | false | Show legend control |
disableMapInteraction | boolean | false | Lock map (no pan/zoom) |
collapseLayerControlOnLoad | boolean | false | Start with layers control collapsed |
| Output | Type | Description |
|---|---|---|
onMapLoad | MapInitEvent | Fired when map is ready; provides map and layerControl |
<div class="grid-12">
<div class="g-col-6">
<!-- Map card -->
</div>
<div class="g-col-6">
<!-- Details card -->
</div>
</div>
<div class="grid-12">
<div class="g-col-12">
<!-- Map card -->
</div>
<div class="g-col-12">
<!-- Grid card -->
</div>
</div>
@if (entity.HasBoundary) {
<div class="card">
<div class="card-header"><span class="card-title">Location</span></div>
<div class="card-body">
<neptune-map ...>
<!-- layers -->
</neptune-map>
</div>
</div>
} @else {
<div class="card">
<div class="card-header"><span class="card-title">Location</span></div>
<div class="card-body">
<p class="text-muted">No location data available for this entity.</p>
</div>
</div>
}
HasBoundary / spatial flags to detail DTOBoundingBox to detail DTO (if applicable)neptune-map component to component importshandleMapReady methodnpm run gen-model after API changeshandleMapReady is called and sets mapIsReady = true@if (mapIsReady) guardmap and layerControl are passed to layer components| async)mapHeight inputboundingBox input to map componentCreate or flesh out a Jira story with structured sections for POs, Devs, and Claude. Accepts an optional Jira key to update an existing card.
Export Water Quality Management Plans for one jurisdiction from the local Neptune database to an Esri File Geodatabase in native projection. Use when a client requests WQMP spatial data for a specific city/jurisdiction.
Extract rework items from a Jira card's Acceptance Criteria and produce a fix plan. Auto-detects issue key from branch or accepts one as argument.
Fetch a Jira card by key (e.g. NPT-100) and produce a detailed implementation plan. Use this when starting work on a new story.
Build the SQL Server DACPAC and scaffold EF Core entities. Run this after finishing all SQL schema edits in Neptune.Database/.
Add a scrollspy Table of Contents sidebar to a page component with signal-based scroll tracking.