[SEO] JobPosting structured data, canonical/OG meta, noindex private pages, fuller sitemap
CI/CD / CI · dotnet build (push) Successful in 59s
CI/CD / Deploy · hamkadr (push) Successful in 2m27s

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:
soroush.asadi
2026-06-07 08:16:30 +03:30
parent aa61efd46f
commit 6af6a026a1
6 changed files with 194 additions and 3 deletions
+16 -1
View File
@@ -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");
});