DeutschLernen/GermanApp/Domain/Entities/StorySegment.cs
Lasse Rune Hansen 5a514c5a2d feat(backend/story-integration): Phase 1 - Database & Models
Implement story integration foundation:
- Create Domain/Entities/StorySegment.cs with full CRUD methods
- Create Domain/Entities/StoryProgress.cs for user story progress tracking
- Create Application/DTOs/StorySegmentDto.cs with multiple DTO types
- Create Domain/Interfaces/IStoryRepository.cs
- Create Domain/Interfaces/IStoryProgressRepository.cs
- Create Infrastructure/Data/Repositories/StoryRepository.cs
- Create Infrastructure/Data/Repositories/StoryProgressRepository.cs
- Add DbSets and entity configurations to AppDbContext
- Add navigation properties to Level, Lesson, and User entities

Next: Phase 2 - Backend Services (StoryService, StoryGenerationService)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-13 13:23:12 +02:00

200 lines
5.7 KiB
C#

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace GermanApp.Domain.Entities;
/// <summary>
/// Represents a segment of a continuous story for a specific level and lesson.
/// Story segments are unlocked sequentially as users complete lessons.
/// </summary>
public class StorySegment
{
public int Id { get; private set; }
/// <summary>
/// The CEFR level this story segment belongs to.
/// </summary>
public int LevelId { get; private set; }
/// <summary>
/// The lesson this story segment is associated with.
/// Can be null if the segment is an introduction or conclusion.
/// </summary>
public int? LessonId { get; private set; }
/// <summary>
/// The text content of the story segment.
/// </summary>
public string Content { get; private set; } = string.Empty;
/// <summary>
/// URL path to the audio file for this story segment.
/// </summary>
public string? AudioUrl { get; private set; }
/// <summary>
/// The order of this segment within the level's story.
/// Segments are displayed in ascending order.
/// </summary>
public int Order { get; private set; }
/// <summary>
/// Title or brief description of this story segment.
/// </summary>
public string Title { get; private set; } = string.Empty;
/// <summary>
/// Theme or topic of this story segment.
/// </summary>
public string Theme { get; private set; } = string.Empty;
/// <summary>
/// Estimated reading time in minutes.
/// </summary>
public int EstimatedReadingMinutes { get; private set; }
/// <summary>
/// Whether this segment is active and visible to users.
/// </summary>
public bool IsActive { get; private set; } = true;
/// <summary>
/// Timestamp when the segment was created.
/// </summary>
public DateTime CreatedAt { get; private set; }
/// <summary>
/// Timestamp when the segment was last updated.
/// </summary>
public DateTime? UpdatedAt { get; private set; }
// Navigation properties (EF Core will handle these)
public virtual Level? Level { get; private set; }
public virtual Lesson? Lesson { get; private set; }
/// <summary>
/// Constructor for EF Core deserialization.
/// </summary>
private StorySegment() { }
/// <summary>
/// Factory method to create a new story segment.
/// </summary>
/// <param name="levelId">ID of the level this segment belongs to</param>
/// <param name="lessonId">Optional ID of the associated lesson</param>
/// <param name="content">The story text content</param>
/// <param name="order">The order within the level's story</param>
/// <param name="title">Title of the segment</param>
/// <param name="theme">Theme or topic of the segment</param>
/// <param name="estimatedReadingMinutes">Estimated reading time in minutes</param>
/// <returns>New StorySegment instance</returns>
public static StorySegment Create(
int levelId,
int? lessonId,
string content,
int order,
string title,
string theme,
int estimatedReadingMinutes = 2)
{
return new StorySegment
{
LevelId = levelId,
LessonId = lessonId,
Content = content,
Order = order,
Title = title,
Theme = theme,
EstimatedReadingMinutes = estimatedReadingMinutes,
CreatedAt = DateTime.UtcNow
};
}
/// <summary>
/// Updates the content of the story segment.
/// </summary>
/// <param name="newContent">New content text</param>
public void UpdateContent(string newContent)
{
Content = newContent;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the audio URL for this segment.
/// </summary>
/// <param name="audioUrl">URL path to the audio file</param>
public void UpdateAudioUrl(string audioUrl)
{
AudioUrl = audioUrl;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the title of the story segment.
/// </summary>
/// <param name="newTitle">New title</param>
public void UpdateTitle(string newTitle)
{
Title = newTitle;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the theme of the story segment.
/// </summary>
/// <param name="newTheme">New theme</param>
public void UpdateTheme(string newTheme)
{
Theme = newTheme;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the estimated reading time.
/// </summary>
/// <param name="minutes">Estimated reading time in minutes</param>
public void UpdateEstimatedReadingMinutes(int minutes)
{
EstimatedReadingMinutes = minutes;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the order of this segment within the level's story.
/// </summary>
/// <param name="newOrder">New order value</param>
public void UpdateOrder(int newOrder)
{
Order = newOrder;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Updates the associated lesson.
/// </summary>
/// <param name="newLessonId">New lesson ID (can be null)</param>
public void UpdateLesson(int? newLessonId)
{
LessonId = newLessonId;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Activates this story segment.
/// </summary>
public void Activate()
{
IsActive = true;
UpdatedAt = DateTime.UtcNow;
}
/// <summary>
/// Deactivates this story segment.
/// </summary>
public void Deactivate()
{
IsActive = false;
UpdatedAt = DateTime.UtcNow;
}
}