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:
@@ -1,5 +1,6 @@
|
||||
using DeepDrftModels.Enums;
|
||||
using DeepDrftPublic.Client.Common;
|
||||
using DeepDrftPublic.Client.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
@@ -27,6 +28,7 @@ public partial class SharePopover : ComponentBase, IDisposable
|
||||
|
||||
[Inject] public required NavigationManager Navigation { get; set; }
|
||||
[Inject] public required IJSRuntime JS { get; set; }
|
||||
[Inject] public required ShareTracker ShareTracker { get; set; }
|
||||
|
||||
private bool IsReleaseMode => ReleaseEntryKey is not null;
|
||||
|
||||
@@ -67,6 +69,14 @@ public partial class SharePopover : ComponentBase, IDisposable
|
||||
{
|
||||
if (await CopyToClipboard(LinkUrl))
|
||||
{
|
||||
// Record a share only after the clipboard write succeeds (§1b). Release mode targets the
|
||||
// release EntryKey; track mode targets the track EntryKey. The tracker debounces repeat
|
||||
// copies of the same (target, channel) into one event.
|
||||
if (IsReleaseMode)
|
||||
ShareTracker.RecordShare(ShareTargetType.Release, ReleaseEntryKey!, ShareChannel.Link);
|
||||
else if (!string.IsNullOrWhiteSpace(EntryKey))
|
||||
ShareTracker.RecordShare(ShareTargetType.Track, EntryKey, ShareChannel.Link);
|
||||
|
||||
_linkCopied = true;
|
||||
await ResetAfterDelay(() => _linkCopied = false);
|
||||
}
|
||||
@@ -76,6 +86,11 @@ public partial class SharePopover : ComponentBase, IDisposable
|
||||
{
|
||||
if (await CopyToClipboard(EmbedSnippet))
|
||||
{
|
||||
// Embed is a single-track affordance only (release mode hides it), so this always targets a
|
||||
// track with channel = embed.
|
||||
if (!string.IsNullOrWhiteSpace(EntryKey))
|
||||
ShareTracker.RecordShare(ShareTargetType.Track, EntryKey, ShareChannel.Embed);
|
||||
|
||||
_embedCopied = true;
|
||||
await ResetAfterDelay(() => _embedCopied = false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user