원클릭으로
migrate-page
Migrate a page from legacy MVC to Angular SPA + API. Orchestrates grid, map, modal, and workflow sub-skills as needed.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Migrate a page from legacy MVC to Angular SPA + API. Orchestrates grid, map, modal, and workflow sub-skills as needed.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create 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.
| name | migrate-page |
| description | Migrate a page from legacy MVC to Angular SPA + API. Orchestrates grid, map, modal, and workflow sub-skills as needed. |
| allowed-tools | ["Read","Glob","Grep","Edit","Write","Bash(dotnet build:*)","Bash(npm run gen-model:*)","Bash(dotnet test:*)","Bash(npm test:*)","Skill(migrate-grid)","Skill(migrate-map)","Skill(crud-modal)","Skill(migrate-workflow)"] |
| argument-hint | <EntityName> |
When the user invokes /migrate-page <EntityName>:
First, thoroughly examine the existing MVC implementation:
Neptune.WebMvc/Controllers/{Entity}Controller.csNeptune.WebMvc/Views/{Entity}/Neptune.WebMvc/Views/Shared/ that may be usedNeptune.WebMvc/Scripts/ related to the entityIdentify and document:
Based on your analysis, note which of these components the page contains:
| Component Found | Specialized Skill | When to Use |
|---|---|---|
| Data tables/grids | /migrate-grid | Index pages, detail pages with related entity lists |
| Maps with boundaries/locations | /migrate-map | Pages showing spatial data |
| Create/Edit forms | /crud-modal | Pages with New/Edit functionality |
| Multi-step wizards | /migrate-workflow | Pages with sequential data entry steps |
Document which skills you'll need for this migration.
Before writing code, plan the artifacts needed:
DTOs to create:
{Entity}GridDto — Fields needed for list/index view{Entity}Dto — Fields for detail view including related data{Entity}UpsertDto — Fields for create/edit forms{Entity}SimpleDto — If used in dropdowns elsewhereIdentify:
Create the following files in order:
Location: Neptune.Models/DataTransferObjects/
{Entity}GridDto.cs{Entity}Dto.cs{Entity}UpsertDto.csExtension methods are generated by scaffold in Neptune.EFModels/Entities/Generated/ExtensionMethods/{Entity}ExtensionMethods.cs. If you need custom extension methods beyond what scaffold generates, add them in Neptune.EFModels/Entities/ as a partial class or separate file:
AsDto() — Full detail mappingAsGridDto() — Grid row mappingAsSimpleDto() — Simple/dropdown mappingLocation: Neptune.EFModels/Entities/{PluralEntity}.cs
ListAsDtoAsync() or ListAsGridDto()GetByIDAsDto()GetByID()GetByIDWithChangeTracking()CreateNew()Update()DeleteAsync()Location: Neptune.API/Controllers/{Entity}Controller.cs
SitkaController<{Entity}Controller>(dbContext, logger, neptuneConfiguration) with primary constructor (3 params)Apply authorization attributes to controller endpoints based on legacy feature attributes.
Step 1: Identify legacy features
Search for Feature] in the legacy controller:
grep -E "Feature\]" Neptune.WebMvc/Controllers/{Entity}Controller.cs
Step 2: Map to Neptune authorization attributes
| Legacy Feature Pattern | New Attribute | Roles |
|---|---|---|
| Public/anonymous endpoint | [AllowAnonymous] | No auth required |
| Admin-only operations | [AdminFeature] | Admin, SitkaAdmin |
| SitkaAdmin-only operations | [SitkaAdminFeature] | SitkaAdmin |
| Jurisdiction edit operations | [JurisdictionEditFeature] | Admin, SitkaAdmin, JurisdictionManager, JurisdictionEditor (+ jurisdiction match) |
| Jurisdiction manage operations | [JurisdictionManageFeature] | Admin, SitkaAdmin, JurisdictionManager (+ jurisdiction match) |
| Any authenticated user | [UserViewFeature] | All logged-in users |
| Unassigned users | [LoggedInUnclassifiedFeature] | Unassigned users |
Step 3: Apply attributes
using Neptune.API.Services.Authorization; to the controllerusing Microsoft.AspNetCore.Authorization; if using [AllowAnonymous][AllowAnonymous] or [UserViewFeature]Example:
[HttpGet]
[UserViewFeature]
public ActionResult<List<EntityGridDto>> List() { ... }
[HttpPost]
[AdminFeature]
public ActionResult<EntityDto> Create([FromBody] EntityUpsertDto dto) { ... }
[HttpPut("{entityID}")]
[JurisdictionEditFeature]
public ActionResult<EntityDto> Update([FromRoute] int entityID, [FromBody] EntityUpsertDto dto) { ... }
After API code is complete:
# Build the API to generate swagger.json
dotnet build Neptune.API/Neptune.API.csproj -c Debug
# Generate TypeScript models
cd Neptune.Web
npm run gen-model
Verify the generated files in Neptune.Web/src/app/shared/generated/.
Location: Neptune.Web/src/app/pages/{entity}/
Create the folder structure based on identified components:
{entity}-list/ — If page has a main grid (use /migrate-grid){entity}-detail/ — If page has a detail view{entity}-modal/ — If page needs create/edit forms (use /crud-modal)All components must be standalone with explicit imports. Use @Input() with BehaviorSubject pattern for route params.
If the page contains data grids, follow the /migrate-grid skill for:
neptune-grid)If the page contains maps, follow the /migrate-map skill for:
neptune-map)If the page needs create/edit/delete functionality, follow the /crud-modal skill for:
Add route to Neptune.Web/src/app/app.routes.ts:
{
path: 'entities',
children: [
{
path: '',
loadComponent: () => import('./pages/entity/entity-list/entity-list.component').then(m => m.EntityListComponent)
},
{
path: ':entityID',
loadComponent: () => import('./pages/entity/entity-detail/entity-detail.component').then(m => m.EntityDetailComponent)
}
]
}
Apply guards as needed:
| Guard | Purpose |
|---|---|
UnsavedChangesGuard | Prevents navigation away from unsaved form changes |
Auth checks are typically done within components using AuthenticationService.
Location: Neptune.Tests/
new EntityController(dbContext, logger, Options.Create(new NeptuneConfiguration()))Location: Same folder as component with .spec.ts extension
jasmine.createSpyObjAfter migration is complete and tested:
[Obsolete("Migrated to Angular SPA")] attribute to legacy controller# Run API tests
dotnet test Neptune.Tests/Neptune.Tests.csproj
# Run Angular tests
cd Neptune.Web
npm test
# Manual verification
npm start
# Navigate to new pages and verify functionality
@Input() + BehaviorSubject pattern.AsNoTracking() with .Include() then .Select(x => x.AsDto())[AllowAnonymous] or [UserViewFeature]