Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/instructions/csharp.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,6 @@ Demonstrates naming, structure, generics, primary constructors, nullable annotat
```csharp
namespace Company.Project.Widgets;

using ItemCache = Dictionary<string, object>;

/// <summary>Defines folding behavior for widgets.</summary>
public interface IWidget
{
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"/^dotnet --version$/": {
"approve": true,
"matchCommandLine": true
}
},
"dotnet build": true
}
}
9 changes: 7 additions & 2 deletions TalkFolio.slnx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/TalkFolio.Tests/TalkFolio.Tests.csproj" />
<Project Path="src/TalkFolio/TalkFolio.csproj" />
<Project Path="src/TalkFolio.Api/TalkFolio.Api.csproj" />
<Project Path="src/TalkFolio.Data.YamlFile/TalkFolio.Data.YamlFile.csproj" />
</Folder>
</Solution>
<Folder Name="/tst/">
<Project Path="tst/TalkFolio.Tests/TalkFolio.Tests.csproj" />
<Project Path="tst/TalkFolio.Data.YamlFile.Tests/TalkFolio.Data.YamlFile.Tests.csproj" />
</Folder>
</Solution>
1 change: 1 addition & 0 deletions docs/ADRs.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ This document consolidates the design decisions reached for TalkFolio. Each entr
* Malformed YAML throws `MalformedTalkYamlException`.
* Duplicate talk IDs throw `DuplicateTalkIdException`.
* Duplicate `(Title, PresentationFamily.Variant)` pairs throw `DuplicateTalkTitleVariantException`.
* `PresentationFamily.Name` does not participate in the duplicate-talk uniqueness key.
* These exceptions are logged as load failures and then rethrown so upstream callers can handle each failure type distinctly.
* Catalog loads only succeed when all talk files satisfy the repository invariants.

Expand Down
8 changes: 5 additions & 3 deletions docs/TalkSchema.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Tags:
- embeddings
- knowledge-graph
PresentationFamily:
Id: 8ccdf8b8-fd2c-4d41-9fe0-32fade0f41dc
Name: RAG Deep Dive
Variant: Canonical
LifecycleStatus: Active
ProposalCopyItems:
Expand Down Expand Up @@ -103,7 +103,7 @@ The current best-fit set of core fields is:
* AlternateTitles: list of marketing or branding variants
* Category: coarse top-level selection bucket from a controlled list that can expand over time
* Tags: topic labels for overlap and CFP matching; free-form strings constrained to alphanumerics and `-`
* PresentationFamily: family membership object with `Id` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`)
* PresentationFamily: family membership object with `Name` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`)
* LifecycleStatus: concept-level state
* ProposalCopyItems: typed array of inline proposal copy blocks, each with `Type` and `Copy` (`|-` literal block)
* TargetAudience: list of audience descriptors drawn from a controlled list that can expand over time
Expand Down Expand Up @@ -189,6 +189,7 @@ PresentationFamily:
* PresentationFamily is not a taxonomy node.
* It is a grouping concept, not a category hierarchy.
* Family names are treated as stable identifiers for the grouping, not display-only text.
* Catalog duplicate detection keys on Talk `Title` + `PresentationFamily.Variant` only; `PresentationFamily.Name` does not participate in that uniqueness check.
* Two talks in the same PresentationFamily should not be co-submitted to the same conference.
* TalkCircuit enforces this rule at submission time.
* TalkCircuit can find a talk's family members by querying Talks that share its `PresentationFamily.Name`.
Expand Down Expand Up @@ -329,12 +330,13 @@ The working baseline for the first TalkFolio implementation is:
* Talk entity with GUID `Id` and canonical field set
* controlled-but-extensible Category list
* Tags as free-form, hyphen-safe strings
* presentation family with the Talk owning membership via a nested `PresentationFamily` object (`Id` + `Variant`)
* presentation family with the Talk owning membership via a nested `PresentationFamily` object (`Name` + `Variant`)
* concept lifecycle of Ideation | Active | Retired
* references to SlideDeckIds and optional public publication references
* proposal copy stored inline as `ProposalCopyItems` (typed items with `|-` literal-block copy)
* companion material referenced via `RelatedContent` (typed, talk-level, lightweight references)
* flexible talk-level flags via `Flags`
* unstructured prose limited to `ProposalCopyItems[].Copy`, `IdeationNotes`, `PresentationFamily.Notes`, and `RelatedContent[].Notes`
* duplicate-talk validation keys on `Title` + `PresentationFamily.Variant` only; `PresentationFamily.Name` is not part of that uniqueness rule

This gives a clean, minimal schema that matches the domain boundary without pulling in deck-building or submission-state concerns.
17 changes: 11 additions & 6 deletions src/TalkFolio.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace TalkFolio.Api;

using TalkFolio.Data.YamlFile;
using TalkFolio.Interfaces;
using TalkFolio.Services;

#pragma warning disable CA1052, CA1515
public partial class Program
{
Expand All @@ -8,10 +12,11 @@ public static WebApplication BuildApp(string[] args)
var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddOptions<TalkCatalogRepositoryOptions>()
.BindConfiguration("TalkCatalogRepository");
.AddOptions<TalkCatalogOptions>()
.BindConfiguration("TalkCatalog");

builder.Services.AddSingleton<ITalkCatalogRepository, FileSystemTalkCatalogRepository>();
builder.Services.AddSingleton<ITalkCatalogRepository, TalkCatalogRepository>();
builder.Services.AddSingleton<TalkCatalogService>();

var app = builder.Build();

Expand All @@ -20,13 +25,13 @@ public static WebApplication BuildApp(string[] args)
app.MapGet(
"/talks",
async Task<IResult> (
ITalkCatalogRepository repository,
TalkCatalogService service,
ILoggerFactory loggerFactory,
CancellationToken cancellationToken) =>
{
var logger = loggerFactory.CreateLogger("TalkFolio.Api.TalksEndpoint");
ProgramLog.HandlingGetTalksRequest(logger);
var catalog = await repository.LoadAsync(cancellationToken).ConfigureAwait(false);
var catalog = await service.LoadAsync(cancellationToken).ConfigureAwait(false);
ProgramLog.ReturningTalksFromGetTalks(logger, catalog.Talks.Count);

if (logger.IsEnabled(LogLevel.Trace))
Expand All @@ -46,4 +51,4 @@ public static void Main(string[] args)
BuildApp(args).Run();
}
}
#pragma warning restore CA1052, CA1515
#pragma warning restore CA1052, CA1515
3 changes: 2 additions & 1 deletion src/TalkFolio.Api/TalkFolio.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<ProjectReference Include="..\TalkFolio\TalkFolio.csproj" />
<ProjectReference Include="..\TalkFolio.Data.YamlFile\TalkFolio.Data.YamlFile.csproj" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile.Serialization;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Raw YAML projection of presentation family data.
/// Raw projection of presentation family data.
/// </summary>
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Used by YamlDotNet reflection deserialization.")]
internal sealed class YamlPresentationFamilyReference
internal sealed class PresentationFamilyReference
{
public string? Name { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile.Serialization;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Raw YAML projection of proposal copy item data.
/// Raw projection of proposal copy item data.
/// </summary>
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Used by YamlDotNet reflection deserialization.")]
internal sealed class YamlProposalCopyItem
internal sealed class ProposalCopyItem
{
public string? Type { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile.Serialization;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Raw YAML projection of a public presentation reference.
/// Raw projection of a public presentation reference.
/// </summary>
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Used by YamlDotNet reflection deserialization.")]
internal sealed class YamlPublicPresentationReference
internal sealed class PublicPresentationReference
{
public string? Source { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile.Serialization;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Raw YAML projection of related companion content.
/// Raw projection of related companion content.
/// </summary>
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Used by YamlDotNet reflection deserialization.")]
internal sealed class YamlRelatedContentItem
internal sealed class RelatedContentItem
{
public string? Type { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile.Serialization;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Raw YAML projection for a talk record.
/// Raw projection for a talk record.
/// </summary>
[SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "Used by YamlDotNet reflection deserialization.")]
internal sealed class YamlTalkRecord
internal sealed class TalkRecord
{
public Guid Id { get; set; }

Expand All @@ -18,7 +18,7 @@ internal sealed class YamlTalkRecord

public List<string>? Tags { get; set; }

public YamlPresentationFamilyReference? PresentationFamily { get; set; }
public PresentationFamilyReference? PresentationFamily { get; set; }

public string? LifecycleStatus { get; set; }

Expand All @@ -28,11 +28,11 @@ internal sealed class YamlTalkRecord

public List<Guid>? SlideDeckIds { get; set; }

public List<YamlProposalCopyItem>? ProposalCopyItems { get; set; }
public List<ProposalCopyItem>? ProposalCopyItems { get; set; }

public List<YamlPublicPresentationReference>? PublicPresentationReferences { get; set; }
public List<PublicPresentationReference>? PublicPresentationReferences { get; set; }

public List<YamlRelatedContentItem>? RelatedContent { get; set; }
public List<RelatedContentItem>? RelatedContent { get; set; }

public string? IdeationNotes { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace TalkFolio;
namespace TalkFolio.Data.YamlFile;

/// <summary>
/// Configures the file-backed repository used to read TalkFolio data.
/// Configures the repository used to read TalkFolio data.
/// </summary>
public sealed class TalkCatalogRepositoryOptions
public sealed class TalkCatalogOptions
{
/// <summary>
/// Gets or sets the root directory that contains the repository data.
Expand Down
Loading