create_job returned plain-text bodies on every failure branch except
quota-exhausted, so the frontend's res.json() silently failed and always
showed a generic "Failed to create job" message regardless of the real
cause (company not approved, quota exhausted, DB error).
Also adds PATCH /api/admin/companies/{id}/job-slots as a manual top-up
for purchased_job_slots, since no self-serve purchase flow exists yet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- submit_for_verification: stop downgrading user_role_assignments.status
to PENDING. This was locking users out of login while their verification
was under review. Verification progress is tracked in the verifications
table; role assignment stays APPROVED throughout.
- verification_status: remove role_assignment_approved from the status
calculation. Because the assignment now stays APPROVED, using it as a
proxy was incorrectly overriding PENDING verification status to APPROVED
immediately after submission.
- companies submit_with_documents: encode document_type from filename
prefix before '|' separator (set by frontend) rather than file stem;
add duplicate-verification guard to match users service.
- job_seekers: add get_or_create_job_seeker_profile helper to ensure
profile row exists before upsert operations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document upload endpoints (job_seekers, customers, companies, and the
profession_shared crate used by 10 profession apps) returned a generic
"File upload failed" 500 on any storage error, hiding the actual cause
from both the API response and (for job_seekers/companies) the server
logs, which only printed anyhow's outer context via Display instead of
the full error chain via Debug.
Also add an explicit DefaultBodyLimit(11MB) to every affected app's
router — none had one, so axum's implicit 2MB default could silently
reject uploads under the UI's advertised 10MB cap.
Found while investigating "notifications/emails not working on approve
or job posting":
1. Real bug: apps/companies/src/handlers/mod.rs::view_contact (company
viewing an applicant's contact info) inserted into notifications
using column name `notification_type`, which has never existed —
the column is `type`. This INSERT has been failing outright every
time a company views a contact.
2. Root cause for approvals specifically: verifications/approval_requests
never existed until earlier this session (see
20260718200000_create_verifications_and_approvals) — every admin
approve/reject action was failing at the DB layer before it ever
reached the notification/email code, so nothing in this area could
have worked regardless of the email/notification logic itself.
3. Observability gap: every `state.mail.send_*_email(...)` call site
silently discarded its Result (`let _ = ...`), so if the SMTP/
Zeptomail provider is unconfigured (crates/email::Mailer already
logs a clear warning at startup for that, but callers gave no
per-send signal) or a send fails for any other reason, there was no
way to see it happen. Added `tracing::error!` logging on failure
for every job/approval-related email: job submitted, job approved,
job rejected, requirement approved, profile approval
approved/rejected, requirement submitted. Doesn't change delivery —
if the environment has no EMAIL_PROVIDER/SMTP_*/ZEPTOMAIL_*
configured, sends still fail, but that failure is now visible in
logs instead of silent.
In-app notifications for approvals were already schema-correct
(job/profile/requirement approve+reject all insert into notifications
with the right columns) — the two real defects were #1 and #2 above.
submit_with_documents parsed the multipart 'profile' field (shaped
{roleKey, profile_data: {...}} per the frontend wizard) but read fields
like company_name directly off the outer wrapper instead of unwrapping
profile_data first - every company_profiles field ended up blank, and
the double-wrapped object got stored as the verification's payload,
breaking admin-side rendering of company name/details.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a DB-trigger-generated reference_number (NXT-{TYPE}-{YY}-{000001}) to
verifications, support_tickets, payments, job_applications, lead_requests,
and users, replacing raw UUIDs shown to customers/admins. Also fixes
verification-status endpoint to return uploaded documents (previously
omitted, so documents never appeared after submission), and adds a
reference-number lookup endpoint for the AI support assistant.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- companies/admin: add proper POST /jobs/{id}/approve and /jobs/{id}/reject
endpoints (sets status=LIVE, not direct SQL bypass)
- customers: fix list_requests to query by customer_user_id (not professional),
add optional lead_id filter; fix debit to use professional_user_id
- payments: switch razorpay_order_id column to payu_txnid (PayU migration)
- users/auth: fix role resolution to not inject phantom roles for professionals
- contracts/profession_shared: fix my_requests SQL to join leads+users instead
of nonexistent requirements table
- db/job_seeker: fix INSERT VALUES placeholder count (add missing $10)
- storage: add MOCK_STORAGE=true mode for local dev without real B2 creds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restarting these deployments to pick up the corrected B2 secret revealed
they'd been running healthy old pods on top of a bad digest in the
deployment spec all along (silent from an earlier rebuild wave) — the
restart exposed it via ImagePullBackOff/ErrImagePull.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The last crates/db push (professional.rs role_key fix) rebuilt all 20
services concurrently again, and 8 of them landed ImagePullBackOff on a
digest the registry doesn't have — same congestion pattern as the
employees incident. This commit only touches apps/*/ for the affected
services so CI rebuilds just these 8 in relative isolation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add #![allow(dead_code)] pragma to all main.rs files
- Remove unused imports from users handlers (ai_cache, AiCreditPackageRepository, AiCreditTransactionRepository)
- Make LiteLLMChatMessage and LiteLLMChoice public with public fields
- Fix remaining unused variables with cargo fix
- Add missing pub visibility modifiers to litellm structs
All packages now compile with ZERO warnings and errors!
- Delete apps/companies/src/handlers/ai.rs (broken placeholder code)
- Remove ai module export from handlers/mod.rs
- Remove /api/companies/ai route from main.rs
The broken stub had:
- Uuid::parse_str("placeholder") that always errored
- Uuid::new_v4() generating random IDs instead of using auth
- Queries to non-existent company_ai_credits/ai_usage_log tables
AI credits are now properly handled by the users service with
the new ai_credits module (wallet, ledger, LiteLLM integration).
- Add AI credit management endpoints for companies
- Add AI usage history tracking
- Add AI content generation with Ollama integration
- Add Ollama client for generating job descriptions, resume analysis, and cover letters
- Integrate AI router into companies service
- companies: user.name in email and contact queries
- customers: user.name in email
- job_seekers: u.name in company user query
- cron tasks (jobs/leads/requirements): use u.name instead of u.full_name
- contracts/profession_shared: u.name for customer_name fields
- Update leads service to use 'leads' table
- Update extension models to use user_role_profile_id
- Update ProfessionalRepository to work with new schema
- Create TracecoinWalletRepository for wallet operations
- Update all handlers to use new model fields
- Rename Application fields (job_seeker_id -> applicant_user_id)
- Update cron tasks for new schema
- Fix compilation errors across all services
- Remove duplicate departments/designations/employees handlers from users service (already in employees service)
- Fix all 9 profession admin handlers to use correct DB schema (display_name, bio, location, custom_data)
- Fix companies admin handler to match CompanyProfile DB model with all fields
- Fix customers admin handler to match Requirement model with preferred_date
- Fix missing serde_json imports and type annotations in admin handlers
- Add #[allow(dead_code)] for intentionally unused structs/fields
- Add test infrastructure: auth crypto tests (2 passing), test directory structure
- Zero compilation warnings across all services
- Add AdminJobRow and AdminApplicationRow response structs
- Implement GET /api/admin/jobs with company join and applications count
- Implement GET /api/admin/applications with applicant and job details
- Gateway routing update will follow
- Add payments service proxying to Beeceptor mock gateway (create-order, verify, status)
- Add companies admin approve/reject/suspend + get detail endpoints
- Apply require_admin auth guards to all employee/department/designation handlers
- Add submit-for-verification endpoint to all 12 roles (10 professions + job seekers + customers + companies)
- Fix port conflict (employees moved from 8085 to 8096)
- Add submit_for_verification methods to all profile repositories