Files
jobtrackingapp/docs/remaster/BUG_REPORT.md
T
cesnimda f0f178d77e docs(remaster): full-system audit + rebuild-vs-refactor decision
Deep, code-grounded audit of Job Tracker producing the mission deliverables
under docs/remaster/: system audit, bug report, architecture/data-model/AI/UX
reviews, remaster proposal, migration plan, competitor research, and the gated
REBUILD_DECISION.

Verdict: Incremental Refactor (no full rebuild). Evidence: no Critical defects;
hardened cookie/CSRF auth (token never in JS storage), real SSRF defence,
enforced multi-tenancy via global query filters, decoupled provider-swappable
AI service, 135 backend tests. Debt is localised (god controllers/entity,
missing hot-path indexes, prompt-injection hardening, CRA build debt) and
reachable by in-place, test-guarded refactors.

Also harden .gitignore: exclude agent tooling (.claude/, .bg-shell/, .agent.md)
and restore/broaden the runtime-secrets block (**/keys/, **/backups/, exports,
CV artifacts) so nested DataProtection keys can't be committed accidentally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:04:03 +02:00

4.4 KiB

Bug Report — Job Tracker

Companion to: SYSTEM_AUDIT_REPORT.md Severity: Critical / High / Medium / Low. Each item is code-grounded or explicitly [Speculative]. "Speculative" = a plausible defect I did not fully reproduce; verify before fixing.

Critical

None found. No auth bypass, no tenant-isolation break, no RCE/SSRF hole surfaced in the audited paths. (Auth uses HttpOnly cookie + CSRF; tenancy uses global query filters; ingestion has SSRF defence.) This is itself strong evidence against "rebuild".

High

ID Tag Location Description Fix
H-1 [Bug] Models/JobApplication.cs:28-31 + attachment write paths Denormalised HasResume/HasCoverLetter/HasPortfolio/HasOtherAttachment can drift from the actual Attachments collection, so the checklist UI can show a resume attached when none is, or vice-versa. Make them computed projections, or maintain via one domain method; add a test.
H-2 [Design flaw] JobApplication.TailoredCvText vs TailoredCvDraft Two writable representations of the tailored CV with no precedence rule → stale-content reads. Pick TailoredCvDraft, deprecate the inline string.
H-3 [Perf/Bug] Data/JobTrackerContext.cs (indexes) Missing indexes on IsDeleted, FollowUpAt, child FKs → full scans on every list/board/reminder/analytics query; degrades non-linearly with data. Add the 5 hot-path indexes.
H-4 [Perf] JobApplicationsController.GetStats (:1848), GetAnalyticsOverview (:2851) Loads the whole table into memory then filters/GroupBy().Count() in .NET. Aggregate server-side (EF GroupBy/CountAsync).

Medium

ID Tag Location Description Fix
M-1 [Perf/Bug] GmailController :646-657, :701-711, :893-918 N+1 loops: per-message AnyAsync in CreateSuggestedJob; redundant re-loop after a HashSet is already built in RelinkThread; message-by-message import in RefreshLinkedThreads. Batch with a single set-based query.
M-2 [Bug] GmailController :659, :713 GmailReviewDecisions loaded with ToListAsync then scanned where FirstOrDefaultAsync suffices. Use FirstOrDefaultAsync.
M-3 [Design flaw] tools/summarizer/app.py:469,527,581 Prompt injection via raw interpolation of scraped JD + instruction (capped by human-review boundary). Delimit untrusted inputs; add factuality check.
M-4 [Design flaw] JobCvMatchService "Match score" is keyword-literal; mislabels semantic matches as gaps. Relabel + synonym map.
M-5 [Design flaw] job import UX Scrape failure silently degrades to manual entry with no explanation/pre-fill. Explicit partial-parse state.
M-6 [Speculative] repeated RulesEngine.GetSettings across list/detail/reminders Same per-user settings re-read many times per request cycle. Cache in the already-registered IMemoryCache (short TTL).
M-7 [Speculative] JS-rendered boards Static HttpClient fetch returns hydration-only HTML → empty parse. Document limitation; optional headless fetch.

Low

ID Tag Location Description
L-1 [Design flaw] JobApplication.Salary (free-text) + structured salary Two salary representations; ensure writes keep them consistent or drop free-text after backfill.
L-2 [Architectural weakness] JobTrackerBackend link-compile glob Non-obvious build layout; onboarding hazard.
L-3 [Design flaw] Tags/*Json stored as JSON strings Unqueryable; fine for SQLite, revisit on MySQL/Postgres.
L-4 [Speculative] scraper plugins Silent rot with no health telemetry.

Cross-reference with .gsd

  • .gsd D007/D008 (Gmail full-thread continuity) is implemented — not a bug, a delivered decision.
  • .gsd D006 (notes-block workaround) is a known UX debt the register itself flags — Medium, schema fix.
  • .gsd/OVERRIDES.md "use next.js" is unimplemented — a plan/impl divergence, not a runtime bug, but it means the recorded frontend decision and the shipped stack disagree. Resolve deliberately.

Notes on what is NOT broken (verified, to prevent false alarms)

  • Auth token is not in localStorage/sessionStorage (asserted by login-page.test.tsx:70-71).
  • SSRF blocklist covers IPv4 private/CGNAT/link-local/benchmark + IPv6 ULA/link-local/Teredo.
  • Match scoring is deterministic — no AI in the trust-bearing number.