conversion: Trichter misst Verwaltungsseite, Anforderung und Firma bei der Einlösung

Roadmap 6.16. Bisher stand jede Einlösung ohne Firma im Trichter (Stufe
"Magic Link eingelöst" immer 0 Firmen), zwischen Mail-Klick und Einlösung
fehlten "Verwaltungsseite geöffnet" und "Anmeldelink angefordert", und
die Erstbuchung stand immer auf organic. Die Leiter hat jetzt sieben Stufen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-13 14:55:29 +00:00
parent f5e3f1d1fe
commit e8cf684f02
10 changed files with 211 additions and 52 deletions

View file

@ -140,7 +140,7 @@ test('consuming a magic link records step two with the token origin', function (
expect($event->source)->toBe(ConversionSource::MailReject);
});
test('registering records step four', function () {
test('registering records the account step', function () {
/** @var TestCase $this */
event(new Registered(User::factory()->create()));
@ -166,6 +166,21 @@ test('the first booking is recorded once per company', function () {
->count())->toBe(1);
});
test('the first booking carries the origin of the last redeemed link', function () {
/** @var TestCase $this */
$user = User::factory()->create();
$company = Company::factory()->create(['owner_user_id' => $user->id]);
$link = app(MagicLinkGenerator::class)->createLoginLink($user, null, 15, ConversionSource::MailPublish);
$link['magic_link']->forceFill(['consumed_at' => now()])->save();
app(ConversionRecorder::class)->recordFirstBooking($user);
// Bis 13.10.2026 stand hier immer `organic` — auch wer über die
// Veröffentlichungsmail kam und dann buchte (Roadmap 6.16).
expect(ConversionEvent::query()->where('type', ConversionEventType::FirstBooking->value)->sole()->source)
->toBe(ConversionSource::MailPublish);
});
test('a broken recording never breaks the request it accompanies', function () {
/** @var TestCase $this */
Schema::drop('conversion_events');
@ -184,7 +199,7 @@ test('the funnel counts distinct companies per step', function () {
funnelEvent(ConversionEventType::MailLinkClicked, ConversionSource::MailPublish, $a);
funnelEvent(ConversionEventType::MailLinkClicked, ConversionSource::MailPublish, $a);
funnelEvent(ConversionEventType::MailLinkClicked, ConversionSource::MailPublish, $b);
funnelEvent(ConversionEventType::MagicLinkConsumed, ConversionSource::MailPublish, $a);
funnelEvent(ConversionEventType::ManagePageOpened, ConversionSource::MailPublish, $a);
$data = app(ConversionFunnelReport::class)->build(now()->subMonth());
$steps = collect($data['sources'])->firstWhere('source', ConversionSource::MailPublish->value)['steps'];
@ -264,7 +279,7 @@ test('the ladder is complete and ordered', function () {
$steps = array_map(fn (ConversionEventType $t): int => $t->step(), ConversionEventType::ladder());
// Eine Leiter ohne Sprossen sagt nicht, wo es hakt.
expect($steps)->toBe([1, 2, 3, 4, 5])
expect($steps)->toBe([1, 2, 3, 4, 5, 6, 7])
->and(ConversionEventType::NewsroomEdited->diagnosis())->toBe('Kein Anreiz, das Profil zu pflegen');
});