From 3ce32496e87b0912543e4802c1d634ca7ae91769 Mon Sep 17 00:00:00 2001 From: Nick Date: Sat, 13 Sep 2025 21:04:48 +0100 Subject: [PATCH] Save --- .../Controllers/DiscoveryController.cs | 211 ++++++++-- CatherineLynwood/Models/AbTestOptions.cs | 12 + CatherineLynwood/Models/BuyLinksViewModel.cs | 8 +- CatherineLynwood/Program.cs | 3 + CatherineLynwood/Views/Discovery/Index.cshtml | 383 ------------------ .../Views/Discovery/IndexDesktop.cshtml | 338 ++++++++++++++++ .../{Index1.cshtml => IndexMobileA.cshtml} | 146 ++----- .../Views/Discovery/IndexMobileB.cshtml | 300 ++++++++++++++ .../Views/Discovery/_BuyBox.cshtml | 15 +- CatherineLynwood/appsettings.json | 3 + 10 files changed, 895 insertions(+), 524 deletions(-) create mode 100644 CatherineLynwood/Models/AbTestOptions.cs delete mode 100644 CatherineLynwood/Views/Discovery/Index.cshtml create mode 100644 CatherineLynwood/Views/Discovery/IndexDesktop.cshtml rename CatherineLynwood/Views/Discovery/{Index1.cshtml => IndexMobileA.cshtml} (75%) create mode 100644 CatherineLynwood/Views/Discovery/IndexMobileB.cshtml diff --git a/CatherineLynwood/Controllers/DiscoveryController.cs b/CatherineLynwood/Controllers/DiscoveryController.cs index 0ef946d..03afcd7 100644 --- a/CatherineLynwood/Controllers/DiscoveryController.cs +++ b/CatherineLynwood/Controllers/DiscoveryController.cs @@ -1,11 +1,10 @@ using System.Globalization; +using System.Security.Cryptography; using System.Text.RegularExpressions; - +using System.Text; using CatherineLynwood.Models; using CatherineLynwood.Services; - using Microsoft.AspNetCore.Mvc; - using Newtonsoft.Json; namespace CatherineLynwood.Controllers @@ -16,31 +15,40 @@ namespace CatherineLynwood.Controllers private readonly DataAccess _dataAccess; private readonly ICountryContext _country; + // A/B/C constants + private const string VariantCookie = "af_disc_abc"; + private const string VariantQuery = "ab"; // ?ab=A or B or C + public DiscoveryController(DataAccess dataAccess, ICountryContext country) { _dataAccess = dataAccess; _country = country; } - // ------------------------- - // Pages - // ------------------------- - [Route("")] public async Task Index() { - // 1) Resolve country ISO2 (already set by middleware) - var iso2 = (_country.Iso2 ?? "GB").ToUpperInvariant(); - if (iso2 == "UK") iso2 = "GB"; // normalise + // Prevent caches or CDNs from cross-serving variants + Response.Headers["Vary"] = "Cookie, User-Agent"; - // 2) Build server-side link slugs for this user + // Decide device class first + var device = ResolveDeviceClass(); + + // Decide variant + var variant = ResolveVariant(device); + + // Country ISO2 + var iso2 = (_country.Iso2 ?? "GB").ToUpperInvariant(); + if (iso2 == "UK") iso2 = "GB"; + + // Buy links var buyLinks = BuildBuyLinksFor(iso2); - // 3) Load reviews (unchanged) + // Reviews Reviews reviews = await _dataAccess.GetReviewsAsync(); reviews.SchemaJsonLd = GenerateBookSchemaJsonLd(reviews, 3); - // 4) Compose page VM + // VM var vm = new DiscoveryPageViewModel { Reviews = reviews, @@ -48,8 +56,17 @@ namespace CatherineLynwood.Controllers Buy = buyLinks }; - // Use your existing view (rename if you prefer): Index1.cshtml - return View("Index1", vm); + // View mapping: + // - A and B are the two MOBILE variants + // - C is the DESKTOP variant + string viewName = variant switch + { + Variant.A => "IndexMobileA", // mobile layout A + Variant.B => "IndexMobileB", // mobile layout B + _ => "IndexDesktop" // desktop layout C + }; + + return View(viewName, vm); } [Route("reviews")] @@ -57,7 +74,6 @@ namespace CatherineLynwood.Controllers { Reviews reviews = await _dataAccess.GetReviewsAsync(); reviews.SchemaJsonLd = GenerateBookSchemaJsonLd(reviews, 100); - // If you prefer a strongly-typed page VM here too, you can wrap, but returning Reviews keeps your existing view working return View(reviews); } @@ -101,9 +117,146 @@ namespace CatherineLynwood.Controllers return View(soundtrackTrackModels); } - // ------------------------- - // Private helpers - // ------------------------- + // ========================= + // A/B/C selection + // ========================= + + private enum Variant { A, B, C } + private enum DeviceClass { Mobile, Desktop } + + private Variant ResolveVariant(DeviceClass device) + { + // 0) Query override: ?ab=A|B|C forces and persists + if (Request.Query.TryGetValue(VariantQuery, out var qs)) + { + var parsed = ParseVariant(qs.ToString()); + if (parsed.HasValue) + { + // If they force A or B but device is desktop, we still respect C logic by default. + // Allow override to win for testing convenience. + WriteVariantCookie(parsed.Value); + return parsed.Value; + } + } + + // 1) Existing cookie + if (Request.Cookies.TryGetValue(VariantCookie, out var cookieVal)) + { + var parsed = ParseVariant(cookieVal); + if (parsed.HasValue) + { + // If cookie says A/B but device is desktop, upgrade to C to keep desktop experience consistent. + if (device == DeviceClass.Desktop && parsed.Value != Variant.C) + { + WriteVariantCookie(Variant.C); + return Variant.C; + } + // If cookie says C but device is mobile, you can either keep C or reassign to A/B. + // We keep C only for desktops. On mobile we reassess to A/B the first time after cookie mismatch. + if (device == DeviceClass.Mobile && parsed.Value == Variant.C) + { + var reassigned = AssignMobileVariant(); + WriteVariantCookie(reassigned); + return reassigned; + } + return parsed.Value; + } + } + + // 2) Fresh assignment + if (device == DeviceClass.Desktop) + { + WriteVariantCookie(Variant.C); + return Variant.C; + } + else + { + var assigned = AssignMobileVariant(); // A or B + WriteVariantCookie(assigned); + return assigned; + } + } + + private static Variant AssignMobileVariant(int bPercent = 50) + { + bPercent = Math.Clamp(bPercent, 0, 100); + var roll = RandomNumberGenerator.GetInt32(0, 100); // 0..99 + return roll < bPercent ? Variant.B : Variant.A; + } + + private static Variant? ParseVariant(string value) + { + if (string.Equals(value, "A", StringComparison.OrdinalIgnoreCase)) return Variant.A; + if (string.Equals(value, "B", StringComparison.OrdinalIgnoreCase)) return Variant.B; + if (string.Equals(value, "C", StringComparison.OrdinalIgnoreCase)) return Variant.C; + return null; + } + + private void WriteVariantCookie(Variant variant) + { + var opts = new CookieOptions + { + Expires = DateTimeOffset.UtcNow.AddDays(90), + HttpOnly = false, // set true if you do not need analytics to read it + Secure = true, + SameSite = SameSiteMode.Lax, + Path = "/" + }; + Response.Cookies.Append(VariantCookie, variant.ToString(), opts); + } + + // ========================= + // Device detection + // ========================= + private DeviceClass ResolveDeviceClass() + { + // Simple and robust server-side approach using User-Agent. + // Chrome UA reduction still leaves Mobile hint for Android; iOS strings include iPhone/iPad. + var ua = Request.Headers.UserAgent.ToString(); + + if (IsMobileUserAgent(ua)) + return DeviceClass.Mobile; + + return DeviceClass.Desktop; + } + + private static bool IsMobileUserAgent(string ua) + { + if (string.IsNullOrEmpty(ua)) return false; + + // Common mobile indicators + // Android phones include "Android" and "Mobile" + // iPhone includes "iPhone"; iPad includes "iPad" (treat as mobile for your layouts) + // Many mobile browsers include "Mobile" + // Exclude obvious desktop platforms + ua = ua.ToLowerInvariant(); + + if (ua.Contains("ipad") || ua.Contains("iphone") || ua.Contains("ipod")) + return true; + + if (ua.Contains("android") && ua.Contains("mobile")) + return true; + + if (ua.Contains("android") && !ua.Contains("mobile")) + { + // Likely a tablet; treat as mobile for your use case + return true; + } + + if (ua.Contains("mobile")) + return true; + + // Desktop hints + if (ua.Contains("windows nt") || ua.Contains("macintosh") || ua.Contains("x11")) + return false; + + // Fallback + return false; + } + + // ========================= + // Existing helpers + // ========================= private static BuyLinksViewModel BuildBuyLinksFor(string iso2) { @@ -149,7 +302,7 @@ namespace CatherineLynwood.Controllers LinkChoice? mk(string? slug) => string.IsNullOrEmpty(slug) ? null : new LinkChoice { Slug = slug, Url = BuyCatalog.Url(slug) }; - return new BuyLinksViewModel + var vm = new BuyLinksViewModel { Country = cc, IngramHardback = mk(ingHbSlug), @@ -163,8 +316,20 @@ namespace CatherineLynwood.Controllers Apple = mk(appleSlug)!, Kobo = mk(koboSlug)! }; - } + if (cc == "GB") + { + vm.IngramHardbackPrice = "£16.99"; + vm.IngramPaperbackPrice = "£12.99"; + } + else if (cc == "US") + { + vm.IngramHardbackPrice = "$24.99"; + vm.IngramPaperbackPrice = "$16.99"; + } + + return vm; + } private string GenerateBookSchemaJsonLd(Reviews reviews, int take) { @@ -190,13 +355,12 @@ namespace CatherineLynwood.Controllers ["name"] = "Catherine Lynwood" }, ["datePublished"] = "2025-08-21", - ["description"] = "The Alpha Flame: Discovery is a powerful, character-driven novel set in 1983 Birmingham, following Maggie Grant and Beth—two young women separated by fate, reunited by truth, and bound by secrets...", + ["description"] = "The Alpha Flame: Discovery is a powerful, character-driven novel set in 1983 Birmingham, following Maggie Grant and Beth, two young women separated by fate, reunited by truth, and bound by secrets...", ["genre"] = "Women's Fiction, Mystery, Contemporary Historical", ["inLanguage"] = "en-GB", ["url"] = baseUrl }; - // Reviews if (reviews?.Items?.Any() == true) { var reviewObjects = new List>(); @@ -233,7 +397,6 @@ namespace CatherineLynwood.Controllers }; } - // Work examples schema["workExample"] = new List> { new Dictionary diff --git a/CatherineLynwood/Models/AbTestOptions.cs b/CatherineLynwood/Models/AbTestOptions.cs new file mode 100644 index 0000000..7f1a81d --- /dev/null +++ b/CatherineLynwood/Models/AbTestOptions.cs @@ -0,0 +1,12 @@ +namespace CatherineLynwood.Models +{ + public sealed class AbTestOptions + { + #region Public Properties + + // Percentage of users who should see variant B; the rest see A + public int DiscoveryBPercent { get; set; } = 50; + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/CatherineLynwood/Models/BuyLinksViewModel.cs b/CatherineLynwood/Models/BuyLinksViewModel.cs index fc11be9..429640c 100644 --- a/CatherineLynwood/Models/BuyLinksViewModel.cs +++ b/CatherineLynwood/Models/BuyLinksViewModel.cs @@ -4,26 +4,26 @@ { #region Public Properties - // Amazon (always) public LinkChoice AmazonHardback { get; set; } = new(); public LinkChoice AmazonKindle { get; set; } = new(); public LinkChoice AmazonPaperback { get; set; } = new(); - // eBooks (always) public LinkChoice Apple { get; set; } = new(); public string Country { get; set; } = "GB"; - // Direct (optional) public LinkChoice? IngramHardback { get; set; } + public string? IngramHardbackPrice { get; set; } + public LinkChoice? IngramPaperback { get; set; } + public string? IngramPaperbackPrice { get; set; } + public LinkChoice Kobo { get; set; } = new(); - // National (optional) public LinkChoice? NationalHardback { get; set; } public string? NationalLabel { get; set; } diff --git a/CatherineLynwood/Program.cs b/CatherineLynwood/Program.cs index fe1e622..780a3ab 100644 --- a/CatherineLynwood/Program.cs +++ b/CatherineLynwood/Program.cs @@ -1,4 +1,5 @@ using CatherineLynwood.Middleware; +using CatherineLynwood.Models; using CatherineLynwood.Services; using Microsoft.AspNetCore.HttpOverrides; @@ -83,6 +84,8 @@ namespace CatherineLynwood }); builder.Services.Configure(o => o.Level = CompressionLevel.Fastest); builder.Services.Configure(o => o.Level = CompressionLevel.Fastest); + builder.Services.Configure(builder.Configuration.GetSection("AbTest")); + // HTML minification builder.Services.AddWebMarkupMin(o => diff --git a/CatherineLynwood/Views/Discovery/Index.cshtml b/CatherineLynwood/Views/Discovery/Index.cshtml deleted file mode 100644 index 133d738..0000000 --- a/CatherineLynwood/Views/Discovery/Index.cshtml +++ /dev/null @@ -1,383 +0,0 @@ -@model CatherineLynwood.Models.Reviews - -@{ - ViewData["Title"] = "The Alpha Flame: A Gritty 1980s Birmingham Crime Novel about Twin Sisters"; - - bool showReviews = Model.Items.Any(); -} - -
-
- -
-
- - -
- -
-
-
- -
-

The Front Cover

-

This is the final front cover of The Alpha Flame: Discovery. It features Maggie stood outside the derelict Rubery Hill Hospital.

-
-
-
-
- - @if (showReviews) - { - -
-
-
-
-

The Alpha Flame: Discovery
A Gritty 1980s Birmingham Crime Novel

-

Survival, secrets, and sisters in 1980s Birmingham.

-
-
- - - - -
-

★ Reader Praise ★

- - @foreach (var review in Model.Items.Take(3)) - { - var fullStars = (int)Math.Floor(review.RatingValue); - var hasHalfStar = review.RatingValue - fullStars >= 0.5; - var emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); - var reviewDate = review.DatePublished.ToString("d MMMM yyyy"); - -
- - @for (int i = 0; i < fullStars; i++) - { - - } - @if (hasHalfStar) - { - - } - @for (int i = 0; i < emptyStars; i++) - { - - } - - @Html.Raw(review.ReviewBody) -
- @review.AuthorName on - @if (string.IsNullOrEmpty(review.URL)) - { - @review.SiteName - } - else - { - @review.SiteName - } - @reviewDate -
-
- } - - @if (Model.Items.Count > 3) - { - - } - -
-
-
-
-
- - - -
-
-
-
-

The Alpha Flame: Discovery: Synopsis

-
-
-
-
- -
-
- -
- -
-

- Listen to Catherine telling you about The Alpha Flame: Discovery -

-
-
- - -

Synopsis

-

Set in 1983 Birmingham, The Alpha Flame: Discovery is a gritty crime novel following twin sisters Beth and Maggie as they uncover dark family secrets and fight to survive abuse in a harsh, realistic world. With unflinching honesty, it explores the bonds of family, the scars of the past, and the resilience needed to endure. This powerful first instalment in the trilogy immerses readers in the grim realities of 1980s Britain while celebrating hope in the face of darkness.

-

For Beth, the world is a cold and unforgiving place. Devastation strikes in a single moment, leaving her isolated, shattered, and vulnerable. Alone in the bleak shadows of a city that offers neither refuge nor redemption, she is forced to navigate a relentless cycle of desperation and despair. Every step of her journey tests the limits of her endurance, pushing her into harrowing situations where survival feels like a hollow victory. Beth’s existence is marked by loss, betrayal, and an almost suffocating loneliness that threatens to consume her entirely. Yet, even in the darkest corners of her ordeal, a fragile ember of defiance smoulders within her, a quiet, stubborn refusal to let the world destroy her completely.

-

Maggie, by contrast, is a force of nature, a woman who thrives on her unshakable drive and an unrelenting belief in her own power. Behind her fiery red hair and disarming charm lies a storm of determination and ferocity. Maggie doesn’t just live; she races through life, fuelled by a need for speed and the thrill of freedom. Her Triumph TR6 isn’t just a car; it’s an extension of her spirit, sleek, powerful, and unapologetically bold. On the open road, with the engine roaring and the world blurring past her, she feels invincible. But Maggie’s intensity doesn’t stop at the wheel. Her relationships burn just as brightly. As a lover, she is dominant, passionate, and unafraid to embrace her darker desires. While fiercely loving and loyal, Maggie is also formidable; crossing her isn’t a mistake anyone makes twice.

-

When fate brings Beth and Maggie together, their connection is explosive, a union of two polar opposites that burns with both tenderness and raw power. For Beth, Maggie represents a lifeline, a reminder that love and trust still exist, even in a world that has betrayed her at every turn. For Maggie, Beth awakens a fierce protectiveness and vulnerability she’s rarely allowed herself to feel. Together, they ignite a flame that challenges them to confront their own fears, desires, and limitations.

-

Set against the kaleidoscope of 1983, where synthesised anthems provide a pulsing soundtrack and the streets are alive with the bold styles and rebellious energy of the decade, their story unfolds in a city teeming with danger and intrigue. From high-speed chases along winding roads to dimly lit clubs and desolate alleyways, the heroines’ journey is a visceral exploration of survival and freedom. The neon haze of the era contrasts sharply with the stark realities they face, painting a vivid picture of a world where strength and vulnerability coexist.

-

As secrets surface and danger tightens its grip, Beth and Maggie must confront not only the challenges around them but the truths within themselves. Their bond is tested by betrayal, desire, and the shadows of their pasts, but through it all, their flame burns brighter, illuminating their courage and the unbreakable spirit of two heroines determined to rewrite their fates.

-

At its heart, The Alpha Flame is a story of survival, passion, and empowerment. It explores the devastating lows and triumphant highs of life with unflinching honesty, capturing the raw power of human connection against the gritty, vibrant backdrop of an unforgettable era. With its blend of drama, intensity, and unapologetic emotion, this is a story that will leave its mark long after the final frame.

- - -
-
-
-
- } - else - { - -
-
-
-
-

The Alpha Flame: Discovery
A Gritty 1980s Birmingham Crime Novel

-

Survival, secrets, and sisters in 1980s Birmingham.

-
-
-
-
- -
-
- -
- -
-

- Listen to Catherine telling you about The Alpha Flame: Discovery -

-
-
-
-
-
- - Buy Kindle Edition - - - Buy Paperback (Bookshop Edition) - - - Buy Hardback (Collector's Edition) - -

- Available from your local Amazon store.
- Or order from your local bookshop using: -

    -
  • - ISBN 978-1-0682258-1-9 - Bookshop Edition (Paperback) -
  • -
  • - ISBN 978-1-0682258-0-2 - Collector's Eidtion (Hardback) -
  • -
- -

-
-
-
- - -

Synopsis

-

Set in 1983 Birmingham, The Alpha Flame: Discovery is a gritty crime novel following twin sisters Beth and Maggie as they uncover dark family secrets and fight to survive abuse in a harsh, realistic world. With unflinching honesty, it explores the bonds of family, the scars of the past, and the resilience needed to endure. This powerful first instalment in the trilogy immerses readers in the grim realities of 1980s Britain while celebrating hope in the face of darkness.

-

For Beth, the world is a cold and unforgiving place. Devastation strikes in a single moment, leaving her isolated, shattered, and vulnerable. Alone in the bleak shadows of a city that offers neither refuge nor redemption, she is forced to navigate a relentless cycle of desperation and despair. Every step of her journey tests the limits of her endurance, pushing her into harrowing situations where survival feels like a hollow victory. Beth’s existence is marked by loss, betrayal, and an almost suffocating loneliness that threatens to consume her entirely. Yet, even in the darkest corners of her ordeal, a fragile ember of defiance smoulders within her, a quiet, stubborn refusal to let the world destroy her completely.

-

Maggie, by contrast, is a force of nature, a woman who thrives on her unshakable drive and an unrelenting belief in her own power. Behind her fiery red hair and disarming charm lies a storm of determination and ferocity. Maggie doesn’t just live; she races through life, fuelled by a need for speed and the thrill of freedom. Her Triumph TR6 isn’t just a car; it’s an extension of her spirit, sleek, powerful, and unapologetically bold. On the open road, with the engine roaring and the world blurring past her, she feels invincible. But Maggie’s intensity doesn’t stop at the wheel. Her relationships burn just as brightly. As a lover, she is dominant, passionate, and unafraid to embrace her darker desires. While fiercely loving and loyal, Maggie is also formidable; crossing her isn’t a mistake anyone makes twice.

-

When fate brings Beth and Maggie together, their connection is explosive, a union of two polar opposites that burns with both tenderness and raw power. For Beth, Maggie represents a lifeline, a reminder that love and trust still exist, even in a world that has betrayed her at every turn. For Maggie, Beth awakens a fierce protectiveness and vulnerability she’s rarely allowed herself to feel. Together, they ignite a flame that challenges them to confront their own fears, desires, and limitations.

-

Set against the kaleidoscope of 1983, where synthesised anthems provide a pulsing soundtrack and the streets are alive with the bold styles and rebellious energy of the decade, their story unfolds in a city teeming with danger and intrigue. From high-speed chases along winding roads to dimly lit clubs and desolate alleyways, the heroines’ journey is a visceral exploration of survival and freedom. The neon haze of the era contrasts sharply with the stark realities they face, painting a vivid picture of a world where strength and vulnerability coexist.

-

As secrets surface and danger tightens its grip, Beth and Maggie must confront not only the challenges around them but the truths within themselves. Their bond is tested by betrayal, desire, and the shadows of their pasts, but through it all, their flame burns brighter, illuminating their courage and the unbreakable spirit of two heroines determined to rewrite their fates.

-

At its heart, The Alpha Flame is a story of survival, passion, and empowerment. It explores the devastating lows and triumphant highs of life with unflinching honesty, capturing the raw power of human connection against the gritty, vibrant backdrop of an unforgettable era. With its blend of drama, intensity, and unapologetic emotion, this is a story that will leave its mark long after the final frame.

-
-
-
-
- } - - - - - @if (DateTime.Now < new DateTime(2025, 9, 1)) - { -
-
-
-

Win: a Collector’s Edition of The Alpha Flame: Discovery

-

- Enter my giveaway for your chance to own this special edition. Signed in the UK, or delivered as a premium collector’s copy worldwide. -

- Exclusive, limited, beautiful. - -
-
-
- } - - -
- - -
-

Chapter Previews

-
-
-
- - - -
-

Chapter 1: Drowning in Silence - Beth

-

Beth returns home to find her mother lifeless in the bath...

- -
-
-
-
-
- - - -
-

Chapter 2: The Last Lesson - Maggie

-

On Christmas Eve, Maggie nervously heads out for her driving test...

- -
-
-
-
-
- - - -
-

Chapter 13: A Name She Never Owned - Susie

-

Susie goes out for a drink with a punter. What on earth could go wrong...

- -
-
-
-
-
- - -@section Scripts { - - - - - -} - - -@section Meta{ - - - - -} diff --git a/CatherineLynwood/Views/Discovery/IndexDesktop.cshtml b/CatherineLynwood/Views/Discovery/IndexDesktop.cshtml new file mode 100644 index 0000000..f705311 --- /dev/null +++ b/CatherineLynwood/Views/Discovery/IndexDesktop.cshtml @@ -0,0 +1,338 @@ +@model CatherineLynwood.Models.DiscoveryPageViewModel + +@{ + ViewData["Title"] = "The Alpha Flame: A Gritty 1980s Birmingham Crime Novel about Twin Sisters"; + bool showReviews = Model.Reviews.Items.Any(); +} + +
+
+ +
+
+ + +
+
+ +
+
+ +
+

The Alpha Flame: Discovery

+

It's 1983 Birmingham. Maggie, my fiery heroine, standing outside the derelict Rubery Hill Hospital. A story of survival, sisters, and fire.

+
+
+
+ + + +
+
+ + +@if (showReviews) +{ + var top = Model.Reviews.Items.Where(x => x.RatingValue == 5).OrderByDescending(y => y.DatePublished).First(); + var fullStars = (int)Math.Floor(top.RatingValue); + var hasHalfStar = top.RatingValue - fullStars >= 0.5; + var emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); + var reviewDate = top.DatePublished.ToString("d MMMM yyyy"); + +
+ +
+} + + +
+
+
+

The Alpha Flame: Discovery

+

Survival, secrets, and sisters in 1983 Birmingham.

+
+ +
+ +
+
+ +
+
+
+ +
+

Listen to Catherine talking about the book

+
+
+ + +

+ Set in 1983 Birmingham, nearby Redditch, and Barmouth in Wales, The Alpha Flame: Discovery follows the lives of two young women, Beth and Maggie, as they uncover dark family secrets and fight to survive. Gritty and emotionally charged, it explores the bond between two women who refuse to be broken. +

+ + +

+ +

+ + +
+
+

For Beth, the world is a cold and unforgiving place. Devastation strikes in a single moment, leaving her isolated, shattered, and vulnerable. Alone in the bleak shadows of a city that offers neither refuge nor redemption, she is forced to navigate a relentless cycle of desperation and despair. Every step of her journey tests the limits of her endurance, pushing her into harrowing situations where survival feels like a hollow victory. Beth’s existence is marked by loss, betrayal, and an almost suffocating loneliness that threatens to consume her entirely. Yet, even in the darkest corners of her ordeal, a fragile ember of defiance smoulders within her, a quiet, stubborn refusal to let the world destroy her completely.

+

Maggie, by contrast, is a force of nature, a woman who thrives on her unshakable drive and an unrelenting belief in her own power. Behind her fiery red hair and disarming charm lies a storm of determination and ferocity. Maggie doesn’t just live; she races through life, fuelled by a need for speed and the thrill of freedom. Her Triumph TR6 isn’t just a car; it’s an extension of her spirit, sleek, powerful, and unapologetically bold. On the open road, with the engine roaring and the world blurring past her, she feels invincible. But Maggie’s intensity doesn’t stop at the wheel. Her relationships burn just as brightly. As a lover, she is dominant, passionate, and unafraid to embrace her darker desires. While fiercely loving and loyal, Maggie is also formidable; crossing her isn’t a mistake anyone makes twice.

+

When fate brings Beth and Maggie together, their connection is explosive, a union of two polar opposites that burns with both tenderness and raw power. For Beth, Maggie represents a lifeline, a reminder that love and trust still exist, even in a world that has betrayed her at every turn. For Maggie, Beth awakens a fierce protectiveness and vulnerability she’s rarely allowed herself to feel. Together, they ignite a flame that challenges them to confront their own fears, desires, and limitations.

+

Set against the kaleidoscope of 1983, where synthesised anthems provide a pulsing soundtrack and the streets are alive with the bold styles and rebellious energy of the decade, their story unfolds in a city teeming with danger and intrigue. From high-speed chases along winding roads to dimly lit clubs and desolate alleyways, the heroines’ journey is a visceral exploration of survival and freedom. The neon haze of the era contrasts sharply with the stark realities they face, painting a vivid picture of a world where strength and vulnerability coexist.

+

As secrets surface and danger tightens its grip, Beth and Maggie must confront not only the challenges around them but the truths within themselves. Their bond is tested by betrayal, desire, and the shadows of their pasts, but through it all, their flame burns brighter, illuminating their courage and the unbreakable spirit of two heroines determined to rewrite their fates.

+

At its heart, The Alpha Flame is a story of survival, passion, and empowerment. It captures the raw power of human connection against the gritty, vibrant backdrop of an unforgettable era. With its blend of drama, intensity, and unapologetic emotion, this is a story that will leave its mark long after the final page.

+
+
+
+
+
+ + + + +
+

Chapter Previews

+
+
+
+ + + +
+

Chapter 1: Drowning in Silence — Beth

+

Beth returns home to find her mother lifeless in the bath...

+ +
+
+
+
+
+ + + +
+

Chapter 2: The Last Lesson — Maggie

+

On Christmas Eve, Maggie nervously heads out for her driving test not knowing the story that will pan out before her...

+ +
+
+
+
+
+ + + +
+

Chapter 13: A Name She Never Owned — Susie

+

Susie goes out for a drink with a punter. What on earth could go wrong...

+ +
+
+
+
+
+ +@section Scripts { + + + + + + + + + + +} + +@section Meta { + + + +} diff --git a/CatherineLynwood/Views/Discovery/Index1.cshtml b/CatherineLynwood/Views/Discovery/IndexMobileA.cshtml similarity index 75% rename from CatherineLynwood/Views/Discovery/Index1.cshtml rename to CatherineLynwood/Views/Discovery/IndexMobileA.cshtml index c3f81d9..010347f 100644 --- a/CatherineLynwood/Views/Discovery/Index1.cshtml +++ b/CatherineLynwood/Views/Discovery/IndexMobileA.cshtml @@ -20,29 +20,15 @@
- -
-
- -
-

The Alpha Flame: Discovery

-

It's 1983 Birmingham. Maggie, my fiery heroine, standing outside the derelict Rubery Hill Hospital. A story of survival, sisters, and fire.

-
-
-
- -
-
-
+
+
+