using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PlotLine.Services; using PlotLine.ViewModels; namespace PlotLine.Controllers; [AllowAnonymous] [Route("")] public sealed class PublicController(IConfiguration configuration) : Controller { private const string SupportEmail = "hello@plotdirector.com"; private const string PolicyDate = "June 7, 2026"; private const string Keywords = "novel planning software, writing software, story planning app, author tools, plot tracking, character tracking, story timeline, novel organisation, fiction writing software, series writing software, continuity tracking, plot threads, story bible"; [HttpGet("about", Name = PublicRouteNames.About)] public IActionResult About() { SetSeo( "About PlotDirector | Built for Novelists", "Learn why PlotDirector was created by a novelist to help writers organise complex stories, manage continuity, and finish their books with confidence.", "/about", "AboutPage", "About PlotDirector"); return View(CreateModel()); } [HttpGet("contact", Name = PublicRouteNames.Contact)] public IActionResult Contact() { SetSeo( "Contact PlotDirector", "Contact PlotDirector for support, questions, feedback, or feature suggestions about our novel planning and story organisation platform.", "/contact", "ContactPage", "Contact PlotDirector"); return View(CreateModel()); } [HttpGet("privacy", Name = PublicRouteNames.Privacy)] public IActionResult Privacy() { SetSeo( "Privacy Policy | PlotDirector", "Read the PlotDirector Privacy Policy to learn how we protect your account information, subscription data, and story content.", "/privacy", "PrivacyPolicy", "Privacy Policy"); return View(CreateModel()); } [HttpGet("terms", Name = PublicRouteNames.Terms)] public IActionResult Terms() { SetSeo( "Terms of Service | PlotDirector", "Read the PlotDirector Terms of Service for information about subscriptions, user content, acceptable use, and account responsibilities.", "/terms", "WebPage", "Terms of Service"); return View(CreateModel()); } private void SetSeo(string title, string description, string path, string schemaType, string pageName) { ViewData["SeoTitle"] = title; ViewData["SeoDescription"] = description; ViewData["SeoKeywords"] = Keywords; ViewData["CanonicalUrl"] = PublicSeo.AbsoluteUrl(configuration, path); ViewData["StructuredData"] = new[] { PublicSeo.WebPageJsonLd(configuration, schemaType, pageName, path, description) }; } private static PublicPageViewModel CreateModel() => new() { SupportEmail = SupportEmail, LastUpdated = PolicyDate }; }