feat(phase-16): anonymous play & share telemetry substrate (wave 16.1)
Player-service play-session tracker (floor + 3-bucket classify), SharePopover share tracker with debounce, sendBeacon interop, proxied rate-limited POST api/event/{play,share}, append-only event logs + incremental play_counter with server-side release resolution. Migration authored, not applied. No anonId, no read surface.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DeepDrftModels.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Completion bucket for a recorded play (Phase 16 §1a / D1). The three buckets are exhaustive and
|
||||
/// non-overlapping, classified by the high-water playback fraction reached before the session closed:
|
||||
/// <c>Partial</c> [0, 30%), <c>Sampled</c> [30%, 80%], <c>Complete</c> (80%, 100%]. The headline
|
||||
/// "Plays" figure is the sum of all three — every started listen that crosses the engagement floor
|
||||
/// is a play; the buckets are the texture beneath it.
|
||||
///
|
||||
/// Serialized as its string name on the wire — the converter on the type makes the
|
||||
/// client to proxy to API JSON contract string-based regardless of host serializer config.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<PlayBucket>))]
|
||||
public enum PlayBucket
|
||||
{
|
||||
/// <summary>Reached < 30% of duration — a skip or a brief partial listen (still past the floor).</summary>
|
||||
Partial,
|
||||
|
||||
/// <summary>Reached 30%–80% of duration — a real listen that was neither a skip nor a finish.</summary>
|
||||
Sampled,
|
||||
|
||||
/// <summary>Reached > 80% of duration — effectively a finished listen.</summary>
|
||||
Complete
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DeepDrftModels.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// The channel a share was performed through (Phase 16 §1b). Today both originate from
|
||||
/// <c>SharePopover</c>'s clipboard actions; a future native/Web-Share button would add a channel
|
||||
/// without reshaping the metric. Serialized as its string name on the wire.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<ShareChannel>))]
|
||||
public enum ShareChannel
|
||||
{
|
||||
/// <summary>Copy-link — the canonical track or release URL placed on the clipboard.</summary>
|
||||
Link,
|
||||
|
||||
/// <summary>Copy-embed — the <c><iframe></c> snippet for the single-track FramePlayer.</summary>
|
||||
Embed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What a share targets (Phase 16 §1b). Tracks and releases are both shareable; the popover knows
|
||||
/// which it is at the point of the action, so no server-side resolution is needed for shares.
|
||||
/// Serialized as its string name on the wire.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<ShareTargetType>))]
|
||||
public enum ShareTargetType
|
||||
{
|
||||
/// <summary>The share targets a single track, addressed by its vault <c>EntryKey</c>.</summary>
|
||||
Track,
|
||||
|
||||
/// <summary>The share targets a release, addressed by its public <c>EntryKey</c>.</summary>
|
||||
Release
|
||||
}
|
||||
Reference in New Issue
Block a user