Commit Graph

139 Commits (eff4c166b37ab6555d18fb917cff87f2cc6bb0a9)

Author SHA1 Message Date
ahmed.mujtaba 56f529afa1 frontend skip logic done 2026-08-31 12:54:24 +05:00
ahmed.mujtaba 31742c2c49 correct sort implemented 2026-08-31 12:42:00 +05:00
ahmed.mujtaba bb056456fc the pipeline and dashboard synced 2026-08-31 00:27:27 +05:00
ahmed.mujtaba 4b84ae4a30 recruiterhub activity improvement 2026-08-30 23:24:00 +05:00
ahmed.mujtaba fd53730efe add hiring manager added 2026-08-30 21:49:08 +05:00
ahmed.mujtaba 7f3735362e talentpool filter workds 2026-08-30 20:50:06 +05:00
ahmed.mujtaba db176cf672 is approved and file uplaod done 2026-08-28 20:02:38 +05:00
ahmed.mujtaba e4c5ffec20 is_approved, and file_pat aded 2026-08-28 19:36:22 +05:00
ahmed.mujtaba fef9fa827b candidate s3 lkinked 2026-08-28 18:10:28 +05:00
ahmed.mujtaba 4d343c991a . 2026-08-28 16:29:01 +05:00
ahmed.mujtaba 12fa4f87fc Merge branch 'main' of https://git.utopiadeals.com/utopia-ai/HR-ATS-Portal into RELIMIt 2026-08-28 16:28:55 +05:00
ahmed.mujtaba b5d2b05a6d Hiring manager 2026-08-28 15:54:21 +05:00
ahmed.mujtaba 7e07df18ca s3 configured pending testing 2026-08-28 13:32:25 +05:00
ahmed.mujtaba 1ab52b7292 canidate flow 2026-08-27 21:03:06 +05:00
Talha Ahmed 1ae5249d18 CV bank: production-safe file storage + candidates visibility
Deploy to S3 / deploy (push) Successful in 37s Details
The banked PDF now lives IN the database (new cv_bank_files table,
manual migration 010, auto-applied at startup) instead of the container
filesystem, so production redeploys cannot lose a stored CV; upload
writes row + bytes in one commit and creates no disk file at all. New
GET /candidate/cv-bank/file serves the bytes for both download and the
in-app preview.

Per user request, banking a CV with a detectable email also creates or
reactivates the candidate account (same pattern as manual add, no setup
email), so banked people appear on the Candidates screen; a CV without
an email still banks fine, account-less. Existing bank rows were
backfilled locally.

E2E-verified: upload -> bank row + DB bytes + zero disk files, preview
and download served from the DB, candidate visible on the Candidates
screen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 19:38:40 +05:00
ahmed.mujtaba d47e90b9ec . 2026-08-27 19:21:33 +05:00
Talha Ahmed 9f610a9078 CV bank: private storage for No-Job CV imports
Deploy to S3 / deploy (push) Successful in 36s Details
Storing a CV without a job no longer rides the cv_upload pipeline, which
created a candidate user account and an inbox row — stored CVs were
leaking into the Candidates screen. New cv-bank endpoints instead write
apply_via=cv_bank rows in manual_upload_candidate (nullable user/job
FKs): file + parsed text only, no account, no inbox entry, no scoring,
and email is optional (captured when the CV contains one). The CV Import
screen now shows the bank itself below the dropzone — browse, download
(existing /documents/download route) and delete.

E2E-verified: uploads land as BANKED rows with user_id NULL, zero new
accounts or inbox rows, UI delete works, Candidates screen unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 19:20:38 +05:00
Talha Ahmed d1ca1e933d CV Import: No-Job mode — store CVs in the CV bank
Deploy to S3 / deploy (push) Successful in 36s Details
The job picker gains a No job / store in CV bank option: files upload
one-per-request through the existing POST /candidate/cv_upload pipeline
(email auto-detected from the CV, saved as an UNASSIGNED inbox item with
background job suggestions) instead of being scored. Queue rows show
Stored plus the detected email; a CV with no detectable email fails
alone with a clear message. In this mode the scored grid gives way to a
panel linking Job Matching and the Inbox, where stored CVs are browsed
and later assigned. Also guarded the matcher enqueue in ingest_upload:
with the broker down the upload used to 500 after the row was inserted.

E2E-verified: two CVs stored (emails detected), rows visible in DB with
assigned_job_post_id NULL, both surfaced in Job Matching and the Inbox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 19:11:13 +05:00
ahmed.mujtaba d5a51a28b0 / 2026-08-27 18:54:40 +05:00
ahmed.mujtaba b10d02f325 . 2026-08-27 17:59:21 +05:00
ahmed.mujtaba ecd9b3597a form integrated 2026-08-27 17:32:03 +05:00
Talha Ahmed ccec7d48db Job cover images: move storage from disk into the database
Deploy to S3 / deploy (push) Successful in 31s Details
Production containers have ephemeral filesystems, so the disk-backed
image from the previous commit would vanish on redeploy. New
job_post_images table (bytea, PK = job_posts FK so re-upload replaces),
created everywhere by manual migration 009 which run_manual_sql applies
automatically at startup — prod boots with DB_AUTOGENERATE=false and
never autogenerates tables. Upload/fetch endpoints unchanged for the
frontend; fetch now serves bytes from the row. The one locally stored
disk image was imported into the table and backend/uploads removed.

E2E re-verified: create-with-image 200, fetch 200, cover renders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:34:04 +05:00
ahmed.mujtaba fe80fa9fdc . 2026-08-27 16:20:12 +05:00
Talha Ahmed e6a82aaa23 Job posts: persist and display the cover image
Deploy to S3 / deploy (push) Successful in 32s Details
The create modal collected an image but dropped it. Now POST
/job/image/upload stores it on disk keyed by the post id (uuid-validated,
5 MB / png-jpg-webp-gif, replace-on-reupload; no DB migration) and GET
/job/image/fetch serves it. The create flow uploads right after the row
exists, image failure downgrades to a toast instead of failing the create,
and Job Details renders the cover via an authorized blob fetch.

E2E-verified: upload 200, fetch 200, cover renders in Job Details.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:17:55 +05:00
Talha Ahmed c22ea4c689 Job posts: remove the salary field
Deploy to S3 / deploy (push) Successful in 36s Details
Dropped from the create and edit modals, the detail drawer, the frontend
job mapper, and the composed publish text (which otherwise printed
Salary: Anonymous on every post). Backend model/API still tolerate the
column, so older clients and stored rows are unaffected.

UI-verified live: modal has no salary field, create POST carries no
salary key, cover-image upload previews and the post lands successfully.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:09:30 +05:00
ahmed.mujtaba d5879a0617 Refactor Google Sheets service integration
- Updated the `app.py` file to replace the generic `Sheet` service with specific services: `SheetHealth`, `SheetRead`, `SheetImport`, and `SheetWrite` for better clarity and functionality.
- Modified the `tasks.py` file to utilize the `SheetImport` service for handling sheet import tasks.
- Enhanced the `views.py` file by introducing a new class hierarchy for sheet operations, improving code organization and readability.

These changes improve the structure and maintainability of the Google Sheets integration.
2026-08-27 14:51:59 +05:00
ahmed.mujtaba 6f52436165 . 2026-08-25 20:18:12 +05:00
ahmed.mujtaba 65c189a6db . 2026-08-25 20:11:02 +05:00
Talha Ahmed cec3be73fb Title tier of relevance_score accepts token containment
Live case: the job titled "Generative Engineer" sourced a pool titled
"Generative AI Engineer" -- the exact phrase never occurs in that title,
so every genuine match fell through to the scattered 35 tier and the
whole pool compressed into the 40s. A current title containing every
job-title token now earns the full 55. The headline tier stays
phrase-only so keyword-stuffed headlines still cap at the 35 tier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 19:46:34 +05:00
ahmed.mujtaba a0ab618ac5 implemented semaphhore 2026-08-25 17:29:44 +05:00
ahmed.mujtaba a02b7aa8c3 RELIMIT 2026-08-25 17:01:46 +05:00
Talha Ahmed 9ffb3caa99 Merge remote-tracking branch 'origin/main' into Talha 2026-08-24 22:22:11 +05:00
Talha Ahmed 8bfd71194e Forms also unlock when the candidate has an interview scheduled
Scheduling an interview record did not move the pipeline stage, so
recruiters who booked an interview from the profile still saw the Forms
tab locked (reported on a Shortlist-stage candidate with a completed
Technical interview). The gate now passes when the stage is
INTERVIEW/OFFER/HIRED OR the application has any interview on record —
enforced server-side in candidate_forms create (manual-upload candidates
still unlock by stage alone, since interviews link only to inbox rows)
and mirrored in the Forms tab hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 22:21:36 +05:00
ahmed.mujtaba 5dcc824d70 .
Deploy to S3 / deploy (push) Successful in 37s Details
2026-08-24 16:23:55 +00:00
ahmed.mujtaba e114aeb0cf add .env vars 2026-08-24 21:05:53 +05:00
ahmed.mujtaba f1597792ed tests rtemoved 2026-08-24 20:40:08 +05:00
ahmed.mujtaba 29c0362517 Merge branch 'main' of https://git.utopiadeals.com/utopia-ai/HR-ATS-Portal into Implementing_limitListing 2026-08-24 20:39:31 +05:00
ahmed.mujtaba 8c12872c6e Remove `.env.example` and update Docker configurations for environment management
- Deleted the `.env.example` file as it is no longer needed; all configurations are now centralized in `backend/.env`.
- Updated `docker-compose.yml` and `docker-compose.dev.yml` to reflect changes in environment variable handling, ensuring that the application reads from `backend/.env` exclusively.
- Adjusted the nginx configuration to improve API request handling and ensure proper proxying for frontend interactions.

These changes streamline the environment setup process and enhance the overall configuration management for local and production deployments.
2026-08-24 20:38:15 +05:00
Talha Ahmed f9eb9f1f24 Candidate hiring forms (Annexure A/E/J), full-page profile, UX audit fixes
Deploy to S3 / deploy (push) Successful in 37s Details
Backend: new candidate_forms domain (requisition, interview analysis,
cultural fit) with XOR inbox/manual keys, server-recomputed section
averages and combined summary, INTERVIEW-stage gate (409), history
events, INTERVIEWS_* permissions + 008 RBAC seed; offers table gains
the seven Annexure-J fields.

Frontend: Forms tab in the candidate profile (paper-exact labels from
/forms/definitions, rating tables, score summary tiles, completion
dots); profile converted to a full page at /candidate/:userId opened
from Candidates, Talent Pool and Pipeline; live Advance Stage now calls
PATCH /candidate/stage; workflow-ordered tabs; responsive pass verified
by headless-Edge screenshots at 375-2400px; Stars import crash fix in
Interviews; Matching tab strip wraps on phones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 20:14:36 +05:00
ahmed.mujtaba 20b852d064 addn db_sweyup
Deploy to S3 / deploy (push) Successful in 35s Details
2026-08-24 15:07:11 +05:00
ahmed.mujtaba ea6f67786c . 2026-08-24 15:04:45 +05:00
Talha Ahmed 9e39bc5762 Dashboard audit fixes, Find Talent rename, already-applied matching
Dashboard/chart audit (senior-analyst pass over the live app):
- Pipeline bars were all 0% while the doughnut showed candidates: the
  percentage base was the first stage count (PROCESS, empty). Bars are
  now each stage share of the active total, REJECTED is excluded
  (matching the Analytics card), and stages sort in pipeline order.
- KPI trend chips no longer show a green up-arrow beside an empty delta;
  for lower-is-better metrics (time to hire, cost per hire) the colour
  tracks goodness while the arrow tracks the data direction.
- Closed Jobs tile no longer adds hires to closed requisitions and no
  longer hardcodes an up arrow; Offers Accepted drops the hires-series
  sparkline that plotted the wrong metric.
- charts.js: integer-friendly Y ticks (no more 0,1,1,2,2), edge-hugging
  X labels (last month was clipped), and label thinning on packed axes.

Find Talent: nav item and page title renamed from Talent to match the
action button and to distinguish it from Talent Pool.

Already-applied matching (Find Talent x ATS):
- linkedin_utils.py: shared /in/<slug> extraction that survives PDF
  mangling (percent-escapes, no scheme, trailing punctuation, /pub/).
- inbox_messages.linkedin_slug + manual_upload_candidate.linkedin_slug
  (indexed; empty = scanned-none, NULL = unscanned) written as CVs are
  processed and lazily backfilled in bounded batches at fetch time.
- talent/matching.py annotates profile payloads with already_applied
  (source, status, job, same_job, applications); profile cards and the
  detail modal show a green Already-applied / amber In-ATS-other-job
  chip.

Verified live: seeded CV mention matched its sourced profile with zero
false positives across 50 real Apify profiles; 57 backend tests and the
frontend build + smoke suites pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 20:12:16 +05:00
Talha Ahmed 600d438af3 Analytics: report library, NL ask, TTH baseline, source spend
Builds the four remaining analytics gaps from the architecture plan:

- Report library (REQ-ANL-03): new backend/reports module - saved reports
  as parameterisations of the governed analytics queries (never free-form
  SQL), rolling window_days filters, recorded runs, CSV export via
  Content-Disposition. Reports screen gains the library card with
  create/run/export/delete plus a results modal.
- Natural-language analytics (REQ-ANL-05, ADR-0010): POST /analytics/ask
  maps a question onto one whitelisted intent, runs the same governed
  query the dashboard uses, then narrates the numbers. Ask Analytics card
  on the Analytics screen; LLM outages 503 without touching the charts.
- Time-to-hire baseline (REQ-ANL-08): KPIs surface tth_baseline_* from
  org setting analytics.tth_baseline ({days,source}); not hardcoded
  per OPEN-12. analytics added to org-settings categories. Reports TTH
  card shows the delta when set.
- Source spend (REQ-ANL-09 cost side): hiring costs can be tagged with a
  source channel; source performance returns tagged spend and
  cost-per-application, including spend-only rows for channels with zero
  applications (wasted spend must stay visible). Log-cost modal and
  Source Performance table on Reports; untagged spend stays
  cost-per-hire only.

Verified live: migration autogenerated and applied (saved_reports,
report_runs, hiring_costs.source_channel_id), 50 backend tests, vite
build + smoke/token/theme suites, and a headless-browser drive of both
screens end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:24:35 +05:00
ahmed.mujtaba a8b213be39 commited 2026-08-21 13:00:22 +05:00
Talha Ahmed 5330a2504e Merge branch 'Talha'
Deploy to S3 / deploy (push) Successful in 41s Details
# Conflicts:
#	.gitignore
#	backend/main.py
2026-08-20 22:29:09 +05:00
Talha Ahmed e1bd8526f3 Talent tab: LinkedIn sourcing per job via Apify
New backend/talent/ module (runs + profiles tables, RBAC talent.* seed,
frontend-polled run lifecycle) and frontend Talent screen: job + location
pickers, paid-search confirm, big loader, ranked profile cards with match
ring, profile detail modal, show-10-then-more, next-page re-search.

Sourcing quality: current-title facet + skills-only keyword query,
experience-range facet, thin-result broadening ladder, Utopia Brands/Deals
current employees excluded actor-side and server-side, graded 0-100
relevance score (title phrase over keyword stuffing).

Also narrows the overbroad **_**_**.py gitignore rule to alembic versions;
it was silently swallowing app/tests __init__.py files, the engine smoke
script, and the new talent plugin tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 22:27:18 +05:00
ahmed.mujtaba c536def585 Update Docker and API configurations for improved job fetching and API proxying
- Adjusted `VITE_API_BASE` in Dockerfile and docker-compose.yml to allow same-origin requests, enhancing compatibility with nginx proxy settings.
- Increased the `top` query limit in `app.py` to 500 to accommodate frontend requirements while ensuring consistency across job fetching in `Jobs.jsx` and `Managers.jsx`.
- Updated nginx configuration to properly proxy API requests, preventing incorrect responses for job-related endpoints.

These changes streamline the interaction between the frontend and backend, ensuring a smoother user experience when fetching job data.
2026-08-20 18:55:49 +05:00
ahmed.mujtaba b79009679c Merge branch 'main' of https://git.utopiadeals.com/utopia-ai/HR-ATS-Portal into Implementing_limitListing 2026-08-20 18:22:40 +05:00
ahmed.mujtaba 867fea495a m. 2026-08-20 18:22:33 +05:00
ahmed.mujtaba 43189a11ae Merge branch 'main' into Add_History 2026-08-20 12:55:57 +00:00