# STEP 8 — 컨트롤러 추가 (`ExperionFastController`) ## 사전 확인 (작업 전 반드시 수행) 1. `src/Web/Controllers/ExperionControllers.cs` 파일을 열어 전체 내용을 읽는다. 2. 아래 항목을 확인하고 기록한다: - [x] STEP 7이 완료되어 `ExperionFastService`가 빌드되는가? - [x] `ExperionFastController` 클래스가 이미 존재하는가? → 있으면 내용 비교 후 누락 엔드포인트만 추가 - [x] `PinRequest` record가 이미 존재하는가? - [x] 파일 상단에 `using Microsoft.AspNetCore.Mvc;` 가 있는가? --- ## 작업 내용 **파일**: `src/Web/Controllers/ExperionControllers.cs` **위치**: 파일 하단 (기존 컨트롤러 마지막 클래스 아래) ```csharp // ── FastTable / FastRecord ──────────────────────────────────────────────────── [ApiController] [Route("api/fast")] public class ExperionFastController : ControllerBase { private readonly IExperionFastService _fastSvc; public ExperionFastController(IExperionFastService fastSvc) => _fastSvc = fastSvc; /// 새 fastSession 시작 [HttpPost("start")] public async Task Start([FromBody] FastSessionStartRequest request) { try { var session = await _fastSvc.StartSessionAsync(request); return Ok(new { id = session.Id, name = session.Name, status = session.Status, startedAt = session.StartedAt }); } catch (ArgumentException ex) { return BadRequest(new { error = ex.Message }); } catch (InvalidOperationException ex) { return Conflict(new { error = ex.Message }); } } /// 세션 중지 [HttpPost("{id:int}/stop")] public async Task Stop(int id) { try { await _fastSvc.StopSessionAsync(id); return Ok(new { success = true, message = "세션이 중지되었습니다." }); } catch (InvalidOperationException ex) { return NotFound(new { error = ex.Message }); } } /// 세션 목록 조회 [HttpGet("sessions")] public async Task GetSessions() { var sessions = await _fastSvc.GetSessionsAsync(); return Ok(new { total = sessions.Count(), items = sessions.Select(s => new { id = s.Id, name = s.Name, status = s.Status, samplingMs = s.SamplingMs, durationSec = s.DurationSec, tagCount = s.TagList.Length, rowCount = s.RowCount, startedAt = s.StartedAt, endedAt = s.EndedAt, retentionDays = s.RetentionDays, pinned = s.Pinned }) }); } /// 세션 상세 정보 [HttpGet("{id:int}")] public async Task GetSession(int id) { var session = await _fastSvc.GetSessionAsync(id); if (session == null) return NotFound(); return Ok(new { id = session.Id, name = session.Name, status = session.Status, samplingMs = session.SamplingMs, durationSec = session.DurationSec, tagList = session.TagList, rowCount = session.RowCount, startedAt = session.StartedAt, endedAt = session.EndedAt, retentionDays = session.RetentionDays, pinned = session.Pinned }); } /// 레코드 조회 (Long 포맷) [HttpGet("{id:int}/records")] public async Task GetRecords(int id, [FromQuery] DateTime? from, [FromQuery] DateTime? to, [FromQuery] string format = "long") { var result = await _fastSvc.GetRecordsAsync(id, from, to, format); return Ok(new { sessionId = result.SessionId, from = result.From, to = result.To, tagNames = result.TagNames, total = result.TotalCount, items = result.Items.Select(r => new { sessionId = r.SessionId, recordedAt = r.RecordedAt, tagName = r.TagName, value = r.Value }) }); } /// CSV Export (스트리밍) [HttpGet("{id:int}/csv")] public async Task ExportCsv(int id, [FromQuery] DateTime? from, [FromQuery] DateTime? to) { var ms = new MemoryStream(); await _fastSvc.ExportCsvAsync(id, ms, from, to); ms.Position = 0; return File(ms, "text/csv", $"fast-{id}-{DateTime.Now:yyyyMMddHHmm}.csv"); } /// 세션 삭제 [HttpDelete("{id:int}")] public async Task Delete(int id) { try { await _fastSvc.DeleteSessionAsync(id); return Ok(new { success = true, message = "세션이 삭제되었습니다." }); } catch (InvalidOperationException ex) { return NotFound(new { error = ex.Message }); } } /// 세션 고정/해제 [HttpPost("{id:int}/pin")] public async Task Pin(int id, [FromBody] PinRequest request) { try { await _fastSvc.PinSessionAsync(id, request.Pinned); return Ok(new { success = true, pinned = request.Pinned }); } catch (InvalidOperationException ex) { return NotFound(new { error = ex.Message }); } } } public record PinRequest(bool Pinned); ``` --- ## 사후 확인 (작업 후 반드시 수행) 1. `ExperionControllers.cs` 파일을 다시 열어 추가된 컨트롤러를 읽는다. 2. 아래 항목을 하나씩 확인한다: - [x] `[Route("api/fast")]` 라우트가 맞는가? - [x] `POST /start` 엔드포인트 존재 - [x] `POST /{id}/stop` 엔드포인트 존재 - [x] `GET /sessions` 엔드포인트 존재 - [x] `GET /{id}` 엔드포인트 존재 - [x] `GET /{id}/records` 엔드포인트 존재 - [x] `GET /{id}/csv` 엔드포인트 존재 - [x] `DELETE /{id}` 엔드포인트 존재 - [x] `POST /{id}/pin` 엔드포인트 존재 (총 8개 엔드포인트) - [x] `PinRequest` record 존재 (중복 선언 아닌지 확인) 3. `dotnet build src/Web` 실행 → 에러/경고 0개 확인 4. 문제가 있으면 수정 후 다시 빌드 확인 --- ## 완료 조건 - `dotnet build src/Web` 결과: 에러 0, 경고 0 - `ExperionFastController` 8개 엔드포인트 모두 존재