Update environment management by removing `.env.example` and refining Docker configurations

- Deleted the `.env.example` file to centralize configurations in `backend/.env`.
- Adjusted `docker-compose.yml` and `docker-compose.dev.yml` for improved environment variable handling.
- Enhanced nginx configuration for better API request management.

These changes streamline the setup process and improve configuration management.
pull/26/head
ahmed.mujtaba 2026-08-25 12:31:42 +05:00
commit 347856e8f8
3 changed files with 32 additions and 11 deletions

7
.gitignore vendored
View File

@ -66,3 +66,10 @@ Utopia-ai-hr-ats-portal 1.pem
# Local-only Compose overrides (never deployed)
docker.local.env
tests/**
**/.env**
# Paper form source documents (Annexure A/E/J) — reference material, not code.
# Root-anchored: backend/candidate_forms/ is the forms domain package and IS tracked.
/candidate_forms/
frontend/dist/** */
docker.local.frontend/dist/** */

View File

@ -18,7 +18,7 @@ from candidate_forms.plugins import (
)
from candidate_forms.serializers import serialize_form
from inbox.models import Inbox
from job.candidate.models import Manual_UPLOAD_CANDIDATE
from job.candidate.models import Interviews, Manual_UPLOAD_CANDIDATE
from job.history.enums import HistoryEvent
from job.history.views import HistoryRecorder
from job.job_post.models import JobPosts
@ -263,13 +263,23 @@ class CandidateForm:
)
inbox_id, manual_id, job_post_id, stage = await self._validate_link(payload)
if stage not in FORM_READY_STATUSES:
raise HTTPException(
status_code=409,
detail=(
"Forms unlock at the Interview stage — this candidate is at "
f"{stage or 'Shortlist'}"
),
)
# A scheduled interview also unlocks the forms: the paperwork belongs
# to the interview, not to which kanban column the card sits in.
# (Interview records link only to inbox rows, so manual-upload
# candidates unlock by stage alone.)
has_interview = False
if inbox_id is not None:
rows = await Interviews.get_interviews_by_inbox(self.session, inbox_id)
has_interview = bool(rows)
if not has_interview:
raise HTTPException(
status_code=409,
detail=(
"Forms unlock once the candidate reaches the Interview stage "
f"or has an interview scheduled — this candidate is at "
f"{stage or 'Shortlist'} with no interview on record"
),
)
fields = {
"inbox_id": inbox_id,

View File

@ -72,7 +72,10 @@ export default function CandidateFormsTab({ userId, live }) {
const listParams = inboxId ? { inboxId } : { manualUploadCandidateId: manualId }
const hasApplication = Boolean(inboxId || manualId)
const stage = String(live?.application_status || '').toUpperCase()
const unlocked = formsApi.FORM_READY_STATUSES.includes(stage)
// Stage-ready OR an interview on the books scheduling an interview is what
// makes the paperwork relevant, wherever the kanban card sits.
const hasInterview = (live?.interviews?.length ?? 0) > 0
const unlocked = formsApi.FORM_READY_STATUSES.includes(stage) || hasInterview
const defsQuery = useQuery({
queryKey: qk.forms.definitions(),
@ -102,8 +105,9 @@ export default function CandidateFormsTab({ userId, live }) {
if (!unlocked) {
return (
<EmptyState icon="lock" title="Forms unlock at the Interview stage">
This candidate is at {STAGE_FROM_STATUS[stage] ?? titleCase(stage)}. Move them along
the pipeline to fill the requisition, evaluation and offer forms.
This candidate is at {STAGE_FROM_STATUS[stage] ?? titleCase(stage)} with no interview
on record. Schedule an interview on the Interview tab, or move them along the
pipeline, to fill the requisition, evaluation and offer forms.
</EmptyState>
)
}