feat(backend): add communication, tester, admin and middleman modules
Implement step 17 modules: threads/messages, notifications with automation (submission.created, idea.created, grant_call.opened), innovation test feedback, admin panel (submissions, verify, metrics, grant call status), Middleman adaptation and partnerships. Split multi-type files into one type per file and replace object-valued dictionaries with string-valued maps in data contracts (migrations 0006/0007).
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public interface IAdminService
|
||||
{
|
||||
Task<IReadOnlyList<SubmissionResponse>> ListSubmissionsAsync(
|
||||
string? status,
|
||||
string? challengeId,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<KnowledgeItemResponse?> VerifyKnowledgeItemAsync(
|
||||
string knowledgeItemId,
|
||||
VerifyKnowledgeItemRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<AdminMetricsResponse> GetMetricsAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public enum CreateApplicationOutcome
|
||||
{
|
||||
Created,
|
||||
CallNotFound,
|
||||
CallNotOpen,
|
||||
IdeaNotFound,
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public sealed record CreateApplicationResult(
|
||||
CreateApplicationOutcome Outcome,
|
||||
ApplicationResponse? Application);
|
||||
@@ -0,0 +1,18 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface IApplicationService
|
||||
{
|
||||
Task<CreateApplicationResult> CreateAsync(
|
||||
string userId,
|
||||
CreateApplicationRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<ApplicationResponse?> GetAsync(string applicationId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<ApplicationResponse>> ListForAuthorAsync(
|
||||
string authorId,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -6,6 +6,6 @@ public interface IAuditLogService
|
||||
string? actorId,
|
||||
string action,
|
||||
string target,
|
||||
IReadOnlyDictionary<string, object?> context,
|
||||
IReadOnlyDictionary<string, string?> context,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface IGrantCallService
|
||||
{
|
||||
Task<IReadOnlyList<GrantCallResponse>> ListAsync(string? status, CancellationToken cancellationToken);
|
||||
|
||||
Task<GrantCallResponse?> GetAsync(string grantCallId, CancellationToken cancellationToken);
|
||||
|
||||
Task<GrantCallResponse?> UpdateStatusAsync(
|
||||
string grantCallId,
|
||||
string status,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface IIdeaAssistant
|
||||
{
|
||||
Task<IdeaAssistResponse?> AssistAsync(
|
||||
string ideaId,
|
||||
IdeaAssistRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface IIdeaService
|
||||
{
|
||||
Task<IdeaResponse> CreateAsync(string authorId, CreateIdeaRequest request, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaResponse?> GetAsync(string ideaId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<IdeaResponse>> ListForAuthorAsync(string authorId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<string>> ListDistinctAuthorIdsAsync(CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaResponse?> UpdateAsync(string ideaId, UpdateIdeaRequest request, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaCardResponse?> GetCardAsync(string ideaId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaCardResponse?> UpdateCardAsync(string ideaId, IdeaCardRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface INotificationService
|
||||
{
|
||||
Task NotifyStaffAsync(
|
||||
string type,
|
||||
IReadOnlyDictionary<string, string?> payload,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task NotifyUserAsync(
|
||||
string userId,
|
||||
string type,
|
||||
IReadOnlyDictionary<string, string?> payload,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<NotificationResponse>> ListForUserAsync(
|
||||
string userId,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<NotificationResponse?> MarkReadAsync(
|
||||
string notificationId,
|
||||
string userId,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public sealed record SubmissionEvent(
|
||||
string Type,
|
||||
string SubmissionId,
|
||||
string? ActorId,
|
||||
string Status,
|
||||
DateTimeOffset At);
|
||||
|
||||
public interface ISubmissionEventPublisher
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface IThreadService
|
||||
{
|
||||
Task<IReadOnlyList<ThreadResponse>> ListForUserAsync(
|
||||
string userId,
|
||||
bool isStaff,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<ThreadResponse?> GetAsync(
|
||||
string threadId,
|
||||
string userId,
|
||||
bool isStaff,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<ThreadResponse> CreateAsync(
|
||||
string creatorId,
|
||||
CreateThreadRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<MessageResponse?> AddMessageAsync(
|
||||
string threadId,
|
||||
string authorId,
|
||||
bool isStaff,
|
||||
CreateMessageRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -2,9 +2,8 @@ using TarninaHub.Application.Models;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public interface ITokenService
|
||||
{
|
||||
TokenResult CreateToken(UserAccount user);
|
||||
}
|
||||
|
||||
public sealed record TokenResult(string AccessToken, DateTimeOffset ExpiresAt);
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public interface IIdeaService
|
||||
{
|
||||
Task<IdeaResponse> CreateAsync(string authorId, CreateIdeaRequest request, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaResponse?> GetAsync(string ideaId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<IdeaResponse>> ListForAuthorAsync(string authorId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaResponse?> UpdateAsync(string ideaId, UpdateIdeaRequest request, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaCardResponse?> GetCardAsync(string ideaId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IdeaCardResponse?> UpdateCardAsync(string ideaId, IdeaCardRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IIdeaAssistant
|
||||
{
|
||||
Task<IdeaAssistResponse?> AssistAsync(
|
||||
string ideaId,
|
||||
IdeaAssistRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IGrantCallService
|
||||
{
|
||||
Task<IReadOnlyList<GrantCallResponse>> ListAsync(string? status, CancellationToken cancellationToken);
|
||||
|
||||
Task<GrantCallResponse?> GetAsync(string grantCallId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public enum CreateApplicationOutcome
|
||||
{
|
||||
Created,
|
||||
CallNotFound,
|
||||
CallNotOpen,
|
||||
IdeaNotFound,
|
||||
}
|
||||
|
||||
public sealed record CreateApplicationResult(
|
||||
CreateApplicationOutcome Outcome,
|
||||
ApplicationResponse? Application);
|
||||
|
||||
public interface IApplicationService
|
||||
{
|
||||
Task<CreateApplicationResult> CreateAsync(
|
||||
string userId,
|
||||
CreateApplicationRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<ApplicationResponse?> GetAsync(string applicationId, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<ApplicationResponse>> ListForAuthorAsync(
|
||||
string authorId,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public interface IMiddlemanService
|
||||
{
|
||||
Task<MiddlemanResponse?> AdaptAsync(MiddlemanRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public interface IPartnershipService
|
||||
{
|
||||
Task<IReadOnlyList<PartnershipResponse>> ListForUserAsync(
|
||||
string userId,
|
||||
bool isStaff,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<PartnershipResponse> CreateAsync(
|
||||
string initiatorId,
|
||||
CreatePartnershipRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public sealed record SubmissionEvent(
|
||||
string Type,
|
||||
string SubmissionId,
|
||||
string? ActorId,
|
||||
string Status,
|
||||
DateTimeOffset At);
|
||||
@@ -0,0 +1,16 @@
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
public interface ITestFeedbackService
|
||||
{
|
||||
Task<TestFeedbackResponse?> CreateAsync(
|
||||
string innovationId,
|
||||
string authorId,
|
||||
CreateTestFeedbackRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<TestFeedbackResponse>> ListForInnovationAsync(
|
||||
string innovationId,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using TarninaHub.Application.Models;
|
||||
|
||||
namespace TarninaHub.Application.Abstractions;
|
||||
|
||||
|
||||
public sealed record TokenResult(string AccessToken, DateTimeOffset ExpiresAt);
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record AdminMetricsResponse(
|
||||
int Submissions,
|
||||
int Problems,
|
||||
int Ideas,
|
||||
int Innovations,
|
||||
int KnowledgeItems,
|
||||
int Users,
|
||||
int OpenGrantCalls,
|
||||
int Applications);
|
||||
@@ -1,28 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record GrantCallResponse(
|
||||
string Id,
|
||||
string Name,
|
||||
DateTimeOffset OpensAt,
|
||||
DateTimeOffset ClosesAt,
|
||||
string Status,
|
||||
string? ExternalId);
|
||||
|
||||
public sealed record CreateApplicationRequest(
|
||||
[Required] string GrantCallId,
|
||||
[Required] string IdeaId,
|
||||
IReadOnlyDictionary<string, object?>? Content);
|
||||
|
||||
public sealed record UpdateApplicationRequest(
|
||||
IReadOnlyDictionary<string, object?>? Content,
|
||||
string? Status);
|
||||
|
||||
public sealed record ApplicationResponse(
|
||||
string Id,
|
||||
string GrantCallId,
|
||||
string IdeaId,
|
||||
IReadOnlyDictionary<string, object?> Content,
|
||||
string Status,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record ApplicationResponse(
|
||||
string Id,
|
||||
string GrantCallId,
|
||||
string IdeaId,
|
||||
IReadOnlyDictionary<string, string?> Content,
|
||||
string Status,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record RegisterRequest(string Phone, string? Email, string Password);
|
||||
|
||||
public sealed record LoginRequest(string Phone, string Password);
|
||||
|
||||
public sealed record UserResponse(
|
||||
string Id,
|
||||
string Phone,
|
||||
string? Email,
|
||||
string Role,
|
||||
string? OrganizationId);
|
||||
|
||||
public sealed record TokenResponse(
|
||||
string AccessToken,
|
||||
string TokenType,
|
||||
DateTimeOffset ExpiresAt,
|
||||
UserResponse User);
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record GrantConsentRequest(string Scope, DateTimeOffset? ExpiresAt);
|
||||
|
||||
public sealed record ConsentResponse(
|
||||
string Id,
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateApplicationRequest(
|
||||
[Required] string GrantCallId,
|
||||
[Required] string IdeaId,
|
||||
IReadOnlyDictionary<string, string?>? Content);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateIdeaRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
IdeaCardRequest? Card);
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateMessageRequest(
|
||||
[Required, StringLength(4000, MinimumLength = 1)] string Body);
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreatePartnershipRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Subject,
|
||||
IReadOnlyList<string>? Partners);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateSubmissionRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
[Required] string ChallengeId,
|
||||
[Required] string LocationId,
|
||||
IReadOnlyList<string>? Keywords);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateTestFeedbackRequest(
|
||||
[Range(1, 5)] int Rating,
|
||||
string? Comment,
|
||||
string? Improvements);
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record CreateThreadRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Subject,
|
||||
IReadOnlyList<string>? Participants);
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record GrantCallResponse(
|
||||
string Id,
|
||||
string Name,
|
||||
DateTimeOffset OpensAt,
|
||||
DateTimeOffset ClosesAt,
|
||||
string Status,
|
||||
string? ExternalId);
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record GrantConsentRequest(string Scope, DateTimeOffset? ExpiresAt);
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record IdeaAssistRequest(string? Focus);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record IdeaAssistResponse(
|
||||
IReadOnlyList<string> Suggestions,
|
||||
string ImprovedDescription,
|
||||
bool FromLlm);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record IdeaCardRequest(
|
||||
string? Essence,
|
||||
string? Audience,
|
||||
string? Stage);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record IdeaCardResponse(
|
||||
string Id,
|
||||
string IdeaId,
|
||||
string Essence,
|
||||
string Audience,
|
||||
string Stage);
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record IdeaCardRequest(
|
||||
string? Essence,
|
||||
string? Audience,
|
||||
string? Stage);
|
||||
|
||||
public sealed record CreateIdeaRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
IdeaCardRequest? Card);
|
||||
|
||||
public sealed record UpdateIdeaRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
string? Status);
|
||||
|
||||
public sealed record IdeaCardResponse(
|
||||
string Id,
|
||||
string IdeaId,
|
||||
string Essence,
|
||||
string Audience,
|
||||
string Stage);
|
||||
|
||||
public sealed record IdeaResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Description,
|
||||
string AuthorId,
|
||||
string Status,
|
||||
IdeaCardResponse? Card,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
|
||||
public sealed record IdeaAssistRequest(string? Focus);
|
||||
|
||||
public sealed record IdeaAssistResponse(
|
||||
IReadOnlyList<string> Suggestions,
|
||||
string ImprovedDescription,
|
||||
bool FromLlm);
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record IdeaResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Description,
|
||||
string AuthorId,
|
||||
string Status,
|
||||
IdeaCardResponse? Card,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record InnovationRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[StringLength(2000)] string? Summary,
|
||||
[StringLength(8000)] string? Description,
|
||||
[Required] string ChallengeId,
|
||||
[Required] string Stage,
|
||||
string? Cost,
|
||||
IReadOnlyDictionary<string, object?>? Contact,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, object?>>? Media,
|
||||
bool Published);
|
||||
|
||||
public sealed record InnovationResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Summary,
|
||||
string Description,
|
||||
string ChallengeId,
|
||||
string Stage,
|
||||
string? Cost,
|
||||
IReadOnlyDictionary<string, object?>? Contact,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, object?>> Media,
|
||||
bool Published,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record InnovationRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[StringLength(2000)] string? Summary,
|
||||
[StringLength(8000)] string? Description,
|
||||
[Required] string ChallengeId,
|
||||
[Required] string Stage,
|
||||
string? Cost,
|
||||
IReadOnlyDictionary<string, string?>? Contact,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, string?>>? Media,
|
||||
bool Published);
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record InnovationResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Summary,
|
||||
string Description,
|
||||
string ChallengeId,
|
||||
string Stage,
|
||||
string? Cost,
|
||||
IReadOnlyDictionary<string, string?>? Contact,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, string?>> Media,
|
||||
bool Published,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record InstitutionProfile(
|
||||
string? Type,
|
||||
string? Area,
|
||||
IReadOnlyList<string>? Audiences);
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record KnowledgeItemRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required] string Kind,
|
||||
string? ChallengeId,
|
||||
string? SourceUrl,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, object?>>? Attachments,
|
||||
bool Published);
|
||||
|
||||
public sealed record KnowledgeItemResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Kind,
|
||||
string? ChallengeId,
|
||||
string? SourceUrl,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, object?>> Attachments,
|
||||
bool Published,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
|
||||
public sealed record SocialChallengeResponse(
|
||||
string Id,
|
||||
string Name,
|
||||
string Description,
|
||||
int Order);
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record KnowledgeItemRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required] string Kind,
|
||||
string? ChallengeId,
|
||||
string? SourceUrl,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, string?>>? Attachments,
|
||||
bool Published);
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record KnowledgeItemResponse(
|
||||
string Id,
|
||||
string Title,
|
||||
string Kind,
|
||||
string? ChallengeId,
|
||||
string? SourceUrl,
|
||||
IReadOnlyList<IReadOnlyDictionary<string, string?>> Attachments,
|
||||
bool Published,
|
||||
DateTimeOffset? UpdatedAt);
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record LoginRequest(string Phone, string Password);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record MatchRequest(
|
||||
int? MaxResults,
|
||||
string? ChallengeId);
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record MatchResponse(
|
||||
IReadOnlyList<SimilarCaseItem> SimilarCases,
|
||||
IReadOnlyList<SolutionItem> Solutions,
|
||||
bool Fallback);
|
||||
@@ -1,23 +0,0 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record MatchRequest(
|
||||
int? MaxResults,
|
||||
string? ChallengeId);
|
||||
|
||||
public sealed record SimilarCaseItem(
|
||||
string Id,
|
||||
string Title,
|
||||
double Score);
|
||||
|
||||
public sealed record SolutionItem(
|
||||
string InnovationId,
|
||||
string Title,
|
||||
string Stage,
|
||||
string ChallengeId,
|
||||
double Score,
|
||||
string Rationale);
|
||||
|
||||
public sealed record MatchResponse(
|
||||
IReadOnlyList<SimilarCaseItem> SimilarCases,
|
||||
IReadOnlyList<SolutionItem> Solutions,
|
||||
bool Fallback);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record MessageResponse(
|
||||
string Id,
|
||||
string ThreadId,
|
||||
string AuthorId,
|
||||
string Body,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record MiddlemanRequest(
|
||||
[Required] string InnovationId,
|
||||
InstitutionProfile? InstitutionProfile,
|
||||
string? Needs);
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record MiddlemanResponse(
|
||||
string ServiceForm,
|
||||
IReadOnlyList<string> RequiredResources,
|
||||
string Rationale,
|
||||
bool FromLlm);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record NotificationResponse(
|
||||
string Id,
|
||||
string Type,
|
||||
IReadOnlyDictionary<string, string?> Payload,
|
||||
DateTimeOffset? ReadAt,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record PartnershipResponse(
|
||||
string Id,
|
||||
string InitiatorId,
|
||||
string Subject,
|
||||
IReadOnlyList<string> Partners,
|
||||
string Status);
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record RegisterRequest(string Phone, string? Email, string Password);
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record SimilarCaseItem(
|
||||
string Id,
|
||||
string Title,
|
||||
double Score);
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record SocialChallengeResponse(
|
||||
string Id,
|
||||
string Name,
|
||||
string Description,
|
||||
int Order);
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record SolutionItem(
|
||||
string InnovationId,
|
||||
string Title,
|
||||
string Stage,
|
||||
string ChallengeId,
|
||||
double Score,
|
||||
string Rationale);
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record StorageInfo(
|
||||
string Engine,
|
||||
string DataDirectory,
|
||||
string Namespace,
|
||||
string Database);
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed class StorageProbe
|
||||
{
|
||||
public string Label { get; set; } = "probe";
|
||||
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
public sealed record StorageInfo(
|
||||
string Engine,
|
||||
string DataDirectory,
|
||||
string Namespace,
|
||||
string Database);
|
||||
|
||||
public sealed record StorageStatusResponse(
|
||||
string Engine,
|
||||
string DataDirectory,
|
||||
string Namespace,
|
||||
string Database,
|
||||
int ProbeCount);
|
||||
|
||||
public sealed record StorageProbeResponse(
|
||||
string Label,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed class StorageProbe
|
||||
{
|
||||
public string Label { get; set; } = "probe";
|
||||
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record StorageProbeResponse(
|
||||
string Label,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record StorageStatusResponse(
|
||||
string Engine,
|
||||
string DataDirectory,
|
||||
string Namespace,
|
||||
string Database,
|
||||
int ProbeCount);
|
||||
-9
@@ -2,15 +2,6 @@ using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record CreateSubmissionRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
[Required] string ChallengeId,
|
||||
[Required] string LocationId,
|
||||
IReadOnlyList<string>? Keywords);
|
||||
|
||||
public sealed record UpdateSubmissionStatusRequest(
|
||||
[Required] string Status);
|
||||
|
||||
public sealed record SubmissionResponse(
|
||||
string Id,
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record TestFeedbackResponse(
|
||||
string Id,
|
||||
string InnovationId,
|
||||
string AuthorId,
|
||||
int Rating,
|
||||
string Comment,
|
||||
string Improvements,
|
||||
DateTimeOffset CreatedAt);
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record ThreadResponse(
|
||||
string Id,
|
||||
string Subject,
|
||||
IReadOnlyList<string> Participants,
|
||||
DateTimeOffset CreatedAt,
|
||||
IReadOnlyList<MessageResponse> Messages);
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record TokenResponse(
|
||||
string AccessToken,
|
||||
string TokenType,
|
||||
DateTimeOffset ExpiresAt,
|
||||
UserResponse User);
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record TrendPoint(
|
||||
string ChallengeId,
|
||||
string ChallengeName,
|
||||
int SubmissionCount);
|
||||
@@ -1,9 +1,5 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
public sealed record TrendPoint(
|
||||
string ChallengeId,
|
||||
string ChallengeName,
|
||||
int SubmissionCount);
|
||||
|
||||
public sealed record TrendsResponse(
|
||||
DateTimeOffset From,
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record UpdateApplicationRequest(
|
||||
IReadOnlyDictionary<string, string?>? Content,
|
||||
string? Status);
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record UpdateGrantCallStatusRequest([Required] string Status);
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record UpdateIdeaRequest(
|
||||
[Required, StringLength(200, MinimumLength = 3)] string Title,
|
||||
[Required, StringLength(4000, MinimumLength = 10)] string Description,
|
||||
string? Status);
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record UpdateSubmissionStatusRequest(
|
||||
[Required] string Status);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record UserResponse(
|
||||
string Id,
|
||||
string Phone,
|
||||
string? Email,
|
||||
string Role,
|
||||
string? OrganizationId);
|
||||
@@ -0,0 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TarninaHub.Application.Dtos;
|
||||
|
||||
|
||||
public sealed record VerifyKnowledgeItemRequest(bool Verified);
|
||||
@@ -0,0 +1,22 @@
|
||||
using TarninaHub.Domain.Enums;
|
||||
|
||||
namespace TarninaHub.Application.Mappings;
|
||||
|
||||
public static class PartnershipStatusWire
|
||||
{
|
||||
public static string ToWire(this PartnershipStatus status) => status switch
|
||||
{
|
||||
PartnershipStatus.Proposed => "proposed",
|
||||
PartnershipStatus.Active => "active",
|
||||
PartnershipStatus.Closed => "closed",
|
||||
_ => "proposed",
|
||||
};
|
||||
|
||||
public static PartnershipStatus? Parse(string? value) => value?.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"proposed" => PartnershipStatus.Proposed,
|
||||
"active" => PartnershipStatus.Active,
|
||||
"closed" => PartnershipStatus.Closed,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace TarninaHub.Application.Matchmaking;
|
||||
|
||||
|
||||
public sealed record LlmPrompt(string System, string User);
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace TarninaHub.Application.Matchmaking;
|
||||
|
||||
public sealed record LlmPrompt(string System, string User);
|
||||
|
||||
public static class MatchPromptBuilder
|
||||
{
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace TarninaHub.Application.Matchmaking;
|
||||
|
||||
|
||||
public sealed record RankedItem<T>(T Item, double Score);
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace TarninaHub.Application.Matchmaking;
|
||||
|
||||
public sealed record RankedItem<T>(T Item, double Score);
|
||||
|
||||
public static class SemanticRanker
|
||||
{
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace TarninaHub.Application.Security;
|
||||
|
||||
|
||||
public static class ConsentScopes
|
||||
{
|
||||
/// <summary>Access granted by the data subject's consent.</summary>
|
||||
public const string ByConsent = "by-consent";
|
||||
|
||||
/// <summary>Time-limited access (uses consent.expires_at).</summary>
|
||||
public const string Temporary = "temporary";
|
||||
|
||||
/// <summary>Fully anonymized data (no personal identifiers).</summary>
|
||||
public const string Anonymized = "anonymized";
|
||||
|
||||
public static readonly IReadOnlyList<string> All = [ByConsent, Temporary, Anonymized];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace TarninaHub.Application.Security;
|
||||
|
||||
|
||||
public static class Policies
|
||||
{
|
||||
/// <summary>operator, manager, admin — ROPS/expert staff.</summary>
|
||||
public const string Staff = "Staff";
|
||||
|
||||
/// <summary>operator, admin.</summary>
|
||||
public const string OperatorOrAdmin = "OperatorOrAdmin";
|
||||
|
||||
/// <summary>manager, operator, admin.</summary>
|
||||
public const string ManagerOrAbove = "ManagerOrAbove";
|
||||
|
||||
/// <summary>admin only.</summary>
|
||||
public const string AdminOnly = "AdminOnly";
|
||||
|
||||
/// <summary>jst and above (jst, operator, manager, admin).</summary>
|
||||
public const string JstOrAbove = "JstOrAbove";
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace TarninaHub.Application.Security;
|
||||
|
||||
|
||||
public static class RoleNames
|
||||
{
|
||||
public const string User = "user";
|
||||
public const string Jst = "jst";
|
||||
public const string Operator = "operator";
|
||||
public const string Manager = "manager";
|
||||
public const string Admin = "admin";
|
||||
|
||||
public static readonly IReadOnlyList<string> All =
|
||||
[User, Jst, Operator, Manager, Admin];
|
||||
|
||||
public static bool IsValid(string role) => All.Contains(role);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
namespace TarninaHub.Application.Security;
|
||||
|
||||
public static class RoleNames
|
||||
{
|
||||
public const string User = "user";
|
||||
public const string Jst = "jst";
|
||||
public const string Operator = "operator";
|
||||
public const string Manager = "manager";
|
||||
public const string Admin = "admin";
|
||||
|
||||
public static readonly IReadOnlyList<string> All =
|
||||
[User, Jst, Operator, Manager, Admin];
|
||||
|
||||
public static bool IsValid(string role) => All.Contains(role);
|
||||
}
|
||||
|
||||
public static class Policies
|
||||
{
|
||||
/// <summary>operator, manager, admin — ROPS/expert staff.</summary>
|
||||
public const string Staff = "Staff";
|
||||
|
||||
/// <summary>operator, admin.</summary>
|
||||
public const string OperatorOrAdmin = "OperatorOrAdmin";
|
||||
|
||||
/// <summary>manager, operator, admin.</summary>
|
||||
public const string ManagerOrAbove = "ManagerOrAbove";
|
||||
|
||||
/// <summary>admin only.</summary>
|
||||
public const string AdminOnly = "AdminOnly";
|
||||
|
||||
/// <summary>jst and above (jst, operator, manager, admin).</summary>
|
||||
public const string JstOrAbove = "JstOrAbove";
|
||||
}
|
||||
|
||||
public static class ConsentScopes
|
||||
{
|
||||
/// <summary>Access granted by the data subject's consent.</summary>
|
||||
public const string ByConsent = "by-consent";
|
||||
|
||||
/// <summary>Time-limited access (uses consent.expires_at).</summary>
|
||||
public const string Temporary = "temporary";
|
||||
|
||||
/// <summary>Fully anonymized data (no personal identifiers).</summary>
|
||||
public const string Anonymized = "anonymized";
|
||||
|
||||
public static readonly IReadOnlyList<string> All = [ByConsent, Temporary, Anonymized];
|
||||
}
|
||||
Reference in New Issue
Block a user