diff --git a/.github/workflows/deploy-docsify.yml b/.github/workflows/deploy-docsify.yml
new file mode 100644
index 00000000..4ab10e1a
--- /dev/null
+++ b/.github/workflows/deploy-docsify.yml
@@ -0,0 +1,44 @@
+name: Deploy Docsify to GitHub Pages
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+
+ - name: Upload Docs artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: build
+ environment:
+ name: github-pages
+ url: ${{ steps.deploy.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deploy
+ uses: actions/deploy-pages@v4
+
+ - name: Show deployed link
+ run: echo "Docs available at ${{ steps.deploy.outputs.page_url }}"
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 06a6bc55..f3e4765f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -7,7 +7,7 @@
-
+
@@ -48,5 +48,6 @@
+
diff --git a/SnakeAid.Api/Controllers/FirstAidGuidelineController.cs b/SnakeAid.Api/Controllers/FirstAidGuidelineController.cs
new file mode 100644
index 00000000..e7cdb96d
--- /dev/null
+++ b/SnakeAid.Api/Controllers/FirstAidGuidelineController.cs
@@ -0,0 +1,127 @@
+using MapsterMapper;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using SnakeAid.Core.Meta;
+using SnakeAid.Core.Requests.FirstAidGuideline;
+using SnakeAid.Core.Responses.FirstAidGuideline;
+using SnakeAid.Core.Validators;
+using SnakeAid.Service.Interfaces;
+using Swashbuckle.AspNetCore.Annotations;
+
+namespace SnakeAid.Api.Controllers
+{
+ [Route("api/first-aid-guidelines")]
+ [ApiController]
+ public class FirstAidGuidelineController : BaseController
+ {
+ private readonly IFirstAidGuidelineService _guidelineService;
+
+ public FirstAidGuidelineController(
+ ILogger logger,
+ IHttpContextAccessor httpContextAccessor,
+ IMapper mapper,
+ IFirstAidGuidelineService guidelineService)
+ : base(logger, httpContextAccessor, mapper)
+ {
+ _guidelineService = guidelineService;
+ }
+
+ ///
+ /// Create a new first aid guideline
+ ///
+ [HttpPost]
+ [ValidateModel]
+ [SwaggerOperation(Summary = "Create First Aid Guideline", Description = "Create a new first aid guideline (Admin only)")]
+ [SwaggerResponse(200, "Created successfully", typeof(ApiResponse))]
+ [SwaggerResponse(400, "Validation error")]
+ [SwaggerResponse(401, "Unauthorized")]
+ [SwaggerResponse(403, "Forbidden")]
+ public async Task CreateFirstAidGuideline([FromBody] CreateFirstAidGuidelineRequest request)
+ {
+ var result = await _guidelineService.CreateFirstAidGuidelineAsync(request);
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Get first aid guideline by ID
+ ///
+ [HttpGet("{id}")]
+ [SwaggerOperation(Summary = "Get First Aid Guideline by ID", Description = "Get detailed information of a first aid guideline")]
+ [SwaggerResponse(200, "Success", typeof(ApiResponse))]
+ [SwaggerResponse(404, "Guideline not found")]
+ public async Task GetFirstAidGuidelineById(int id)
+ {
+ var result = await _guidelineService.GetFirstAidGuidelineByIdAsync(id);
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Get list of first aid guidelines with pagination and filters
+ ///
+ [HttpGet("filter")]
+ [SwaggerOperation(Summary = "Filter First Aid Guidelines", Description = "Get paginated list of first aid guidelines with optional filters")]
+ [SwaggerResponse(200, "Success", typeof(ApiResponse>))]
+ public async Task FilterFirstAidGuidelines([FromQuery] GetFirstAidGuidelineRequest request)
+ {
+ var result = await _guidelineService.FilterFirstAidGuidelinesAsync(request);
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Get all first aid guidelines without pagination
+ ///
+ [HttpGet]
+ [SwaggerOperation(Summary = "Get All First Aid Guidelines", Description = "Get all first aid guidelines without pagination")]
+ [SwaggerResponse(200, "Success", typeof(ApiResponse>))]
+ public async Task GetAllFirstAidGuideline()
+ {
+ var result = await _guidelineService.GetAllFirstAidGuidelineAsync();
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Get first aid guidelines by snake species ID
+ ///
+ [HttpGet("by-snake-species/{snakeSpeciesId}")]
+ [SwaggerOperation(Summary = "Get First Aid Guidelines by Snake Species", Description = "Get first aid guidelines based on the venom types of a specific snake species")]
+ [SwaggerResponse(200, "Success", typeof(ApiResponse>))]
+ [SwaggerResponse(404, "Snake species not found")]
+ public async Task GetFirstAidGuidelinesBySnakeSpecies(int snakeSpeciesId)
+ {
+ var result = await _guidelineService.GetFirstAidGuidelinesBySnakeSpeciesIdAsync(snakeSpeciesId);
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Update an existing first aid guideline
+ ///
+ [HttpPut("{id}")]
+ [ValidateModel]
+ [SwaggerOperation(Summary = "Update First Aid Guideline", Description = "Update an existing first aid guideline (Admin only)")]
+ [SwaggerResponse(200, "Updated successfully", typeof(ApiResponse))]
+ [SwaggerResponse(400, "Validation error")]
+ [SwaggerResponse(401, "Unauthorized")]
+ [SwaggerResponse(403, "Forbidden")]
+ [SwaggerResponse(404, "Guideline not found")]
+ public async Task UpdateFirstAidGuideline(int id, [FromBody] UpdateFirstAidGuidelineRequest request)
+ {
+ var result = await _guidelineService.UpdateFirstAidGuidelineAsync(id, request);
+ return StatusCode(result.StatusCode, result);
+ }
+
+ ///
+ /// Delete a first aid guideline
+ ///
+ [HttpDelete("{id}")]
+ [SwaggerOperation(Summary = "Delete First Aid Guideline", Description = "Delete a first aid guideline (Admin only)")]
+ [SwaggerResponse(200, "Deleted successfully", typeof(ApiResponse))]
+ [SwaggerResponse(401, "Unauthorized")]
+ [SwaggerResponse(403, "Forbidden")]
+ [SwaggerResponse(404, "Guideline not found")]
+ public async Task DeleteFirstAidGuideline(int id)
+ {
+ var result = await _guidelineService.DeleteFirstAidGuidelineAsync(id);
+ return StatusCode(result.StatusCode, result);
+ }
+ }
+}
diff --git a/SnakeAid.Api/Controllers/SignalRTestController.cs b/SnakeAid.Api/Controllers/SignalRTestController.cs
new file mode 100644
index 00000000..5cf6f060
--- /dev/null
+++ b/SnakeAid.Api/Controllers/SignalRTestController.cs
@@ -0,0 +1,149 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.SignalR;
+using SnakeAid.Api.Hubs;
+using SnakeAid.Core.Meta;
+
+namespace SnakeAid.Api.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class SignalRTestController : ControllerBase
+{
+ private readonly IHubContext _hubContext;
+
+ public SignalRTestController(IHubContext hubContext)
+ {
+ _hubContext = hubContext;
+ }
+
+ [HttpGet("test-connection")]
+ public async Task TestConnection()
+ {
+ try
+ {
+ return Ok(new ApiResponse