[SEO] JobPosting structured data, canonical/OG meta, noindex private pages, fuller sitemap
Strategy = Google-for-Jobs + clean indexing. Add schema.org JobPosting JSON-LD to shift & job detail pages (title, description, datePosted, validThrough, employmentType, hiringOrganization, jobLocation, baseSalary) plus Organization + WebSite JSON-LD on the home page (SeoJsonLd helper; System.Text.Json => valid, script-safe). Layout emits per-page canonical, Open Graph + Twitter cards, and applies robots noindex,nofollow to all private/applicant areas (/Admin,/Me,/Employer,/Account,/Preferences) so applicant data is never indexed. robots.txt now disallows those + /resume,/avatar,/report,/push,/notifications and points at the sitemap; sitemap.xml adds facility pages + content pages (Download/Help/Privacy/Rules/Terms). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -305,7 +305,15 @@ self.addEventListener('notificationclick', e => {
|
||||
app.MapGet("/robots.txt", (HttpContext ctx) =>
|
||||
{
|
||||
var b = $"{ctx.Request.Scheme}://{ctx.Request.Host}";
|
||||
return Results.Text($"User-agent: *\nAllow: /\nDisallow: /Admin\nDisallow: /Employer\nSitemap: {b}/sitemap.xml\n", "text/plain");
|
||||
var rules = string.Join('\n',
|
||||
"User-agent: *",
|
||||
"Allow: /",
|
||||
// Private / applicant areas — never index.
|
||||
"Disallow: /Admin", "Disallow: /Employer", "Disallow: /Me", "Disallow: /Account",
|
||||
"Disallow: /Preferences", "Disallow: /resume/", "Disallow: /avatar/",
|
||||
"Disallow: /report", "Disallow: /push/", "Disallow: /notifications/",
|
||||
$"Sitemap: {b}/sitemap.xml", "");
|
||||
return Results.Text(rules, "text/plain");
|
||||
});
|
||||
|
||||
app.MapGet("/sitemap.xml", async (HttpContext ctx, AppDbContext db) =>
|
||||
@@ -326,6 +334,9 @@ app.MapGet("/sitemap.xml", async (HttpContext ctx, AppDbContext db) =>
|
||||
|
||||
foreach (var p in new[] { "", "/Shifts", "/Jobs", "/Calendar", "/Facilities" })
|
||||
Url($"{b}{p}", DateTime.UtcNow, p == "" ? "daily" : "hourly");
|
||||
// Static content pages (rarely change).
|
||||
foreach (var p in new[] { "/Download", "/Help", "/Privacy", "/Rules", "/Terms" })
|
||||
Url($"{b}{p}", null, "monthly");
|
||||
|
||||
foreach (var s in await db.Shifts.Where(s => s.Status == ShiftStatus.Open && s.Date >= today)
|
||||
.Select(s => new { s.Id, s.CreatedAt }).ToListAsync())
|
||||
@@ -335,6 +346,10 @@ app.MapGet("/sitemap.xml", async (HttpContext ctx, AppDbContext db) =>
|
||||
.Select(j => new { j.Id, j.CreatedAt }).ToListAsync())
|
||||
Url($"{b}/Jobs/Details/{j.Id}", j.CreatedAt, "weekly");
|
||||
|
||||
// Public facility pages.
|
||||
foreach (var fId in await db.Facilities.Select(f => f.Id).ToListAsync())
|
||||
Url($"{b}/Facilities/Details/{fId}", null, "weekly");
|
||||
|
||||
sb.Append("</urlset>");
|
||||
return Results.Content(sb.ToString(), "application/xml");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user