Commit graph

157 commits

Author SHA1 Message Date
Ashwin Kumar Sivakumar
fdd5c7a418 Fix security audit findings: admin authz, captcha, secret leak, CORS
All checks were successful
build-and-release / build (developers) (push) Successful in 5m31s
build-and-release / build (catering-services) (push) Successful in 5m56s
build-and-release / build (employees) (push) Successful in 6m23s
build-and-release / build (companies) (push) Successful in 6m31s
build-and-release / build (cron) (push) Successful in 6m38s
build-and-release / build (customers) (push) Successful in 7m19s
build-and-release / build (gateway) (push) Successful in 1m28s
build-and-release / build (fitness-trainers) (push) Successful in 2m2s
build-and-release / build (jobs) (push) Successful in 1m12s
build-and-release / build (graphic-designers) (push) Successful in 2m20s
build-and-release / build (job-seekers) (push) Successful in 2m24s
build-and-release / build (photographers) (push) Successful in 2m20s
build-and-release / build (makeup-artists) (push) Successful in 2m55s
build-and-release / build (tutors) (push) Successful in 2m15s
build-and-release / build (payments) (push) Successful in 3m48s
build-and-release / build (ugc-content-creators) (push) Successful in 2m35s
build-and-release / build (social-media-managers) (push) Successful in 4m46s
build-and-release / build (video-editors) (push) Successful in 2m41s
build-and-release / build (users) (push) Successful in 8m7s
- Require admin role on role/module/permission management endpoints
  that previously accepted any authenticated user (privilege escalation)
- Add server-side captcha generation/verification (Redis-backed,
  single-use, 5 min TTL) enforced on register/login for users and
  employees services
- Untrack .env.test111 (contained a live SMTP key) and harden
  .gitignore against future .env commits
- Stop logging OTP codes in plaintext
- Restrict jobs service CORS to an explicit origin allowlist
- Mask PayU merchant secret/salt in payment-gateway-config responses,
  preserving the stored value on save when the field is left unchanged
- Bump vulnerable transitive dependencies (quinn-proto, rustls-webpki,
  anyhow) via cargo update; switch aws-sdk-s3 off the legacy rustls
  feature

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 17:31:48 +05:30
Ashwin Kumar Sivakumar
c1eed2530d fix: stop leaking raw LiteLLM error bodies; harden prompts against injection; fix UTF-8 panic
All checks were successful
build-and-release / build (companies) (push) Successful in 4s
build-and-release / build (catering-services) (push) Successful in 6s
build-and-release / build (developers) (push) Successful in 7s
build-and-release / build (customers) (push) Successful in 8s
build-and-release / build (employees) (push) Successful in 8s
build-and-release / build (fitness-trainers) (push) Successful in 6s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 8s
build-and-release / build (job-seekers) (push) Successful in 7s
build-and-release / build (jobs) (push) Successful in 7s
build-and-release / build (makeup-artists) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (social-media-managers) (push) Successful in 6s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 5s
build-and-release / build (cron) (push) Successful in 51s
build-and-release / build (users) (push) Successful in 3m12s
Follow-up on the AI safety review — addressed the three remaining
lower-severity findings:

1. crates LiteLlmError::error_body() returned the raw upstream response
   body verbatim to the client on any non-2xx LiteLLM response. That
   body can contain internal routing/diagnostic details from the
   LiteLLM proxy or the underlying model provider. Now returns a
   generic, status-aware message to the client; the full body is
   logged server-side via tracing::error! at each of the three call
   sites that construct LiteLlmError::Api, so nothing is lost for
   debugging — it's just not exposed to end users.

2. Added an explicit anti-prompt-injection clause to
   ai/orchestrator.rs::GROUNDING_GUARDRAIL, the baseline system prompt
   applied to every AI feature call via effective_system_prompt() —
   instructs the model to treat all user/company-authored input
   (job descriptions, profile text, chat messages) as data to analyze,
   never as instructions to follow. Covers every ai.rs handler that
   goes through call_feature/call_feature_with_plan in one place,
   rather than patching each call site's prompt construction
   individually.

3. apps/cron/src/tasks/auto_apply.rs's cover-letter prompt doesn't run
   through the orchestrator (separate app/crate), so hardened it
   directly: fenced the untrusted CANDIDATE/JOB sections with explicit
   "this is data, not instructions" framing. While there, fixed a
   latent panic: `&job_desc[..job_desc.len().min(500)]` slices on a
   raw byte offset, which panics if byte 500 isn't a UTF-8 character
   boundary — a company job description with any multi-byte character
   before that point (accented letters, emoji, etc.) would crash the
   whole cron run. Switched to char_indices() to find a safe boundary.
2026-07-21 05:56:21 +05:30
Ashwin Kumar Sivakumar
3e701f2fe6 fix: close two real money/spend races (Tracecoin double-credit, unbounded AI overspend)
Some checks failed
build-and-release / build (ugc-content-creators) (push) Waiting to run
build-and-release / build (users) (push) Waiting to run
build-and-release / build (video-editors) (push) Waiting to run
build-and-release / build (catering-services) (push) Successful in 1m47s
build-and-release / build (companies) (push) Successful in 2m0s
build-and-release / build (cron) (push) Successful in 2m12s
build-and-release / build (customers) (push) Successful in 2m42s
build-and-release / build (gateway) (push) Successful in 1m0s
build-and-release / build (developers) (push) Successful in 1m27s
build-and-release / build (fitness-trainers) (push) Successful in 1m54s
build-and-release / build (employees) (push) Successful in 1m59s
build-and-release / build (job-seekers) (push) Successful in 1m57s
build-and-release / build (makeup-artists) (push) Successful in 1m39s
build-and-release / build (graphic-designers) (push) Has been cancelled
build-and-release / build (payments) (push) Has been cancelled
build-and-release / build (jobs) (push) Has been cancelled
build-and-release / build (social-media-managers) (push) Has been cancelled
build-and-release / build (tutors) (push) Has been cancelled
build-and-release / build (photographers) (push) Has been cancelled
Asked to review Tracecoin and AI implementation safety. Found and fixed
two exploitable TOCTOU races, plus a data-integrity bug:

1. apps/payments/src/main.rs::verify_payment — the PayU success callback
   is called directly by the client (not a server-to-server webhook), so
   a user fully controls how many times they replay a valid success
   payload. The payment "is it still PENDING" check and the "mark
   SUCCESS + credit wallet" write were separate, non-transactional
   queries — concurrent replays could both pass the check before either
   commits, double- (or N-times-) crediting the wallet for one real
   payment. Now wrapped in a single transaction with
   `SELECT ... FOR UPDATE` on the payments row, so a second concurrent
   call blocks until the first commits, then correctly sees the row is
   no longer PENDING (Postgres re-evaluates the WHERE clause via
   EvalPlanQual after the lock is granted).

2. crates/db/src/models/ai/repository.rs — UserAiSubscriptionRepository
   had the exact same shape of bug: apps/users/src/ai/credits.rs::
   charge_feature read the subscription, checked daily-limit and credit
   balance, THEN issued two separate unconditional `UPDATE ... SET x =
   x + $1` statements with no WHERE guard on the balance. N concurrent
   requests from one user all pass the check before any deduction
   lands, running up unlimited LLM API spend (this endpoint is called
   before/around real LiteLLM calls, so the cost is real). Added
   UserAiSubscriptionRepository::try_charge — a single conditional
   UPDATE that checks the daily limit and credit balance and deducts
   atomically, returning None (mapped to the existing error types) if
   either check fails.

3. apps/cron/src/tasks/auto_apply.rs — daily_actions_used was being
   incremented twice per auto-applied job (once in the credit-deduct
   UPDATE, once more in a second, redundant UPDATE right after) —
   silently halving job seekers' effective daily auto-apply limit.
   Removed the redundant second UPDATE.

Also added non-negative CHECK constraints directly to the live
database (tracecoin_wallets.balance/reserved,
user_ai_subscriptions.daily_actions_used/monthly_credits_used/
purchased_credits_used) as defense in depth — belt-and-suspenders in
case a future code path reintroduces a similar bug.
2026-07-21 05:51:23 +05:30
Ashwin Kumar Sivakumar
92ce2d2a86 fix: notification insert used wrong column name; log silent email failures
All checks were successful
build-and-release / build (catering-services) (push) Successful in 15s
build-and-release / build (cron) (push) Successful in 13s
build-and-release / build (developers) (push) Successful in 10s
build-and-release / build (employees) (push) Successful in 8s
build-and-release / build (fitness-trainers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 5s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 6s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (makeup-artists) (push) Successful in 6s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (social-media-managers) (push) Successful in 6s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (ugc-content-creators) (push) Successful in 6s
build-and-release / build (video-editors) (push) Successful in 6s
build-and-release / build (companies) (push) Successful in 2m9s
build-and-release / build (customers) (push) Successful in 2m47s
build-and-release / build (users) (push) Successful in 3m16s
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.
2026-07-21 04:30:34 +05:30
Ashwin Kumar Sivakumar
c570d7df67 chore: remove the dead apps/leads microservice
apps/leads implemented its own, independent "lead request" system
(POST /api/leads, /api/lead-requests/send, accept/reject) with a
schema that never matched the live one (message vs remarks, no
professional_user_id, accepted_at/rejected_at instead of resolved_at —
see 20260721030000_create_lead_requests's commit message). Confirmed
unreachable: the frontend's live flows use apps/customers'
/api/customers/requirements and each profession's /leads/request
(crates/contracts::profession_shared), never anything under
apps/leads' own paths. Its /api/lead-requests/* endpoints weren't even
reachable through the gateway (wrong prefix, never matched
/api/leads or /api/admin/leads).

Removed:
- apps/leads/ entirely, and its Cargo.toml workspace membership
- the `leads` docker-compose service, its LEADS_SERVICE_URL env var on
  gateway, and gateway's depends_on entry
- the `leads` entry from both CI build matrices (.gitea/.forgejo)
- gateway's leads_url field/routing branch — gateway no longer hard-
  requires LEADS_SERVICE_URL to boot (.expect() would have panicked
  once the service was gone); /api/admin/leads now falls through to
  the customers service, which already had a matching (previously
  shadowed) branch for it

NOTE: this service may still have a live Deployment/Service in
nxtgauge-gitops (a separate repo not touched here) — that manifest
should be removed too, or the next deploy will reference an image that
no CI job builds anymore.
2026-07-21 04:19:56 +05:30
Ashwin Kumar Sivakumar
9309334d52 seed: add a starter Tracecoin package per role; fix paise unit bug in invoice line item
Seeds one TRACECOIN_BUNDLE package per role (100 Tracecoins / ₹250,
placeholder pricing per your instruction) so the purchase flow
(CreditsPage.tsx -> GET /api/packages, filtered client-side by
role_key) has something to show instead of "No packages available for
your role," and so create_order/verify_payment/invoice generation can
actually be exercised end-to-end. Idempotent (WHERE NOT EXISTS guard)
so it's safe against the custom db-migrate runner re-executing every
file on every deploy. Adjust real pricing later via the existing admin
CRUD (POST/PATCH /api/packages) — no new endpoint needed, it already
works.

Also fixes a unit bug introduced in the invoice wiring last commit:
payments.amount_inr is already paise (copied straight from
pricing_packages.price_inr, which is paise despite the name — PayU
order creation divides it by 100 via paise_to_rupee_string), but the
invoice line item multiplied it by 100 again, making every generated
invoice show a 100x inflated amount.
2026-07-21 03:47:54 +05:30
Ashwin Kumar Sivakumar
68f659903c fix: audit_logs, tax_rules, reviews tables never existed; fix wrong column in review creation
Finished the sweep of every table referenced by live Rust code but not
created by any active migration:

- audit_logs / audit_log_changes — backs wallet::audit() (crates/wallet),
  called from every admin Tracecoin balance adjustment
  (apps/payments/src/admin.rs::adjust_credits). actor_type defaulted since
  the only caller doesn't supply it.
- tax_rules — backs the admin tax-rule CRUD in apps/payments/src/admin.rs.
  init-db.sql has a differently-named version (title/percentage/
  applicable_to); schema here matches the live code's actual columns
  (name/tax_rate/applies_to).
- reviews — backs the professional review/rating system
  (apps/users/src/handlers/reviews.rs).

Also fixed a real bug found while building the reviews schema:
admin_create_review's customer-lookup subquery selected
`lead_requests.user_id`, a column that has never existed (it's
`customer_user_id`) — would have failed on the very first review
creation attempt now that lead_requests actually exists.

Checked every other previously-flagged table (permissions, orders,
external_roles, internal_roles, kb_*, notification_*, order_items,
portfolio_images, smtp_configs, dashboard_widgets,
verification_documents) against actual Rust usage — none of them are
referenced by a real SQL query (grep hits were all Rust variable/type
names), so nothing to fix there. Full migration-chain sweep confirms
zero remaining "references a table before it's created" issues.
2026-07-21 03:05:14 +05:30
Ashwin Kumar Sivakumar
63fd3f5135 feat: generate a GST invoice automatically after a successful Tracecoin/PayU purchase
crates/invoice (InvoiceService, GST computation, HTML rendering) was
fully built but never wired to anything and never had its tables —
invoices/invoice_line_items/billing_profiles/invoice_number_seq never
existed in any active migration (same root cause as everything else
this session: only in scripts/init-db.sql, which the real db-migrate
job never runs). Created them, matching InvoiceService's actual
columns exactly rather than init-db.sql's older, simpler invoices
shape.

Fixed a real bug in InvoiceService::create while at it: four money
fields (total, and three line-item amounts) were bound as i64 against
columns/read-models that are i32 everywhere else — would have failed
every insert with a Postgres type mismatch the first time this code
ever actually ran against a real table.

Wired invoice generation into apps/payments' PayU verify_payment
handler (the actual success callback) — right after the wallet is
credited, a one-line-item GST invoice is generated from the purchased
package and PayU's billing fields (firstname/email/phone), using a
new INVOICE_SELLER_* env-configurable seller identity. Generation
failures are logged, not surfaced to the buyer, since the payment and
wallet credit have already succeeded by that point.

Also added the missing user-facing endpoints to fetch what got
generated: GET /api/payments/invoices (list) and
GET /api/payments/invoices/{id} (detail + line items) — previously
only admin-side invoice viewing existed.

NOTE: the frontend (nxtgauge-frontend-solid, a separate repo) has an
existing invoice-viewing page at src/routes/dashboard/wallet/invoices/
but it calls /wallet/me/invoices (no /api/ prefix) via a different,
apparently-dead API helper (api.get, not apiFetch) that every other
live page avoids — same dead-code pattern as the earlier apps/leads
discovery. The live purchase flow (CreditsPage.tsx) has no invoice UI
at all yet. Not fixed here since it's out of this repo's scope this
session — flagging for a frontend pass.
2026-07-21 03:02:47 +05:30
Ashwin Kumar Sivakumar
b5dea58ed4 fix: customer document submission and profile verification
customer_profiles already had custom_data but never got a `status`
column, so — same root cause already fixed for job_seeker_profiles —
the generic profile save/get/submit handlers failed outright for the
CUSTOMER role, and the admin final-approval path couldn't write a
verified status either.

- Migration: add customer_profiles.status (default 'DRAFT').
- Special-case CUSTOMER in the generic profile.rs handlers (get_profile,
  save_profile, fetch_saved_profile, set_profile_status), mirroring the
  existing JOB_SEEKER special-case, storing basic-tab fields under
  custom_data.basic_info.
- Re-enable the CUSTOMER branch in activate_profile_after_final_approval
  now that the status column exists.
- Add the missing POST /api/customers/profile/documents upload endpoint
  — the frontend's document upload (required: Aadhar/Government ID)
  targets this exact path for CUSTOMER and previously 404'd since no
  such route was ever registered. Mirrors the B2-upload-only pattern
  used by the profession apps' shared upload_document handler.

Verified separately: requirement posting (POST /api/customers/requirements)
and requirement submission-for-verification (POST
/api/customers/requirements/:id/submit) already work correctly — both
use the `leads` table (an active migration, despite the model's
"Requirement" naming) and properly create a verification record
(case_type REQUIREMENT_APPROVAL) that lands in admin Verification
Management via the existing approve_requirement/reject_requirement
handlers. No changes needed there.
2026-07-21 01:39:25 +05:30
Ashwin Kumar Sivakumar
4e292efbdf fix: profession admin listing endpoints matched role_key in the wrong case
Each profession's admin list/get endpoint (apps/<role>/src/admin.rs) filtered
user_role_profiles by a lowercase role_key literal (e.g. 'photographer'), but
the app always stores it uppercase ('PHOTOGRAPHER', matching role_to_table in
apps/users/src/handlers/role_meta.rs). These endpoints therefore always
returned an empty list / 404, regardless of how many professionals had
actually submitted. catering_services also had a singular/plural mismatch
('catering_service' vs the stored 'CATERING_SERVICES'). Uppercased (and
correctly pluralized) all 10 literals to match.
2026-07-21 01:28:09 +05:30
Ashwin Kumar Sivakumar
2e95c4750b fix: company job posting, job seeker profile submission, and job applications
- Company approval wrote profile status to 'ACTIVE' (company_profiles'
  own pre-verification default) using an id column that never matched
  any row, so create_job's APPROVED check always rejected newly
  approved companies. Match on user_id for user_id-keyed tables and
  write the canonical 'APPROVED' status.
- job_seeker_profiles was missing columns the job-seeker app has
  always queried (full_name, location, summary, skills,
  active_application_count, status), and the job_applications /
  job_seeker_documents tables it depends on were never migrated in —
  job seeker profile save/submit and job applications failed outright
  with "column/relation does not exist".
- Renamed the job_seeker first_name/last_name split to full_name to
  match what the frontend has always sent.
- Special-cased JOB_SEEKER in the generic profile.rs handlers (mirrors
  the existing COMPANY special-case) so the shared ProfilePage save/
  submit flow, which was routed through a user_role_profile_id-based
  path job_seeker_profiles never had, now persists correctly.
- Fixed apply_to_job's company notification query joining a
  nonexistent "companies" table instead of company_profiles.
- Fixed auto-apply cron's company status filter to match the
  corrected 'APPROVED' status.
2026-07-21 01:00:47 +05:30
Ashwin Kumar Sivakumar
00923681ec fix: company profile submission stored wrapper object as verification payload
All checks were successful
build-and-release / build (customers) (push) Successful in 8s
build-and-release / build (catering-services) (push) Successful in 11s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (developers) (push) Successful in 14s
build-and-release / build (gateway) (push) Successful in 5s
build-and-release / build (employees) (push) Successful in 15s
build-and-release / build (cron) (push) Successful in 18s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (leads) (push) Successful in 6s
build-and-release / build (jobs) (push) Successful in 6s
build-and-release / build (makeup-artists) (push) Successful in 6s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (users) (push) Successful in 6s
build-and-release / build (companies) (push) Successful in 2m2s
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>
2026-07-19 22:03:36 +05:30
Ashwin Kumar Sivakumar
e4c9fc31ee feat: human-readable reference numbers + fix verification document visibility
All checks were successful
build-and-release / build (developers) (push) Successful in 1m42s
build-and-release / build (companies) (push) Successful in 1m48s
build-and-release / build (catering-services) (push) Successful in 1m55s
build-and-release / build (cron) (push) Successful in 2m4s
build-and-release / build (customers) (push) Successful in 2m26s
build-and-release / build (employees) (push) Successful in 1m24s
build-and-release / build (fitness-trainers) (push) Successful in 1m37s
build-and-release / build (gateway) (push) Successful in 1m38s
build-and-release / build (graphic-designers) (push) Successful in 1m54s
build-and-release / build (jobs) (push) Successful in 1m48s
build-and-release / build (leads) (push) Successful in 1m40s
build-and-release / build (job-seekers) (push) Successful in 2m52s
build-and-release / build (photographers) (push) Successful in 1m50s
build-and-release / build (payments) (push) Successful in 2m16s
build-and-release / build (makeup-artists) (push) Successful in 2m48s
build-and-release / build (tutors) (push) Successful in 2m16s
build-and-release / build (social-media-managers) (push) Successful in 2m42s
build-and-release / build (ugc-content-creators) (push) Successful in 2m36s
build-and-release / build (video-editors) (push) Successful in 2m19s
build-and-release / build (users) (push) Successful in 5m10s
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>
2026-07-19 16:34:00 +05:30
Ashwin Kumar Sivakumar
bb616c6db1 fix(db): make three more migrations idempotent; log swallowed login DB error
All checks were successful
build-and-release / build (customers) (push) Successful in 1m23s
build-and-release / build (employees) (push) Successful in 1m48s
build-and-release / build (catering-services) (push) Successful in 1m57s
build-and-release / build (companies) (push) Successful in 2m6s
build-and-release / build (cron) (push) Successful in 2m23s
build-and-release / build (gateway) (push) Successful in 51s
build-and-release / build (developers) (push) Successful in 2m44s
build-and-release / build (fitness-trainers) (push) Successful in 1m39s
build-and-release / build (jobs) (push) Successful in 45s
build-and-release / build (graphic-designers) (push) Successful in 2m16s
build-and-release / build (job-seekers) (push) Successful in 2m16s
build-and-release / build (leads) (push) Successful in 1m46s
build-and-release / build (payments) (push) Successful in 2m19s
build-and-release / build (makeup-artists) (push) Successful in 3m0s
build-and-release / build (photographers) (push) Successful in 2m42s
build-and-release / build (social-media-managers) (push) Successful in 2m19s
build-and-release / build (ugc-content-creators) (push) Successful in 2m33s
build-and-release / build (tutors) (push) Successful in 2m42s
build-and-release / build (video-editors) (push) Successful in 2m44s
build-and-release / build (users) (push) Successful in 6m38s
Same class of bug as the ai_plans_and_limits fix: ai_credit_packages and
users_litellm_key used plain CREATE TABLE/ADD COLUMN with no re-run guard,
and payu_rename_columns did a bare RENAME COLUMN that fails outright on any
second run ("column razorpay_order_id does not exist"). All three were
discovered by actually running the db-migrate job end to end for the first
time and fixed in the same pass as the verification_logs FK fix - already
baked into the db-migrate image that was built and run manually, this
commit just brings the source in the repo in sync with what's deployed.

Also: apps/employees login handler's DB error was being discarded via
.map_err(|_| ...) with zero logging, making the reported "db error while
logging in" impossible to diagnose from pod logs. Log the real error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 04:40:31 +05:30
Ashwin Kumar Sivakumar
a0d97583c4 ci: retrigger isolated employees rebuild (bad digest from concurrent push)
All checks were successful
build-and-release / build (catering-services) (push) Successful in 15s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (customers) (push) Successful in 14s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 5s
build-and-release / build (cron) (push) Successful in 17s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 6s
build-and-release / build (users) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 6s
build-and-release / build (developers) (push) Successful in 8s
build-and-release / build (graphic-designers) (push) Successful in 7s
build-and-release / build (makeup-artists) (push) Successful in 5s
build-and-release / build (leads) (push) Successful in 6s
build-and-release / build (companies) (push) Successful in 10s
build-and-release / build (jobs) (push) Successful in 6s
build-and-release / build (employees) (push) Successful in 1m45s
The 20-service matrix push for 8a29b81 landed a digest in gitops for
employees that doesn't exist in the registry (ImagePullBackOff, confirmed
via kubectl - same failure mode documented in 512eb72/ea622a4). This commit
only touches apps/employees/ so the CI path-filter rebuilds just that one
service in isolation, avoiding the concurrent-push contention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 00:30:27 +05:30
Ashwin Kumar Sivakumar
8a29b81c84 feat(admin-auth): add POST /api/admin/auth/refresh for sliding session window
All checks were successful
build-and-release / build (gateway) (push) Successful in 1m33s
build-and-release / build (graphic-designers) (push) Successful in 2m13s
build-and-release / build (ugc-content-creators) (push) Successful in 2m12s
build-and-release / build (users) (push) Successful in 4m48s
build-and-release / build (catering-services) (push) Successful in 1m22s
build-and-release / build (job-seekers) (push) Successful in 3m20s
build-and-release / build (companies) (push) Successful in 2m36s
build-and-release / build (social-media-managers) (push) Successful in 2m18s
build-and-release / build (tutors) (push) Successful in 2m41s
build-and-release / build (customers) (push) Successful in 1m38s
build-and-release / build (employees) (push) Successful in 3m16s
build-and-release / build (makeup-artists) (push) Successful in 1m46s
build-and-release / build (photographers) (push) Successful in 2m39s
build-and-release / build (jobs) (push) Successful in 1m5s
build-and-release / build (cron) (push) Successful in 1m40s
build-and-release / build (leads) (push) Successful in 2m18s
build-and-release / build (payments) (push) Successful in 3m10s
build-and-release / build (fitness-trainers) (push) Successful in 1m25s
build-and-release / build (video-editors) (push) Successful in 2m11s
build-and-release / build (developers) (push) Successful in 1m43s
Admin access tokens expire after 15 minutes with no way to renew one, so
active admins got logged out mid-work with no warning (silent 401s, now
surfaced by admin-solid's session-expired dialog). Add a refresh endpoint
that exchanges the HttpOnly nxtgauge_admin_token cookie for a new 15-minute
access token, rotating the employee_sessions row (revoke old, store new) -
mirrors the existing pattern in apps/users/src/handlers/auth.rs, but against
the DB-backed employee_sessions table instead of Redis.

Add EmployeeRepository::get_by_id / get_valid_session_by_token / revoke_session
to support it.

The admin-solid frontend calls this on a timer while the admin is active and
skips it once idle for 15 minutes, so the session now extends while active
and expires on inactivity as intended, instead of on a fixed wall-clock timer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 00:14:08 +05:30
Tracewebstudio Dev
f56251374a Increase LiteLLM request timeout from 60s to 180s
All checks were successful
build-and-release / build (catering-services) (push) Successful in 9s
build-and-release / build (customers) (push) Successful in 8s
build-and-release / build (fitness-trainers) (push) Successful in 5s
build-and-release / build (cron) (push) Successful in 15s
build-and-release / build (companies) (push) Successful in 16s
build-and-release / build (employees) (push) Successful in 14s
build-and-release / build (gateway) (push) Successful in 6s
build-and-release / build (developers) (push) Successful in 16s
build-and-release / build (graphic-designers) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 6s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (makeup-artists) (push) Successful in 7s
build-and-release / build (jobs) (push) Successful in 6s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 6s
build-and-release / build (social-media-managers) (push) Successful in 5s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (video-editors) (push) Successful in 5s
build-and-release / build (users) (push) Successful in 3m36s
The askash-main model at llm.nxtgauge.com takes 60-120s to generate
job descriptions; previous 60s timeout caused all JD generations to fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-18 14:23:04 +02:00
Tracewebstudio Dev
623cda47b0 fix: end-to-end workflow fixes for company/job-seeker and profession flows
All checks were successful
build-and-release / build (employees) (push) Successful in 1m25s
build-and-release / build (developers) (push) Successful in 1m41s
build-and-release / build (customers) (push) Successful in 1m43s
build-and-release / build (cron) (push) Successful in 1m57s
build-and-release / build (catering-services) (push) Successful in 2m19s
build-and-release / build (companies) (push) Successful in 2m44s
build-and-release / build (fitness-trainers) (push) Successful in 1m36s
build-and-release / build (gateway) (push) Successful in 1m40s
build-and-release / build (graphic-designers) (push) Successful in 1m50s
build-and-release / build (jobs) (push) Successful in 1m42s
build-and-release / build (job-seekers) (push) Successful in 2m31s
build-and-release / build (leads) (push) Successful in 2m1s
build-and-release / build (photographers) (push) Successful in 1m46s
build-and-release / build (makeup-artists) (push) Successful in 2m30s
build-and-release / build (social-media-managers) (push) Successful in 2m42s
build-and-release / build (tutors) (push) Successful in 2m16s
build-and-release / build (video-editors) (push) Successful in 2m19s
build-and-release / build (payments) (push) Successful in 4m40s
build-and-release / build (ugc-content-creators) (push) Successful in 4m35s
build-and-release / build (users) (push) Successful in 4m45s
- 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>
2026-07-18 11:40:01 +02:00
Ashwin Kumar Sivakumar
f5201965d8 Issue each account its own LiteLLM virtual key instead of the shared master key
All checks were successful
build-and-release / build (cron) (push) Successful in 5m1s
build-and-release / build (catering-services) (push) Successful in 9m1s
build-and-release / build (customers) (push) Successful in 9m3s
build-and-release / build (developers) (push) Successful in 9m23s
build-and-release / build (employees) (push) Successful in 10m36s
build-and-release / build (companies) (push) Successful in 10m59s
build-and-release / build (gateway) (push) Successful in 3m26s
build-and-release / build (fitness-trainers) (push) Successful in 8m52s
build-and-release / build (jobs) (push) Successful in 4m46s
build-and-release / build (graphic-designers) (push) Successful in 8m44s
build-and-release / build (job-seekers) (push) Successful in 9m22s
build-and-release / build (makeup-artists) (push) Successful in 8m33s
build-and-release / build (leads) (push) Successful in 10m17s
build-and-release / build (payments) (push) Successful in 8m40s
build-and-release / build (photographers) (push) Successful in 9m36s
build-and-release / build (social-media-managers) (push) Successful in 8m38s
build-and-release / build (tutors) (push) Successful in 8m42s
build-and-release / build (ugc-content-creators) (push) Successful in 7m27s
build-and-release / build (video-editors) (push) Successful in 7m46s
build-and-release / build (users) (push) Successful in 10m0s
register() now generates a per-account LiteLLM key (best-effort, non-blocking)
and stores it on the user. New internal endpoint GET /internal/users/{id}/llm-key
lets other services fetch (or lazily backfill) an account's key, authenticated
via the existing X-AI-Service-Key shared secret.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 20:29:00 +05:30
Ashwin Kumar Sivakumar
74664176da chore: retrigger isolated CI builds for users, social-media-managers (again)
All checks were successful
build-and-release / build (companies) (push) Successful in 9s
build-and-release / build (customers) (push) Successful in 7s
build-and-release / build (developers) (push) Successful in 4s
build-and-release / build (catering-services) (push) Successful in 14s
build-and-release / build (cron) (push) Successful in 13s
build-and-release / build (employees) (push) Successful in 3s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 6s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (graphic-designers) (push) Successful in 6s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 6m13s
build-and-release / build (users) (push) Successful in 7m32s
Both still on stale bad digests after the previous retrigger. Old replicas
continue serving traffic throughout, so no outage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 05:50:21 +05:30
Ashwin Kumar Sivakumar
6c5c6b6938 chore: retrigger isolated CI build for social-media-managers
All checks were successful
build-and-release / build (catering-services) (push) Successful in 8s
build-and-release / build (customers) (push) Successful in 7s
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (employees) (push) Successful in 13s
build-and-release / build (cron) (push) Successful in 16s
build-and-release / build (companies) (push) Successful in 16s
build-and-release / build (developers) (push) Successful in 15s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 3s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 6s
build-and-release / build (payments) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 6s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 5s
build-and-release / build (users) (push) Successful in 5s
build-and-release / build (social-media-managers) (push) Successful in 5m40s
Landed a bad digest again in the previous batch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 05:03:19 +05:30
Ashwin Kumar Sivakumar
b8785e39f2 chore: retrigger isolated CI builds for services with stale bad digests
All checks were successful
build-and-release / build (employees) (push) Successful in 12s
build-and-release / build (customers) (push) Successful in 15s
build-and-release / build (cron) (push) Successful in 15s
build-and-release / build (fitness-trainers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (catering-services) (push) Successful in 8m41s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (graphic-designers) (push) Successful in 8m35s
build-and-release / build (developers) (push) Successful in 9m8s
build-and-release / build (companies) (push) Successful in 9m25s
build-and-release / build (makeup-artists) (push) Successful in 9m12s
build-and-release / build (social-media-managers) (push) Successful in 9m4s
build-and-release / build (video-editors) (push) Successful in 8m49s
build-and-release / build (users) (push) Successful in 10m56s
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>
2026-07-15 04:14:58 +05:30
Ashwin Kumar Sivakumar
bf3850c282 chore: retrigger isolated CI builds for photographers, payments
All checks were successful
build-and-release / build (companies) (push) Successful in 9s
build-and-release / build (developers) (push) Successful in 7s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (employees) (push) Successful in 12s
build-and-release / build (customers) (push) Successful in 14s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (cron) (push) Successful in 16s
build-and-release / build (catering-services) (push) Successful in 17s
build-and-release / build (graphic-designers) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (makeup-artists) (push) Successful in 6s
build-and-release / build (social-media-managers) (push) Successful in 5s
build-and-release / build (tutors) (push) Successful in 5s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (users) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 5m50s
build-and-release / build (payments) (push) Successful in 5m58s
Both landed ImagePullBackOff on bad digests from the previous batch;
old replicas kept serving throughout, so no outage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 03:23:56 +05:30
Ashwin Kumar Sivakumar
ea622a4af8 chore: retrigger isolated CI builds for 6 more services on bad digests
All checks were successful
build-and-release / build (catering-services) (push) Successful in 3s
build-and-release / build (companies) (push) Successful in 5s
build-and-release / build (customers) (push) Successful in 4s
build-and-release / build (developers) (push) Successful in 5s
build-and-release / build (employees) (push) Successful in 6s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (makeup-artists) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 3m25s
build-and-release / build (users) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 3s
build-and-release / build (cron) (push) Successful in 4m4s
build-and-release / build (jobs) (push) Successful in 4m12s
build-and-release / build (tutors) (push) Successful in 7m13s
build-and-release / build (fitness-trainers) (push) Successful in 8m58s
build-and-release / build (ugc-content-creators) (push) Successful in 8m51s
Same congestion pattern from the crates/contracts push. gateway still had
2 healthy replicas serving traffic throughout, so no outage — just a
failed rolling-update replica for these 6 services.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 03:01:39 +05:30
Ashwin Kumar Sivakumar
95184f83c4 chore: retrigger isolated CI builds for 8 services stuck on bad digests
Some checks failed
build-and-release / build (makeup-artists) (push) Waiting to run
build-and-release / build (payments) (push) Waiting to run
build-and-release / build (photographers) (push) Waiting to run
build-and-release / build (social-media-managers) (push) Waiting to run
build-and-release / build (tutors) (push) Waiting to run
build-and-release / build (ugc-content-creators) (push) Waiting to run
build-and-release / build (users) (push) Waiting to run
build-and-release / build (video-editors) (push) Waiting to run
build-and-release / build (customers) (push) Successful in 14s
build-and-release / build (cron) (push) Successful in 14s
build-and-release / build (employees) (push) Successful in 12s
build-and-release / build (fitness-trainers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 6s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (developers) (push) Has been cancelled
build-and-release / build (companies) (push) Has been cancelled
build-and-release / build (catering-services) (push) Has been cancelled
build-and-release / build (graphic-designers) (push) Has been cancelled
build-and-release / build (job-seekers) (push) Has been cancelled
build-and-release / build (leads) (push) Has been cancelled
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>
2026-07-15 02:32:46 +05:30
Ashwin Kumar Sivakumar
fb681accc3 fix(profile): use user_role_profile_id column, not id, for profession tables
All checks were successful
build-and-release / build (companies) (push) Successful in 4s
build-and-release / build (catering-services) (push) Successful in 5s
build-and-release / build (cron) (push) Successful in 5s
build-and-release / build (customers) (push) Successful in 5s
build-and-release / build (developers) (push) Successful in 4s
build-and-release / build (employees) (push) Successful in 5s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 3s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 3s
build-and-release / build (payments) (push) Successful in 5s
build-and-release / build (tutors) (push) Successful in 5s
build-and-release / build (ugc-content-creators) (push) Successful in 3s
build-and-release / build (social-media-managers) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 3s
build-and-release / build (users) (push) Successful in 7m58s
The profession-specific tables (photographer_profiles, tutor_profiles, etc.)
were extended with a separate user_role_profile_id FK column and a NOT NULL
user_id column, but every generic profile query still treated the shared
user_role_profiles.id value as if it were the profession table's own `id`
PK, and never supplied user_id at all. Result: PATCH /api/profile 500'd
with "null value in column user_id violates not-null constraint" on every
first-time save for any of the 10 professional roles — profile saves were
completely broken, which cascades into submit-for-verification always
running off an empty fallback payload with no real data or documents.
Fixes get_profile, save_profile, set_profile_status, and
fetch_saved_profile_by_urp_id to query/write user_role_profile_id (and
populate user_id on insert) instead of assuming id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 00:57:39 +05:30
Ashwin Kumar Sivakumar
89a2076974 fix(verifications): wrap list response in {items: [...]}
Some checks failed
build-and-release / build (employees) (push) Successful in 7s
build-and-release / build (cron) (push) Successful in 10s
build-and-release / build (developers) (push) Successful in 12s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (companies) (push) Successful in 15s
build-and-release / build (catering-services) (push) Successful in 16s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (customers) (push) Successful in 16s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (graphic-designers) (push) Successful in 5s
build-and-release / build (makeup-artists) (push) Successful in 3s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 4s
build-and-release / build (payments) (push) Successful in 6s
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 6s
build-and-release / build (users) (push) Has been cancelled
GET /api/admin/verifications returned a bare JSON array, but every
consumer (Verification Management, Approval Management, and the e2e
test's own mock) expects {items: [...]}. Array.isArray(payload?.items)
was always false against a bare array, so both admin screens have been
showing "No verification requests found" regardless of what's actually
in the queue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 00:51:14 +05:30
Ashwin Kumar Sivakumar
512eb722a5 chore(employees): retrigger isolated CI build
All checks were successful
build-and-release / build (companies) (push) Successful in 9s
build-and-release / build (customers) (push) Successful in 8s
build-and-release / build (catering-services) (push) Successful in 12s
build-and-release / build (developers) (push) Successful in 4s
build-and-release / build (cron) (push) Successful in 12s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (graphic-designers) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (users) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (employees) (push) Successful in 5m53s
The prior push (crates/cache change) rebuilt all 20 workspace services
concurrently, and the employees job's build/push landed a digest that
doesn't exist in the registry (kubectl confirmed ImagePullBackOff with
"not found" resolving that exact sha256). This commit only touches
apps/employees/ so the CI path-filter rebuilds just that one service in
isolation, without the same concurrent-build congestion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 00:34:39 +05:30
Ashwin Kumar Sivakumar
01f3810c8f feat(employees): add forgot-password/reset-password for admin accounts
All checks were successful
build-and-release / build (cron) (push) Successful in 4m55s
build-and-release / build (catering-services) (push) Successful in 9m18s
build-and-release / build (developers) (push) Successful in 9m14s
build-and-release / build (employees) (push) Successful in 9m15s
build-and-release / build (customers) (push) Successful in 9m35s
build-and-release / build (companies) (push) Successful in 9m49s
build-and-release / build (gateway) (push) Successful in 3m2s
build-and-release / build (fitness-trainers) (push) Successful in 8m20s
build-and-release / build (jobs) (push) Successful in 4m22s
build-and-release / build (graphic-designers) (push) Successful in 8m41s
build-and-release / build (job-seekers) (push) Successful in 9m14s
build-and-release / build (leads) (push) Successful in 9m10s
build-and-release / build (makeup-artists) (push) Successful in 8m51s
build-and-release / build (payments) (push) Successful in 8m51s
build-and-release / build (photographers) (push) Successful in 8m39s
build-and-release / build (ugc-content-creators) (push) Successful in 6m57s
build-and-release / build (social-media-managers) (push) Successful in 8m25s
build-and-release / build (tutors) (push) Successful in 8m28s
build-and-release / build (video-editors) (push) Successful in 8m43s
build-and-release / build (users) (push) Successful in 11m8s
Employees (internal admin/staff) had no self-service password reset —
only /login, /logout, /session existed. Adds /api/admin/auth/forgot-password
and /api/admin/auth/reset-password, mirroring the existing users-table flow
but against EmployeeRepository and a distinct Redis key namespace
(reset:employee:*) so a code for one identity store can never be consumed
against the other.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 23:28:39 +05:30
Ashwin Kumar Sivakumar
308daf4959 fix(verification): align document keys and dedupe role maps across handlers
All checks were successful
build-and-release / build (cron) (push) Successful in 16s
build-and-release / build (social-media-managers) (push) Successful in 3s
build-and-release / build (developers) (push) Successful in 15s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 6s
build-and-release / build (video-editors) (push) Successful in 5s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (customers) (push) Successful in 7s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (catering-services) (push) Successful in 10s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 6s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (gateway) (push) Successful in 3s
build-and-release / build (users) (push) Successful in 8m30s
build-and-release / build (employees) (push) Successful in 13s
build-and-release / build (companies) (push) Successful in 16s
build-and-release / build (graphic-designers) (push) Successful in 3s
extract_documents() recognized a stale set of document keys that no longer
matched what the frontend actually uploads (portfolio_ownership_proof,
professional_certifications, qualification_proof, tax_document), so every
non-COMPANY role's verification case was created with an empty documents
array. Also extracts role_key_to_display/role_to_table into a shared
role_meta module — verifications.rs and approvals.rs were each missing
UGC_CONTENT_CREATOR from their inline copies, so that role's rejections
and final approvals were silently no-ops.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 21:23:30 +05:30
Ashwin Kumar Sivakumar
b9133018a5 fix(admin-auth): add rate limiting to admin login endpoint
All checks were successful
build-and-release / build (makeup-artists) (push) Successful in 8m13s
build-and-release / build (cron) (push) Successful in 4m39s
build-and-release / build (gateway) (push) Successful in 2m47s
build-and-release / build (employees) (push) Successful in 8m49s
build-and-release / build (fitness-trainers) (push) Successful in 7m42s
build-and-release / build (payments) (push) Successful in 8m6s
build-and-release / build (jobs) (push) Successful in 4m19s
build-and-release / build (catering-services) (push) Successful in 9m29s
build-and-release / build (photographers) (push) Successful in 8m44s
build-and-release / build (customers) (push) Successful in 9m30s
build-and-release / build (tutors) (push) Successful in 7m8s
build-and-release / build (developers) (push) Successful in 9m35s
build-and-release / build (graphic-designers) (push) Successful in 9m33s
build-and-release / build (social-media-managers) (push) Successful in 8m57s
build-and-release / build (leads) (push) Successful in 9m9s
build-and-release / build (ugc-content-creators) (push) Successful in 8m52s
build-and-release / build (video-editors) (push) Successful in 8m14s
build-and-release / build (companies) (push) Successful in 9m58s
build-and-release / build (job-seekers) (push) Successful in 9m55s
build-and-release / build (users) (push) Successful in 10m21s
The admin/employee login handler had no brute-force protection, unlike
the regular user login path. Given these accounts hold internal/
super-admin privileges, add a tighter limit (5 attempts/15min vs 10
for regular users) using the existing sliding-window Redis limiter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 16:12:52 +05:30
Ashwin Kumar Sivakumar
e53098728a refactor(companies): remove local-disk fallback from submit_with_documents — B2 only
All checks were successful
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (users) (push) Successful in 4s
build-and-release / build (companies) (push) Successful in 6m14s
build-and-release / build (developers) (push) Successful in 7s
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (catering-services) (push) Successful in 13s
build-and-release / build (customers) (push) Successful in 12s
build-and-release / build (cron) (push) Successful in 15s
build-and-release / build (employees) (push) Successful in 14s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (gateway) (push) Successful in 3s
build-and-release / build (graphic-designers) (push) Successful in 4s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 4s
2026-07-11 02:13:56 +05:30
Ashwin Kumar Sivakumar
a019f86477 feat(companies): add /profile/submit-with-documents endpoint with local-disk fallback for B2 outages
All checks were successful
build-and-release / build (cron) (push) Successful in 14s
build-and-release / build (graphic-designers) (push) Successful in 3s
build-and-release / build (jobs) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 6s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (customers) (push) Successful in 7s
build-and-release / build (makeup-artists) (push) Successful in 3s
build-and-release / build (payments) (push) Successful in 4s
build-and-release / build (photographers) (push) Successful in 3s
build-and-release / build (catering-services) (push) Successful in 9s
build-and-release / build (tutors) (push) Successful in 5s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 6s
build-and-release / build (users) (push) Successful in 4s
build-and-release / build (fitness-trainers) (push) Successful in 4s
build-and-release / build (video-editors) (push) Successful in 3s
build-and-release / build (developers) (push) Successful in 13s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (companies) (push) Successful in 6m38s
build-and-release / build (employees) (push) Successful in 13s
2026-07-11 01:31:03 +05:30
Ashwin Kumar Sivakumar
5fa1f8f74c fix(profile): persist all COMPANY profile fields, not just company_name
All checks were successful
build-and-release / build (developers) (push) Successful in 7s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (companies) (push) Successful in 10s
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (users) (push) Successful in 7m44s
build-and-release / build (cron) (push) Successful in 15s
build-and-release / build (customers) (push) Successful in 13s
build-and-release / build (employees) (push) Successful in 12s
build-and-release / build (gateway) (push) Successful in 3s
build-and-release / build (catering-services) (push) Successful in 16s
build-and-release / build (graphic-designers) (push) Successful in 4s
build-and-release / build (job-seekers) (push) Successful in 4s
build-and-release / build (jobs) (push) Successful in 5s
build-and-release / build (makeup-artists) (push) Successful in 4s
build-and-release / build (leads) (push) Successful in 4s
build-and-release / build (payments) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (tutors) (push) Successful in 3s
build-and-release / build (ugc-content-creators) (push) Successful in 4s
2026-07-10 14:27:15 +05:30
Ashwin Kumar Sivakumar
9d475858ab fix(auth): default role assignment to APPROVED at signup
All checks were successful
build-and-release / build (fitness-trainers) (push) Successful in 3s
build-and-release / build (catering-services) (push) Successful in 13s
build-and-release / build (customers) (push) Successful in 12s
build-and-release / build (gateway) (push) Successful in 4s
build-and-release / build (employees) (push) Successful in 14s
build-and-release / build (graphic-designers) (push) Successful in 3s
build-and-release / build (cron) (push) Successful in 16s
build-and-release / build (job-seekers) (push) Successful in 5s
build-and-release / build (jobs) (push) Successful in 3s
build-and-release / build (leads) (push) Successful in 5s
build-and-release / build (payments) (push) Successful in 3s
build-and-release / build (makeup-artists) (push) Successful in 5s
build-and-release / build (photographers) (push) Successful in 5s
build-and-release / build (tutors) (push) Successful in 4s
build-and-release / build (social-media-managers) (push) Successful in 4s
build-and-release / build (ugc-content-creators) (push) Successful in 5s
build-and-release / build (video-editors) (push) Successful in 4s
build-and-release / build (users) (push) Successful in 7m30s
build-and-release / build (companies) (push) Successful in 9s
build-and-release / build (developers) (push) Successful in 8s
Roles assigned at registration are immediately active for login + session.
Document/profile approval (handled separately by user_role_profiles in
onboarding/verifications) is the correct gate for review workflows —
do not gate raw role assignment on that flow.

Previously defaulted to PENDING for non-demo accounts, which get filtered
out by get_user_role_keys (WHERE status = 'APPROVED') and produced JWTs
with empty roles, causing the 'role is not assigned' UX bug after login.
2026-07-09 23:41:49 +05:30
Ashwin Kumar Sivakumar
f7d0f6f9f5 fix: Update Dockerfiles to use ci.nxtgauge.com registry
Some checks failed
build-and-release / build (companies) (push) Failing after 39s
build-and-release / build (catering-services) (push) Failing after 57s
build-and-release / build (cron) (push) Failing after 1m4s
build-and-release / build (gateway) (push) Successful in 3m46s
build-and-release / build (fitness-trainers) (push) Successful in 9m8s
build-and-release / build (graphic-designers) (push) Successful in 8m58s
build-and-release / build (employees) (push) Successful in 9m17s
build-and-release / build (customers) (push) Successful in 9m47s
build-and-release / build (developers) (push) Successful in 9m48s
build-and-release / build (job-seekers) (push) Successful in 9m1s
build-and-release / build (jobs) (push) Successful in 4m17s
build-and-release / build (leads) (push) Successful in 8m23s
build-and-release / build (makeup-artists) (push) Successful in 8m40s
build-and-release / build (payments) (push) Successful in 9m21s
build-and-release / build (photographers) (push) Successful in 9m20s
build-and-release / build (social-media-managers) (push) Successful in 8m9s
build-and-release / build (tutors) (push) Successful in 8m16s
build-and-release / build (ugc-content-creators) (push) Successful in 6m59s
build-and-release / build (video-editors) (push) Successful in 6m9s
build-and-release / build (users) (push) Successful in 8m37s
2026-07-08 03:37:18 +05:30
Ashwin Kumar Sivakumar
519a52813f fix(jobs): nest jobs router under /api/jobs to match gateway routing
The gateway forwards /api/jobs unmodified to the jobs service, but the
service registered its routes at bare /jobs with no prefix — every
other service (companies, users) nests under /api/<service> to match.
This made the public job listing endpoint unreachable (404) through
the gateway on test111.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 18:15:34 +05:30
Ashwin Kumar Sivakumar
cba7f607cd fix: resolve all warnings and errors
- 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!
2026-07-06 03:00:37 +05:30
Ashwin Kumar Sivakumar
b99651f330 fix: resolve warnings (partial)
- Fix unused variable entry_type -> _entry_type
- Remove unused imports BufMut and cache_jobs from companies handlers
- Fix doc comment on lazy_static
- Add #[allow(dead_code)] to reset_daily_actions and reset_monthly_credits
- Fix unused imports in job_seekers handlers
2026-07-06 02:55:42 +05:30
Ashwin Kumar Sivakumar
e83271c300 fix: resolve payments package compilation errors
- Remove duplicate 'name' field from PricingPackageRow struct
- Add tracecoins_credited variable from package.tracecoins_amount
- Change rust_decimal to use i32 instead of Decimal for SQL compatibility
- Simplify discount calculation to work with paise (integer) values
- Fix payu config field names (merchant_key, merchant_salt)

payments package now compiles successfully.
2026-07-06 02:32:14 +05:30
Ashwin Kumar Sivakumar
0ac0527232 fix: resolve match arm type mismatches and add Deserialize trait
- Fix match arm type errors in ai.rs: wrap bare String returns in (String, bool)
  tuples to match expected return type (response_text, _ollama_used)
- Add Deserialize trait to LiteLLMChatMessage for deserialization
- Add missing fields to GenerateFieldResponse constructors
- Remove body.user_id reference from form extraction (field doesn't exist)
- Add get_llm_base_url() and get_llm_model() helper functions

users package now compiles successfully (only warnings remain).
2026-07-06 02:27:09 +05:30
Ashwin Kumar Sivakumar
339325091c fix: resolve cherry-pick breakage and add missing modules
- Restore deleted module declarations (tutor, ugc_content_creator, user,
  user_role_profile, verification, video_editor) in db/models/mod.rs
- Add mod ai; to users/src/main.rs (fixes crate::ai import)
- Add pub mod ai_auto; to handlers/mod.rs
- Add rust_decimal dependency to payments/Cargo.toml
- Fix missing PgPool import in payments/src/ai_credits.rs
- Make LiteLLMUsage fields public in users/src/litellm.rs
- Add get_llm_base_url() and get_llm_model() helper functions
- Remove leading underscore from variables that are used

Partial fix for high-performance branch build issues.
2026-07-06 02:23:29 +05:30
Ashwin Kumar Sivakumar
4f2683d085 chore: remove legacy AI quota system
Delete legacy code that used old company_ai_usage/job_seeker_ai_usage tables:
- Remove has_active_ai_pack() - old AI_PACK pricing package check
- Remove check_and_increment_usage() - legacy daily quota tracking
- Remove BASE_AI_LIMIT, get_ai_limit_for_package constants/functions
- Remove legacy queries from ai_auto_apply() and ai_usage_status()
- Update auto_apply.rs to use user_ai_subscriptions.daily_actions_used
  instead of job_seeker_ai_usage table
- Inline apply_scheduled_downgrades() and expire_trials() in cron tasks
  to remove dependency on users crate internal modules

The new system uses user_ai_subscriptions with:
- daily_actions_used / daily_credits_used counters
- monthly_credits_total / monthly_credits_used
- purchased_credits_total / purchased_credits_used

All AI billing now flows through the wallet/ledger system with
LiteLLM integration (Tasks 1-10).
2026-07-06 02:14:23 +05:30
Ashwin Kumar Sivakumar
c795242040 chore: remove broken company_ai_credits stub
- 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).
2026-07-06 02:08:07 +05:30
Ashwin Kumar Sivakumar
0dd5045676 feat: Complete Ask Ash AI Credits implementation on high-performance branch (Tasks 1-10)
- Task 1: Admin endpoints for wallet management
- Task 2: AI Credits admin UI (pricing.tsx, credit.tsx)
- Task 3: Ollama security (NetworkPolicy, prompt validation, audit)
- Task 4: LiteLLM integration (litellm.rs, migrated AI feature handlers)
- Task 5: Refund architecture (ai_refunds table, endpoints)
- Task 6: Coupons, promotions, referrals (order creation with coupon)
- Task 7: Subscription lifecycle (plan upgrades/downgrades, cron jobs)
- Task 8: Credit expiration enforcement (daily cron task)
- Task 9: Token cost engine (ai_model_cost_config, margin view)
- Task 10: Observability (metrics tables, aggregation function)

Cherry-picked from main branch commit 3c0f45f
2026-07-06 01:49:16 +05:30
Ashwin Kumar Sivakumar
fda72c8698 fix(auth): add logging for role assignment debugging
- Enhanced logging for role assignment to track intent/profession
- Better error handling for role insertion
2026-07-03 17:40:19 +05:30
Ashwin Kumar Sivakumar
eaae3d470f Fix /api/ai/* returning 500 on every request, close credit-minting bugs, add grounding guardrail
Critical: ai_access_middleware was wired via from_fn_with_state((), ...)
- passing the unit type as state - and pulled AppState from request
extensions, which nothing ever populated. Every request through
/api/ai/* and /api/ai/auto/* returned 500 INCOMPLETE_CONTEXT. Fixed by
extracting State<AppState> properly and passing the real state at both
call sites; removed the redundant, identically-broken inner middleware
layer inside ai_router().

Security: ai_addon_purchase (/api/ai/addons/purchase, /api/ai/credits/buy)
and ai_plan_upgrade (/api/ai/plans/upgrade) granted AI credits / plan
upgrades (including enterprise) with zero payment verification - any
authenticated user could mint unlimited free credits, and the frontend
already called this directly. Disabled both until wired to a real
payment flow.

Quality: added a grounding/anti-hallucination system prompt applied to
every AI feature call (orchestrator::call_feature /
call_feature_with_plan, plus the handful of call sites that bypass the
orchestrator). Verified against the live model that it reduces but does
not eliminate fabrication on harder reasoning tasks - even the larger
model invents facts not present in the input on some prompts. This is a
real limitation of the two locally-hosted models, not something a
system prompt alone fully solves; flagged for follow-up (e.g. a
verification pass or deterministic checks for high-stakes decisions
like auto-apply).

Also fixed Persona/Pillar keyword detection using naive substring
matching (e.g. "team" matching inside "esteemed", "lead" matching
inside "leadership") - added a word-boundary-aware contains_word()
helper and applied it to all keyword classifiers in this file.
2026-07-03 04:05:14 +05:30
Ashwin Kumar Sivakumar
64089e4da3 Replace Razorpay payment integration with PayU hosted checkout
The frontend (lib/payu.ts, payu-return.tsx) and admin config UI had
already switched to PayU, but the payments service was still calling
Razorpay's order API and verifying Razorpay HMAC signatures -
payments were broken end to end. Rewrites apps/payments to PayU's
hash-based hosted-checkout flow (SHA-512 request/response hash,
key+salt from admin config or PAYU_MERCHANT_KEY/PAYU_SALT), for both
the tracecoin wallet purchase flow and the AI credits flow. The AI
credits frontend checkout was also fabricating a fake payment_id and
signature client-side instead of ever opening a real PayU checkout -
fixed to use the same real flow as tracecoin purchases.

Also fixes the ai_create_ticket endpoint on the users service, which
never validated the X-AI-Service-Key header despite the client
sending one - anyone could create tickets under an arbitrary user_id.
2026-07-02 18:31:07 +05:30
Tracewebstudio Dev
eb009ac3d0 feat: profile photo upload, PDF resume generation, AI auto-apply, schema fixes
- Profile photo upload: POST /api/profile/photo for all roles, stores via B2 storage
- PDF resume: auto-generated from job seeker portfolio on every profile save (printpdf)
- Company applications: enriched with applicant name, avatar, headline, skills, education
- AI auto-apply cron: rewrote run_auto_apply with correct schema (job_seeker_profiles,
  cover_note, ai_auto_apply_settings, ai_auto_apply_logs, credit deduction)
- Schema fix: job_seeker_profiles table name (was incorrectly 'job_seekers' in two places)
- Migration: add resume_url column to job_seeker_profiles
- Migrations: PayU rename, tracecoin hardening, lead reserve linkage, invoice/wallet crates
- PayU integration: ai_credits, packages, admin payment handlers
- Wallet and invoice crates added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 13:31:06 +02:00
Tracewebstudio Dev
5082427279 Wire admin Razorpay gateway config 2026-06-26 21:07:36 +02:00