26. ConvBI / Ylogx full codebase — how it was built, every module, algorithms, deploy

Adarsh Vishwakarma · SDE I AUTA APJ · Job 10454435 still has no public IE that names a live-round question. Unnamed stays unnamed. R1 (13 Aug 2026), R2 (18 Aug 2026), and R3 are done. OA is not a round. This chapter is leftover-hour / possible Round 4 prep, not a forecast of what they will ask, and it does not invent Round 3 contents. Java is Live Code on Zoom. This intern shipped Python FastAPI plus TypeScript NestJS / React. ConvBI in this workspace is the Ylogx-adjacent product codebase, not a second internship.

Grounded in the December 2025 ConvBI tree: architecture-docs 01–08, backend-docs, frontend-docs, Nest src/, FastAPI convbi-ai/, React src/, GitHub Actions, Dockerfiles. Latex diagrams were translated into spoken English; they are not pasted as TikZ. Other candidates reported related product questions; your loop may differ.

Do not paste secrets from task-definition.json, .env, Tally credentials, JWT values, SMTP passwords, RDS hostnames, or AWS account ARNs. Cookie-auth markdown is migration notes; live files still use Bearer JWT + localStorage. Nest has no Redis client; the in-process cache is a five-minute Map. Resume Redis −35% is a Ylogx cache-aside claim, not a package in this Nest tree. No Kafka, EKS-as-shipped, Datadog, Qdrant, or Spring intern.

A. How the product was built

ConvBI is conversational business intelligence for operators who are not SQL experts and still sit on shared warehouse facts. The product problem is three things at once: custom reports, natural-language analysis, and known KPI tiles — without one organizational tier reading another.

I split the system because the jobs are different. NestJS owns identity, RBAC, report CRUD, dashboards, uploads, and admin. FastAPI owns LangChain SQL generation. Postgres is relational truth with row-level security. React is the SPA. REST/JSON is the contract because every browser feature is an HTTP resource (auth, tables, joins, chat, dashboards, reports), Swagger lives at /api, and the AI sidecar is just another HTTP POST. I did not put Kafka or GraphQL in this intern path.

Frontend

React 19, TypeScript, Vite 6, React Router DOM v7, Axios, Tailwind, Recharts and Chart.js. Package name in this tree is projas-frontend.

Nest API

NestJS 11, Node 18 Alpine in Docker, Sequelize 6 + sequelize-typescript, pg, JWT (jsonwebtoken), bcrypt, Terminus health, AWS S3 SDK, Multer, Nodemailer. Listen port from PORT or 5000.

AI sidecar

FastAPI, LangChain + ChatOpenAI, SQLAlchemy engine, Pydantic output, Gunicorn/Uvicorn on port 80 in Docker. Allow-listed ten public tables.

Data

PostgreSQL with RLS. Sequelize pool max 20, min 0, acquire 30s, idle 10s. App tables vs client fact tables.

Why REST, not a message bus. Browser → Nest is request/response. Dashboard tiles are deterministic GETs with month/year query strings. Report builder is POST join SQL. Chat is POST NL, then POST-generated SELECT on the same request. There is no intern Kafka topic, no EKS control plane, no Datadog agent in this tree.

Keep this split straight. Resume metrics (40% faster reports, 99.9% uptime, SQL RAG +65%, RLS+RBAC 3 tiers, Redis −35% bot DB latency, 30 dashboards +60% ops, sub-210 ms, CloudFront / ECS / Docker / ALB / Route 53) belong to the Ylogx intern. This repo is how ConvBI is implemented. IQVIA is LangGraph + Azure hybrid RAG. Horizon is ROS2. Argus is YOLOv9. GiftedBooks is PDF RAG. One product per spoken answer.

B. Directory map of the three packages

convbi-backend (Nest)

convbi-backend/src/
  main.ts                 bootstrap: CORS, 50mb body, ValidationPipe, FinishTransaction, Swagger /api
  app.module.ts           15 feature modules + JwtMiddleware + RLSMiddleware excludes
  config.module.ts
  auth/                   signup, activate, signin, refresh, profile
  middleware/             jwt.middleware.ts, rls.middleware.ts, finish-transaction.middleware.ts
  queryDB/                tables, joins, raw SELECT guards, chat-query
  dashboards/             9 dashboard types, SQL aggregations
  reports/                save/load JSON configs
  chat/                   conversations; executeWithoutRLS for persistence
  fileUpload/             Tally ZIP → S3 → gateway
  organization/ roleManagement/ policyManagement/ featureManagement/
  userHierarchy/ moduleRegistry/ overview/
  models/                 18 Sequelize model files
  dbModules/sequelize.module.ts   pool max 20
  interceptors/logging.interceptor.ts
  filters/http-exception.filter.ts
  healthCheck/            Terminus pingCheck + /health/simple
  common/applicationTables.ts
Dockerfile                node:18.18.2-alpine3.18, USER node, EXPOSE 5000
docker-compose.yml        service convbi-backend :5000
.github/workflows/        convbi-prod.yml (main), convbi-qa.yml (qa)
.aws/task-definition.json Fargate family convbi-backend (do not paste secrets)

convbi-ai (FastAPI)

convbi-ai/
  main.py                 FastAPI POST /chatbot, GET /health
  extractor.py            SQLQueryAndDetailsExtractor, ChatOpenAI, allow-list
  engine.py               SQLAlchemy create_engine from DB_* env
  config.py               table_descriptions for 10 fact tables
  schema_validator.py     drift detect vs live get_table_info()
  output_parser.py        CustomReActSingleInputOutputParser
  parser_prompt_generator.py
  prompts.py              SQLQueryAndDetails Pydantic + system prompt
  prompt_constants.py
Dockerfile                python:3.12-slim, gunicorn 8 Uvicorn workers, timeout 180, port 80

convbi-frontend (React)

convbi-frontend/src/
  App.tsx                 Router + ChatProvider + FeatureAccessProvider + DashboardFiltersProvider
  modules/auth/           SignIn, SignUp, Activate, Forgot/Reset, authService, apiClient
  modules/dashboard/      predefined 9 types + custom canvas (localStorage)
  modules/chatbot/        ChatbotPage → POST /queryDB/chat-query
  modules/reportBuilder/  canvas, dnd, slicers, save JSON
  modules/upload/         TallyUploadPage
  modules/admin/          roles, policies, users, tables, features, expressions
  contexts/               Chat, FeatureAccess, DashboardFilters
  hooks/useTokenRefresh.ts
  utils/axiosInterceptor.ts, jwtUtils.ts
Dockerfile                node:20-alpine build → nginx:stable-alpine, port 80

Latex architecture-docs/08_data_layer.tex draws a local compose triangle (frontend 5173, backend “3000”, Postgres 5432). Live Nest listens on 5000 (main.ts). Production serving is ECS Fargate, not that compose sketch. Show the conflict; do not pick a fake “the AUTA port.”

C. Request lifecycle with exact file names

Live order from main.ts + app.module.ts (not the slightly rearranged latex boxes):

  1. NestFactory.create(AppModule) in src/main.ts.
  2. Global AllExceptionsFilter (filters/http-exception.filter.ts).
  3. Global LoggingInterceptor (interceptors/logging.interceptor.ts) wraps controller execution.
  4. enableCors: origin CORS_ORIGIN or *, credentials: true.
  5. body-parser JSON + urlencoded, 50mb (report JSON).
  6. Global ValidationPipe: whitelist, forbidNonWhitelisted, transform.
  7. app.use(FinishTransactionMiddleware) — registers res.on('finish') before the handler runs.
  8. AppModule.configure applies JwtMiddleware then RLSMiddleware to * except the excluded list.
  9. Controller → service → Sequelize query on req.dbTransaction when present.
  10. Response goes out; finish callback COMMIT or ROLLBACK.

Conflict, show it. backend-docs chapter 3 draws FinishTransaction as step 4 inside AppModule.configure(). Live code registers it in main.ts with app.use, and AppModule only applies JWT + RLS. The idea is the same: register finish first, open the RLS transaction later, commit after the HTTP response.

Excluded pathMethodWhy
health, healthcheck, health/simpleALLALB / Terminus; no JWT
auth/signupPOSTregistration
auth/signinPOSTlogin returns tokens
auth/resend-otpPOSTactivation OTP
auth/activatePOSTOTP + password
auth/forgot-passwordPOSTreset email
auth/reset-passwordPOSTlogged-in reset
auth/update-passwordPOSTtoken from email
auth/refresh-tokenPOSTrefresh is unauthenticated by design

Swagger Bearer scheme is named JWT-auth. Profile, dashboards, queryDB, chat, reports, admin all require the header.

D. Auth algorithm (tokens, refresh, excluded routes)

Resume-derived Standard CS Live files: auth.service.ts, auth.controller.ts, utils/jwt.util.ts, middleware/jwt.middleware.ts, frontend authService.tsx, axiosInterceptor.ts, useTokenRefresh.ts.

Signup → activate

  1. POST /auth/signup with email. Domain must includes(ORGANISATION_EMAIL) (substring, not a parsed hostname).
  2. Duplicate email → 400. Else 6-digit OTP, signToken({ email }), insert User isActive: false, empty password, role USER.
  3. SMTP HTML with OTP and FRONTEND_HOST:FRONTEND_PORT/activateAccount/{token}.
  4. POST /auth/activate: verify token, match OTP, bcrypt.hashSync with 10 salt rounds, set isActive: true, clear OTP.

Signin → tokens

  1. POST /auth/signin: lookup email lowercased; inactive → 401 “User not verified”; bcrypt.compareSync; invalid → 401 “Invalid credentials”. Same message for missing user so enumeration is not a separate 404.
  2. Access token payload: email, guid, role, isActive, passwordUpdatedAt, client_id, organizationId. Secret JWT_ACCESS_SECRET, expiry JWT_EXPIRATION_TIME (docs default 1h).
  3. Refresh token payload: guid, email. Secret JWT_REFRESH_SECRET, expiry JWT_REFRESH_TOKEN_EXPIRATION_TIME (docs default 7d).
  4. Response body returns both as Bearer <jwt> strings. Frontend setAuthData stores token and refreshToken in localStorage.

JwtMiddleware (live)

  1. Require Authorization header.
  2. Split; must be Bearer + token.
  3. jwt.verify(token, JWT_ACCESS_SECRET).
  4. Set req.user = { userId: guid, role, email, client_id, organizationId }.

Refresh

Frontend initTokenRefresh schedules every VITE_TOKEN_REFRESH_INTERVAL or 15 minutes. Architecture latex also draws a 30s isAuthenticated poll in App.tsx (that interval exists) plus focus-triggered refresh. POST /auth/refresh-token is excluded from JWT middleware; body carries the refresh JWT; service verifies with the refresh secret, reloads the user, signs a new pair.

Cookie markdown vs live file. COOKIE_AUTH_IMPLEMENTATION_COMPLETE.md describes HTTP-only cookies, cookie-parser, POST /auth/logout, and no localStorage. There is no cookie-options.ts in this Nest tree. Live main.ts has no cookie-parser. Live JWT middleware reads only the Bearer header. Speak cookies as a planned/noted migration, not as what this snapshot serves.

E. RLS algorithm (role resolution, SET ROLE, fail-closed, pool leftover)

File: src/middleware/rls.middleware.ts (~509 lines). This is the intern isolation mechanism. Generated SQL and dashboard SQL both ride the same transaction.

On every authenticated request I open a Sequelize transaction and keep it on req.dbTransaction. Then I switch the Postgres session with SET ROLE to the caller’s mapped database role, and I set transaction-scoped set_config('app.*', …, true) so policies can read current_setting. Queries in the controller use that transaction. When the HTTP response finishes, FinishTransaction commits or rolls back. If the user has no db_role_name, I set rls_no_access — fail closed — instead of RESET ROLE, which used to leak.

Resolution by JWT role

JWT roleWhat the middleware doesIf no db role
SUPER_ADMINRESET ROLE; app.is_SUPER_ADMIN=true; app.is_admin=true; empty organizationIdN/A — full access path
ADMINLoad SYSTEM-scoped UserRole→Role; SET ROLE "first db_role_name"; app.is_admin=true; app.admin_hierarchy_filter=trueSET ROLE "rls_no_access" (comment in code: previous RESET ROLE leaked)
USERLoad SYSTEM+ORG roles with RolePolicy→Policy; primary db_role_name; collect policyRole, allowedModules → ModuleRegistry.tables → req.user.allowedTablesrls_no_access + noDataAccess=true

Postgres can only have one active role, so multiple assigned db roles collapse to the first db_role_name. Policies still union modules/tables onto req.user.

Session variables (transaction-local third argument true)

An example policy shape from backend-docs (not a pasted production policy): USING (current_setting('app.organizationId', true) = organization_id::text OR current_setting('app.is_SUPER_ADMIN', true) = 'true').

Fail-closed

Users with zero roles, or roles without db_role_name, get PostgreSQL role rls_no_access (documented as zero table permissions). That is the safety net so “HTTP 200 and empty” beats “HTTP 200 and the other org.”

Pool leftover class

SET ROLE is session-level. set_config(..., true) is local to the transaction. FinishTransaction only commit()/rollback() — it does not RESET ROLE. Chat persistence opens a new transaction and runs RESET ROLE inside executeWithoutRLS. The leftover-role class is: a pooled connection reused with a previous SET ROLE still attached if a path forgets to run queries on the request transaction or skips RESET. I speak that as a class I test against, not a named outage.

Do not say generated SQL ran as table owner or superuser. Dashboard and chat-query execution use req.dbTransaction.

F. QueryDB algorithms

Controller: src/queryDB/queryDB.controller.ts. Service: queryDB.service.ts.

Table listing — GET /queryDB/tables

  1. GUEST → 401.
  2. SUPER_ADMIN: information_schema.tables in public, excluding application/system names (users, roles, policies, flyway_schema_history, …).
  3. ADMIN: getAdminAllowedTables — SQL join user_roles → roles → role_policies → policies, union allowedModules, load ModuleRegistry.tables.
  4. USER: prefer req.user.allowedTables from RLS middleware. Fallback: pg_policies overlap roles && ARRAY[policyRoleNames] without the RLS transaction (restricted role may not see the catalog). If still empty, chatbot feature can expose chat tables only.

Join execute — POST /queryDB/execute-query

  1. hasTableAccess on mainTable and joinTable.
  2. Quote identifiers: SELECT "main"."col" AS "col" … FROM "main".
  3. Join keyword: if joinType already ends with JOIN, use it; else append JOIN. Types in enum: INNER, LEFT, RIGHT, FULL.
  4. Optional date BETWEEN ? AND ?. Optional org filter if the table has organizationId (information_schema check).
  5. LIMIT: default 1000, max 5000.
  6. Run on dbTransaction. If dataType is MONTHLY/YEARLY, processDataForPeriod groups in process (high/low/avg of numeric columns).

Raw SQL guards — POST /queryDB/execute-raw-sql (also used by chat-query)

  1. Trim; must start with select (case-insensitive). No INSERT/UPDATE/DELETE path.
  2. Regex extract FROM/JOIN table names (quoted, schema.table).
  3. hasTableAccess per table.
  4. If the caller has an organizationId, inject WHERE (alias."organizationId" = '…') AND … before GROUP BY / ORDER BY / LIMIT / HAVING / UNION.
  5. Execute on the RLS transaction.

The SELECT-prefix check is a shape guard, not a full SQL parser. A SELECT that hides writes via CTE tricks is a residual class; RLS still applies to the session role. Do not claim a proven SQL firewall.

Chat-query — POST /queryDB/chat-query

  1. Body: { query, options }.
  2. fetch(CHATBOT_API_URL || https://chatbot.projas.in/chatbot) JSON POST.
  3. If eventQuery present, executeRawSelectQuery on the same RLS transaction.
  4. Return data rows plus chart metadata; strip the SQL from the client payload. On SQL error, still return the chatbot message with showChart: false and error.

Dataset fields cache (not Redis)

fieldsCache: Map<string, { etag, data, expiresAt }>, TTL 5 minutes, key fields:${tableName}, SHA-1 etag of JSON. This is the only cache in the Nest service. Package.json has no redis / ioredis.

Slicer filters

buildWhereClauseFromFilters: operators in / equals / greater / less / between / contains / starts_with / ends_with, bound via named replacements, ILIKE for text. Distinct values endpoint supports search.

G. AI sidecar algorithms

FastAPI main.py: CORS allow-all, POST /chatbot constructs SQLQueryAndDetailsExtractor and returns parsed data. GET /health → { status: ok }.

Allow-listed tables

Hardcoded in extractor.py SQLDatabase(include_tables=[...]) and described in config.py:

  1. accounting_transaction
  2. bs (balance sheet)
  3. cashflow_bank
  4. cashflow_others
  5. inventory_stk_masters
  6. inventory_stk_vouchers
  7. outstanding_payable
  8. outstanding_receivable
  9. pl
  10. sales

Chain

  1. Build SQLAlchemy engine from DB_USER/PASS/HOST/PORT/NAME (engine.py).
  2. validate_and_sync_schema: parse get_table_info() CREATE TABLE lines, diff vs table_descriptions; optionally rewrite config.py. On failure, log and continue.
  3. Prompt: system rules in prompts.py (read-only SELECT, no trailing semicolon, ROUND(x::NUMERIC, 2) for Postgres, chart-type rules) + table_info + table_descriptions.
  4. LLM: ChatOpenAI(model="gpt-4.1", temperature=0) in the override (base class comments mention gpt-4o-2024-08-06).
  5. Parse into Pydantic SQLQueryAndDetails: eventQuery, chatMessage, toFormat, showChart, dataPeriod, chartType, relevantColumns, xAxis, yAxis, series, interval, has_explicit_limit.
  6. Post-process: collapse whitespace; if the SQL is a WITH-CTE that does not start with SELECT, wrap SELECT * FROM (cte) q.

output_parser.py is a ReAct Action/Action Input parser used by the older parallel-retry path in BaseExtractor; the live SQL extractor override is prompt | llm | Pydantic parser.

GenAI vs IQVIA. This sidecar is LangChain SQL generation with an allow-list. IQVIA is LangGraph Deep Research + Hybrid RAG (Azure AI Search + GraphDB) + LangSmith. Do not mix. Frontend package.json also lists @google/generative-ai; the live NL→SQL hop in this repo is Nest → FastAPI ChatOpenAI, not Gemini on the Nest path.

H. Dashboard algorithms (9 types, SQL aggregations, filters)

Registry lives in frontend modules/dashboard/App.tsx as PREDEFINED_DASHBOARDS. Backend DashboardsController under /dashboards. Service comment: access control is purely Postgres RLS on req.dbTransaction; empty result, not an app 403, if the role cannot see the table.

IDPagesGETTypical facts
overview1/dashboards/overviewsales, pl, accounting_transaction, outstanding_receivable/payable, cashflow_bank, bs
sales6/dashboards/salesSUM/GROUP BY month, state, customer, salesperson; year-over-year growth CTEs
receivables5/dashboards/receivablesaging buckets, page/pageSize (default 12, max 100)
payables3/dashboards/payablesaging, vendor %, invoices >50% OS
stock2/dashboards/stocksinventory masters/vouchers
collections3/dashboards/collectionsaccounting_transaction + sales velocity
profitLoss1/dashboards/profit-losspl amounts by category
balanceSheet1/dashboards/balance-sheetbs; months/years parsed to int arrays
cashflow2/dashboards/cashflowcashflow_bank / others; waterfall on FE

Filter translation

buildCommonDateFilter(months, years, dateColumn):

Controller accepts singular month/year or plural months/years comma strings; plural wins if both sent. Architecture latex also maps month=0 / year=0 to “all months 01–12” / years 2021–2025 on the client API helper; the Nest filter parser treats missing as all.

Client / org filter

getClientFilter: SUPER_ADMIN → empty; ADMIN or USER with dbRoleNames → empty (RLS will filter); ADMIN without RLS roles → AND "organizationId" = org if the column exists; USER without roles → org AND or AND 1=0 (block). That last clause is fail-closed at SQL level when RLS roles were never attached.

Frontend filter context

Live DashboardFiltersContext is per dashboard page id, persisted as dashboardFiltersState_v2, default years/months empty, currencyFormat default lakhs. Architecture 06 simplified this to one global months/years/currency. Speak the live per-page key.

Custom dashboards

Card layout (chart|text|image, x/y/width/height) is stored in localStorage dashboardState on the client. Predefined dashboards always hit Nest. KPI GETs do not call the LLM — that is how sub-210 ms stays a resume sentence.

Admin-style system counts are a separate module: GET /overview (OverviewController), not /dashboards/overview.

I. Report builder algorithms (joins, canvas, save JSON)

Frontend module modules/reportBuilder/. Phases from architecture-docs 04, matched to live APIs:

  1. Data source. Utilitybar step 1 → GET /queryDB/tables (RLS-visible names only).
  2. Joins and columns. INNER/LEFT/RIGHT/FULL → GET /queryDB/tables/:table/columns-with-types.
  3. Fetch. Single table → GET .../data; with join → POST /queryDB/execute-query with selectedColumns map, joinType, joinCondition, optional dates, limit.
  4. Chart building. react-dnd draggable columns onto ChartDropZone (x/y). ElementRenderer uses Chart.js (Bar/Line/Pie/Doughnut). Pivot bits also import Recharts. Both libraries are in package.json.
  5. Canvas. Canvas.tsx + react-rnd, 15px grid snap, PageManager for multi-page, PowerBICustomizationPanel for titles/axes/colors.
  6. Slicers. fields → distinct values → POST /queryDB/dataset/:table/query → setFilteredData to every element. Reset clears filters and remounts.
  7. Save. POST /reports with name + JSON (pages, elements, canvasSize). ReportsService.createReport stores JSONB, createdBy = userId, soft-delete flag.
  8. Load. GET /reports, GET /reports/:id (UUID guid).
  9. Export. Client-side html2canvas + jsPDF in ExportModal — not a Nest PDF service.

Chatbot charts reuse the same ElementRenderer with isChatbotChart=true. Architecture 05 lists a normalizeChartType() map (stackedcolumn → stackedColumn, donut → hollowPie, unknown → bar).

J. Tally ingest

Files: fileUpload.controller.ts, fileUpload.service.ts, file-validation.util.ts, DTO tally-upload.dto.ts. Route POST /file-upload/tally (JWT + RLS apply — not in the exclude list).

  1. Multer memoryStorage; max 2 files; 200MB each; extension .zip; MIME zip / x-zip-compressed / octet-stream.
  2. Magic-byte check PK (0x50 0x4b …) plus AdmZip parse so a renamed PDF does not pass.
  3. sanitizeFilename then S3 key tally-uploads/{timestamp}-{name} via @aws-sdk/lib-storage Upload (multipart for large buffers). Region default ap-south-1 from env.
  4. Build gateway JSON: client_id, uploaded_by, software_type tally, period_in_years, single_tally, zip_files.current_year / previous_year S3 URIs, credential blocks, inventory flags. Do not recite passwords from DTOs or examples.
  5. POST TALLY_GATEWAY_URL with header x-api-key, 30s timeout.
  6. Response: step1 S3 success, step2 gateway instanceId.

This is ingest, not dashboard SQL. Tally Gateway is an external processor; Nest does not unpack the ledger into Postgres itself in this module.

K. Admin RBAC graph (18 Sequelize models)

backend-docs chapter 2: “18 Sequelize models.” Live src/models/ has 18 files. base.model.ts is an abstract timestamps/soft-delete mixin (createdBy, updatedBy, deletedBy, deletedAt, isDeleted). user-without-base.model.ts is a variant. Mapped tables in the ER:

ModelTableRole in the graph
Userusersemail, password, role enum, organizationId, client_id (hierarchy)
Organizationorganizationstenant boundary; 1:N users, roles, policies, modules
Rolerolesname, db_role_name, scope SYSTEM|ORGANIZATION
UserRoleuser_rolesuserId ↔ roleId
PolicypoliciesallowedModules[], rules JSONB, unique policyRole
RolePolicyrole_policiesroleId ↔ policyId, isActive
ModuleRegistrymodule_registrymodule name, tables[]
Feature / UserFeaturefeatures / user_featuresroute gating
Chat / ChatMessage / ChatFeedbackchats / chat_messages / chat_feedbacksconversation store
FavoriteMessage / FavoriteConversationfavorite_*bookmarks
Feedbackfeedbacksgeneral feedback
ReportsreportsJSONB canvas configs

Resolution chain: User → UserRole → Role.db_role_name (SET ROLE) → RolePolicy → Policy.allowedModules → ModuleRegistry.tables. Policy.policyRole is what pg_policies.roles overlaps in getAllowedTables.

Three JWT tiers plus GUEST: SUPER_ADMIN / ADMIN / USER / GUEST. Hierarchy ops (user-hierarchy) use client_id: SUPER_ADMIN creates ADMINs; ADMIN manages USERs. Feature flags are a second axis: SUPER_ADMIN always true in the React context; everyone else must have userFeatures.some(f.route === route).

Live admin HTTP prefixes (latex often wrote /roles, /policies, /features — live controllers differ):

L. Frontend routing and feature flags

App.tsx wraps the tree: ChatProvider → FeatureAccessProvider → DashboardFiltersProvider.

PathGateComponent
/login /signup /forgot-password /reset-password /activateAccount/:token /forgetPassword/:tokenpublicauth modules
/dashboardtoken + ProtectedRoute /dashboardDashboard App
/chatbotProtectedRoute /chatbotChatbotPage
/reportdesignerProtectedRoute /reportdesignerReportBuilder
/uploadProtectedRoute /uploadUploadPage
/dashboard/admin/*layout auth only (comment: always accessible for admins)overview, roles, policies, users, tables, features, custom-expressions
*—Navigate /login

ProtectedRoute waits for feature loading, then hasFeatureAccess(route) or redirects to /dashboard. Feature fetch: GET /feature-management/user-features/:userId, 30s debounce, 2-minute interval, refreshFeatures custom event after login.

Axios instance timeout 10s, attaches Bearer from localStorage, 401 clears token/guid/role and sends the browser to /login. Chat send uses raw fetch to /queryDB/chat-query with the stored token (already may include the Bearer prefix).

M. Deployment

Backend Dockerfile (backend-docs ch7 = live file)

  1. FROM node:18.18.2-alpine3.18
  2. ENV NODE_ENV=production
  3. apk add curl (health)
  4. COPY package*.json first (layer cache)
  5. global @nestjs/cli, npm install --force
  6. COPY source, npm run build
  7. EXPOSE 5000, USER node, CMD node dist/main

Comment in Dockerfile: env comes from the task definition, not a baked .env.

Compose

docker-compose.yml one service, maps 5000:5000, interpolates POSTGRES_*, JWT_*, SMTP_*, FRONTEND_*, ORGANISATION_EMAIL from the host env file. Local Postgres is not in this compose file.

Frontend image

Multi-stage: node:20-alpine npm ci --force + Vite build → nginx:stable-alpine serves /usr/share/nginx/html, wget health on :80. Docs claim ~30–40MB vs a Node image.

AI image

python:3.12-slim, pip from requirements.txt, HEALTHCHECK curl :80/health, gunicorn main:app --workers 8 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80 --timeout 180.

GitHub Actions vs older CodeBuild diagram

Conflict, show it. backend-docs chapter 1 and 7 still draw “push development → AWS CodeBuild → Docker → backend.projas.in”. Live workflows:

Resume serving path remains CloudFront / ALB / ECS / Docker / Route 53. I do not invent EKS as what I operated.

ECS task (structure only — no secrets)

Pool max 20

sequelize.module.ts pool max 20, min 0, acquire 30000, idle 10000. Docs warn: each authenticated request holds an open transaction until finish, so concurrent HTTP ≈ concurrent connections. Postgres max_connections must exceed tasks × 20. Scale by ECS desired count, not by sharding this intern system.

N. Observability — logging interceptor, Terminus, no Datadog

There is no Datadog/New Relic client in Nest package.json. What exists:

O. Security slice

P. One-request walks

Walk 1 — Sign-in

Browser POST /auth/signin (excluded). AuthService bcrypt-compares, signs access+refresh, returns Bearer strings. React stores them, sets isAuthenticated, fires refreshFeatures. Next GET /dashboards/sales hits JWT → RLS transaction → DashboardsService SQL on that transaction → JSON for Recharts/Chart.js. No LLM.

Walk 2 — “Top customers this year” in chatbot

ChatbotPage persists the user line via POST /chat/:id/messages (ChatService RESET ROLE). Then sendChatMessage POST /queryDB/chat-query. Nest fetches FastAPI /chatbot. Extractor allow-lists sales, LLM returns SELECT + chartType. Nest executeRawSelectQuery as the caller role. ElementRenderer draws the chart. FastAPI never executes the tenant query as table owner; Nest does, under SET ROLE.

Walk 3 — Report with a JOIN

GET tables → pick sales + outstanding_receivable → columns-with-types → POST execute-query with joinCondition. LIMIT 1000. Drag columns, save POST /reports JSON. Export is html2canvas in the browser.

Walk 4 — Tally ZIP

Authenticated multipart to /file-upload/tally. Validate ZIP, upload S3, POST gateway. Dashboard numbers move only after the gateway has written facts; this request does not UPDATE sales itself.

Q. Failure classes

Classes, not invented tickets. Companion: chapter 15.

  1. Legal JOIN, wrong org. App-only WHERE is not enough; SET ROLE + RLS must deny the other tenant’s rows.
  2. LLM on a KPI GET. Breaks sub-210 ms; dashboards must stay deterministic REST.
  3. Cache identity. This Nest snapshot caches dataset fields in a process Map keyed by table name, not by role — a class. Resume Redis −35% is role-scoped cache-aside on the bot path; do not say Nest ioredis exists here.
  4. Pool leftover SET ROLE. Commit without RESET; next borrower on the same connection.
  5. Admin with no SYSTEM db_role_name. Old path RESET ROLE leaked; live path rls_no_access.
  6. Chat persistence vs facts. executeWithoutRLS is required for chat tables; using it for sales would skip RLS — never.
  7. SELECT-prefix only. Raw SQL guard is not a parser.
  8. QA vs prod CI. qa branch auto-deploys; main waits for approval. A tag is not a three-tier fixture.
  9. Health vs simple health. /health dies if Postgres dies; /health/simple can still 200.
  10. Cookie notes vs Bearer live. Speaking HTTP-only cookies as shipped in this snapshot is a mismatch.
  11. CloudFront 403 vs ALB 502 vs origin 5xx vs RLS empty. Different hops.
  12. synchronize: true plus Flyway history table — schema ownership class.

R. Honest 10×

First: more RLS fixtures and deny tests on JOINs. Then pool/RESET discipline and desired ECS count. Then query shape (the 1000/5000 limits, EXTRACT filters). I did not shard Ylogx. I was not the EKS cluster owner. Kafka/Datadog retail HLD is not this intern default. 10× users without policy coverage is a faster leak, not a win.

S. Deep questions with spoken answers

Labels: IE-asked means another candidate’s loop reported a similar probe. Resume-derived is from the Aug 2026 resume plus this repo. Standard CS is CS you should still be able to say. Other candidates; not a Job 10454435 forecast.

Q1. What is ConvBI and how does it relate to Ylogx? Resume-derived

Ylogx intern Nov 2024–Oct 2025. ConvBI is the conversational BI product in this repo — reports, SQL RAG chatbot, KPI dashboards, RLS. GitHub Conv-BI is Ylogx-adjacent, not a second intern. I speak Ylogx metrics on this product, not IQVIA.

They might ask nextYou say
Is Warpflow this intern?No. Intern live story is SQL RAG + RLS + this Nest/FastAPI/React split.

Q2. Why Nest and FastAPI instead of one process? Resume-derived Standard CS

Typed auth/RBAC/CRUD fit Nest modules. LangChain SQL libraries fit Python. Postgres stays one truth. REST is the seam. I did not run Ylogx on the JVM; Java is Live Code.

Q3. Why REST, not GraphQL or Kafka? Standard CS

Every UI action is a resource with Swagger. Dashboards are cacheable GETs. Chat is one POST that already fans out to FastAPI. Kafka would add a bus I did not operate. GraphQL is on the skills line, not this intern contract.

Q4. Walk main.ts. Resume-derived

dotenv, NestFactory, AllExceptionsFilter, LoggingInterceptor, CORS, 50mb body-parser, ValidationPipe, FinishTransactionMiddleware, Swagger at /api, listen PORT or 5000.

Q5. What does AppModule actually register? Resume-derived

Config, Sequelize, Health, Auth, Organization, ModuleRegistry, QueryDB, Policy, Role, UserHierarchy, Overview, Reports, Feature, Chat, Dashboards, FileUpload. Middleware: Jwt then RLS with the exclude list.

Q6. Why is refresh-token excluded? Standard CS

The access token is expired; the refresh JWT is the credential, verified with JWT_REFRESH_SECRET inside AuthService, not JwtMiddleware.

Q7. Exact JWT payload? Resume-derived

Access: email, guid, role, isActive, passwordUpdatedAt, client_id, organizationId. Refresh: guid, email. Middleware copies guid→userId, role, email, client_id, organizationId onto req.user.

Q8. Where are tokens stored in this snapshot? Resume-derived

localStorage keys token and refreshToken. Axios attaches Authorization. Cookie MD is notes; cookie-options.ts is absent.

Q9. How often does the SPA refresh? Resume-derived

authService timer default 15 minutes; App also polls isAuthenticated every 30s; focus calls refresh if needsRefresh(). Deduped with refreshPromise.

Q10. Signup domain check — hostname parse? Resume-derived

email.toLowerCase().includes(ORGANISATION_EMAIL). Substring, not a proper domain parser. I would say that honestly if they push.

Q11. Password algorithm? Standard CS

bcrypt genSaltSync(10) + hashSync / compareSync. argon2 is a dependency I did not use on this path.

Q12. Three-tier RLS in one sentence. Resume-derived

SUPER_ADMIN RESET ROLE; ADMIN SET ROLE first SYSTEM db_role_name; USER SET ROLE first db_role_name and union policy modules; anyone without a db role gets rls_no_access.

Q13. Why first db_role_name only? Standard CS

Postgres one active role per session. Multiple app roles still contribute allowedTables from policies; SET ROLE cannot be a list.

Q14. What did RESET ROLE on empty ADMIN used to do? Resume-derived

Code comment: fallback RESET ROLE caused a data leak. Live code SET ROLE rls_no_access. That is Dive Deep: we fail closed.

Q15. set_config third argument true? Standard CS

is_local true → GUC lives for the transaction. After COMMIT those app.* values drop. SET ROLE does not automatically drop; that is the leftover class.

Q16. Where is the transaction committed? Resume-derived

FinishTransactionMiddleware res.on('finish') commit, catch rollback. Registered in main.ts before handlers so the listener exists even if RLS opened the tx later.

Q17. Pool leftover — what do you test? Standard CS

Two consecutive requests, different roles, same pool. If the second query is not on a fresh SET ROLE transaction, it can see the first role. ChatService RESET ROLE on a new tx is the explicit escape hatch for chat tables.

Q18. Why executeWithoutRLS on chat? Resume-derived

Chat rows are app tables. A fact-table role may have no GRANT on chats. Persistence resets role, still filters by userId/org in the service. Fact SQL never uses that helper.

Q19. How does getTables differ by role? Resume-derived

SUPER_ADMIN: information_schema minus system tables. ADMIN: policy modules. USER: allowedTables from middleware or pg_policies overlap on policyRole names, query run outside the restricted tx.

Q20. Why not query pg_policies inside the RLS tx? Resume-derived

Comment in getAllowedTables: SET ROLE may not see the catalog. Catalog read is a meta query, not a fact read.

Q21. executeQuery join SQL shape? Resume-derived

Quoted identifiers, optional JOIN ON from the client string, date BETWEEN, optional organizationId AND, LIMIT min(requested, 5000) default 1000. hasTableAccess on every table.

Q22. Is joinCondition parameterized? Standard CS

Join ON is interpolated from the DTO. Table/column quoting is on names we also authorize via hasTableAccess. Residual injection class if a caller smuggles SQL in joinCondition. I would add a column-whitelist if I did it again.

Q23. Raw SQL allow-list? Resume-derived

Must start with select. FROM/JOIN names extracted with a regex. Still RLS. CTE wrap happens on the AI side for WITH queries.

Q24. Chat-query if FastAPI is down? Resume-derived

Non-OK fetch → 502 Chatbot API error. FE sendChatMessage catch returns a sorry message with empty data so the thread does not crash.

Q25. Who executes generated SQL? Resume-derived

Nest QueryDBService.executeRawSelectQuery on req.dbTransaction. FastAPI only generates. That is why RLS still binds the caller.

Q26. Allow-list purpose? Resume-derived

SQLDatabase include_tables is ten fact tables so the model cannot see users/passwords. Schema validator warns if config.py drifts from live columns.

Q27. Which model string? Resume-derived

extractor override ChatOpenAI model gpt-4.1 temperature 0. BaseExtractor comments mention gpt-4o-2024-08-06. I speak the override that builds the live chain.

Q28. ROUND trap in the prompt? Resume-derived

Postgres ROUND on float fails; prompt demands ROUND(expr::NUMERIC, 2). That is a production SQL-shape rule, not a metric.

Q29. WITH CTE handling? Resume-derived

If trimmed SQL starts WITH and not SELECT, wrap SELECT * FROM (cte) q so Nest’s starts-with-select guard passes.

Q30. Why temperature 0? Standard CS

SQL generation should be deterministic-ish. Chart type still varies; we parse with Pydantic so a malformed blob retries or errors instead of executing garbage.

Q31. Dashboard vs chatbot path? Resume-derived

Dashboards: handwritten SQL, month/year query string, no model. Chatbot: model proposes SQL, Nest executes under RLS. Known KPIs never wait on generation. Resume sub-210 ms is that path.

Q32. Nine dashboards — list them. Resume-derived

Overview, Sales (6), Receivables (5), Payables (3), Stock (2), Collections (3), Profit & Loss, Balance Sheet, Cashflow (2). Resume 30 KPI dashboards is the product count of tiles/pages, not “I invented 30 Nest controllers.”

Q33. EXTRACT month/year vs BETWEEN? Standard CS

Filters use EXTRACT IN lists. That can skip indexes a BETWEEN range would use. Honest 10×: date-range predicates after measuring. I do not invent a p95.

Q34. What if no month/year selected? Resume-derived

buildCommonDateFilter returns empty AND — all rows the RLS role can see. Frontend v2 defaults to empty arrays so the user must pick; architecture latex mentioned empty stubs without calling API on some pages.

Q35. AND 1=0? Resume-derived

USER without org and without dbRoleNames. Fail closed in SQL.

Q36. Custom dashboard persistence? Resume-derived

localStorage dashboardState. Not Nest. Predefined always hits /dashboards/*.

Q37. Chart.js vs Recharts vs resume Recharts? Resume-derived

This snapshot uses both. Report ElementRenderer is Chart.js; many predefined pages import Recharts. Resume wording is Recharts. I do not pick a fake single library.

Q38. Report save payload? Resume-derived

JSON blob of pages/elements/canvas. Reports table. GUEST cannot create. Load by guid UUID.

Q39. Export PDF on the server? Resume-derived

No. html2canvas + jsPDF in the browser.

Q40. Slicer vs dashboard filters? Resume-derived

Slicers are report-builder dataset filters (IN/BETWEEN/ILIKE) on fetched rows. Dashboard filters are month/year/currency on predefined SQL.

Q41. Tally two-step why S3 first? Resume-derived

ZIPs up to 200MB. Gateway should pull s3:// not a multipart through Nest. Nest validates, stores, then triggers.

Q42. ZIP validation layers? Standard CS

Extension, MIME, magic bytes PK, AdmZip parse, size cap, count cap 2, sanitize filename.

Q43. Is file-upload public? Resume-derived

No. Not in Jwt exclude list. Needs Bearer.

Q44. Policy vs Feature vs Role? Resume-derived

Role maps to Postgres SET ROLE. Policy maps modules/tables and policyRole. Feature maps SPA routes. Three axes. SUPER_ADMIN bypasses features in React.

Q45. client_id vs organizationId? Resume-derived

organizationId is tenant. client_id is the managing admin user for hierarchy. SUPER_ADMIN assigns users to ADMINs via user-hierarchy.

Q46. How many models? Resume-derived

18 Sequelize files; Base is mixin; ~16 tables in the ER. I count files if they open GitHub.

Q47. FeatureAccessProvider for ADMIN? Resume-derived

Only SUPER_ADMIN short-circuits true. ADMIN must have assigned features like USER. Admin layout routes themselves are not wrapped in ProtectedRoute.

Q48. Live admin API prefixes vs latex /roles? Resume-derived

Live: /role-management, /policy, /feature-management. Latex shortened names. I speak live controllers.

Q49. Protected layout without feature? Resume-derived

Token missing → /login. Feature missing → /dashboard. Loading spinner while GET user-features.

Q50. Axios 403 feature event? Resume-derived

Interceptor toasts, sessionStorage featureAccessError, CustomEvent featureAccessDenied. 401 wipes tokens.

Q51. Why USER node in Docker? Standard CS

Least privilege. Image still has a full npm install including CLI; I would slim that in a later pass. Not an invented CVE ticket.

Q52. Why npm install --force? Resume-derived

Dockerfile and frontend ci both use --force. That is a peer-dep override class, not a virtue. I would prefer a lockfile that installs clean.

Q53. Prod vs QA workflow difference? Resume-derived

main: latest tag + human approval + wait-for-stability. qa: qa tag, no approval. Same cluster/service names in the YAML — I do not invent a second cluster.

Q54. CodeBuild still? Resume-derived

Docs still draw CodeBuild on development. Live GH Actions on main/qa. I show the conflict.

Q55. ECS health vs Terminus? Resume-derived

Task health curls :5000/health which pings Postgres. A DB blip can make the task unhealthy and ALB can drain it. /health/simple exists for process liveness without DB.

Q56. Pool 20 math? Standard CS

One open tx per authenticated request until finish. Tasks × 20 ≤ Postgres max_connections minus admin headroom. Scale desired count, watch acquire timeouts 30s.

Q57. synchronize: true in prod? Standard CS

It is in sequelize.module.ts. That can alter schema from the app. Flyway history is excluded from listings. I would not defend it as a best practice.

Q58. Logging — Datadog? Resume-derived

No. Interceptor + CustomLogger + CloudWatch awslogs. Redact password/token/secret/apiKey/authorization.

Q59. Redis −35% vs this repo. Resume-derived

Resume: cache-aside on the bot path, role-scoped keys, −35% bot DB latency. This Nest tree: no Redis client; fields Map 5 min keyed by table. I keep the resume number on the intern product and tell the truth about this snapshot.

Q60. Would you put Redis where? Standard CS

Bot SQL results, key includes role/org/query hash, miss then RLS query then fill. Never cache another role’s rows. Dashboards already skip the LLM; cache is optional after measuring.

Q61. sub-210 ms — which hop? Resume-derived

Dashboard GET, not chat generation, not Tally. CloudFront static + pooled SQL, no model. I do not invent p95 samples.

Q62. 99.9% uptime — how do you know? Resume-derived

Resume outcome. I do not invent an SLO PDF or a missed month. Serving path is ECS behind ALB; unhealthy tasks replaced.

Q63. 40% faster reports — mechanism? Resume-derived

Saved JSON canvases + server-side join execute instead of spreadsheet reconstruction. Not LLM on save.

Q64. +65% analysis productivity? Resume-derived

SQL RAG so non-SQL users query facts. Isolation still RLS. I do not invent survey N.

Q65. 30 dashboards +60% ops? Resume-derived

Predefined financial packs plus custom cards. This repo’s registry shows 9 types / many pages. Resume 30 is the intern product KPI count. I do not flatten them into one number on IQVIA.

Q66. RLS vs RBAC one sentence. Resume-derived

RBAC decides which role you are and which modules/routes you have. RLS is Postgres filtering rows for that role. App-only RBAC loses on a JOIN.

Q67. Conflict you committed? Resume-derived

DB RLS versus app-only WHERE. JOIN counterexample. Fail-closed rls_no_access. Commit after deny tests.

Q68. What did you vs we own? Resume-derived

I name mechanisms I implemented. We own product metrics. Intern, not manager. No invented mentee count.

Q69. Java equivalent of SET ROLE? Standard CS

Same idea: per-request connection, SET LOCAL / SET ROLE, never a global DataSource as superuser for tenant queries. Live Code is Java; intern was TS/Python.

Q70. How would you write fail-closed in Java? Standard CS

If role mapping is empty, refuse the query or use a no-privilege role; do not fall back to the pool’s default owner.

Q71. Chatbot chart normalization? Resume-derived

Architecture table: stackedcolumn→stackedColumn, donut→hollowPie, unknown→bar. Same ElementRenderer as reports.

Q72. toFormat flag? Resume-derived

chatMessage is an f-string template to fill from column values when toFormat is true. Otherwise plain text.

Q73. has_explicit_limit? Resume-derived

True only if the user asked for a limit that appears in SQL. Stops the model from silently LIMITing 5 and calling it the full answer.

Q74. Gunicorn 8 workers timeout 180? Resume-derived

LLM can be slow; 180s worker timeout. Nest axios/fetch for chatbot is not given 180s in QueryDB — a mismatch class if the model is slow. I would align timeouts.

Q75. FastAPI CORS *? Standard CS

Sidecar allow_origins *. Nest should be the only caller; CHATBOT_API_URL is server-side. Still a class if the sidecar is public.

Q76. engine.py password quoting? Standard CS

quote_plus on DB_PASS so special characters do not break the URI. Do not print the URI.

Q77. Schema auto-sync rewriting config.py in prod? Resume-derived

validate_and_sync_schema auto_sync True can rewrite config.py. In a read-only container that fails; extractor logs and continues. I would treat auto-write as a dev tool.

Q78. Overview module vs dashboards/overview? Resume-derived

/overview is system stats for admin. /dashboards/overview is financial KPIs. Different controllers.

Q79. last-updated endpoints? Resume-derived

GET /dashboards/last-updated?dashboard=sales and detailed-update-info. FE LastUpdatedDisplay. Not a CDC bus.

Q80. Sales YoY SQL idea? Resume-derived

CTE groups customer_name by EXTRACT YEAR, then compares target year vs previous. Still on req.dbTransaction.

Q81. Receivables paging? Resume-derived

page default 1, pageSize default 12 max 100. Aging buckets are separate aggregations.

Q82. Currency lakhs? Resume-derived

Frontend display scale, not a DB unit conversion stored in Nest. defaultFilters currencyFormat lakhs.

Q83. ValidationPipe forbidNonWhitelisted? Standard CS

Extra JSON keys 400. DTOs must declare fields. Tally multipart is transformed by hand in the controller because form fields are strings.

Q84. 50mb body? Resume-derived

Report JSON with embedded page/element state. Tally files are multipart memory, not this JSON parser.

Q85. Swagger at /api vs REST root? Resume-derived

Controllers are unprefixed except their @Controller path. Docs UI is /api. Health is /health not /api/health.

Q86. SSL to Postgres? Resume-derived

POSTGRES_SSL true → dialectOptions ssl require, rejectUnauthorized false. That last flag is a class (MITM). I would not boast it.

Q87. application_name convbi_app? Resume-derived

Shows up in pg_stat_activity so you can tell app connections from ad-hoc.

Q88. Soft delete? Resume-derived

Base.isDeleted. Auth delete prefixes email with deleted_timestamp_. Admins cannot delete themselves (docs). Queries filter isDeleted false on roles/policies.

Q89. Guest role? Resume-derived

QueryDB and reports reject GUEST with 401. Enum exists; it is not a dashboard persona.

Q90. ModuleRegistry.tables array? Resume-derived

Postgres ARRAY of table names for a business module. Policies store module GUIDs; middleware expands to table names on req.user.allowedTables.

Q91. Policy.rules JSONB? Resume-derived

Per-table filters column/operator/value. Row filtering in DB still relies on SET ROLE policies; rules are the admin expression builder’s model.

Q92. Bulk feature update implementation? Resume-derived

Controller loops featureIds and calls updateUserFeature with isEnabled true. Comment: bulkUpdateUserFeatures does not exist on the service. Honest: N updates in one request.

Q93. Chat favorites? Resume-derived

FavoriteMessage and FavoriteConversation. Toggle endpoints under /chat. Still executeWithoutRLS for those tables.

Q94. FE chatbot timeout vs Nest? Resume-derived

Axios apiClient timeout 10s; chatbot.ts uses fetch without that timeout. Long SQL-gen can hit one path and not the other.

Q95. Token already has Bearer? Resume-derived

Signin returns Bearer prefix. axiosInterceptor strips then re-adds. chatbot fetch passes token as-is. JwtMiddleware splits on space — double Bearer would fail. I would normalize once.

Q96. CloudFront vs Redis vs Map? Resume-derived

CloudFront caches static JS. Redis (resume) caches bot DB reads. Map caches field metadata 5 min in Nest memory. Three different caches. Do not cache tenant JSON at the edge.

Q97. Route 53 vs GoDaddy? Resume-derived

Registrar vs hosted zone. NS must delegate. Companion chapter 15. This repo’s task def FRONTEND_HOST is an env name only — I do not paste hosts.

Q98. Why Fargate not EKS? Resume-derived

Task definition requiresCompatibilities FARGATE. Kubernetes is listed-not-shipped for this intern. I was not cluster owner.

Q99. Secrets in git? Standard CS

I do not paste them. Task def historically had plaintext JWT/SMTP — that is a class. Password for Postgres is Secrets Manager. I would move remaining secrets out of the JSON.

Q100. Logging interceptor user field? Resume-derived

request.user.email or anonymous. JWT middleware must have run. Excluded auth routes log anonymous. Filter logs request.user.id which is not the field JWT sets (userId) — a small mismatch I can mention if they open the filter.

Q101. Health simple vs Terminus when would you use each? Standard CS

ALB on Terminus if you want to stop sending traffic without a DB. simple for “is node alive” during a DB incident so you can still SSH/exec. Prod task def uses /health.

Q102. How does hasTableAccess work for USER? Resume-derived

Chat tables always true. System tables false. Else getTables and includes. That can recurse into the listing logic.

Q103. processDataForPeriod? Resume-derived

After SQL, group rows by YYYY-MM or YYYY, compute highest/lowest/average per numeric column. In-memory, not a second SQL.

Q104. Dataset fields etag? Standard CS

SHA-1 of JSON fields. Returned in meta. Cache is still process-local; two ECS tasks do not share it.

Q105. Why 5 minutes? Resume-derived

fieldsTtlMs = 5 * 60 * 1000 in source. I do not invent that it is the resume Redis TTL. It is metadata TTL.

Q106. Frontend Vite env? Resume-derived

VITE_API_BASE_URL, optional VITE_QUERYDB_BASE_URL, VITE_TOKEN_REFRESH_INTERVAL. Built into the static bundle at Docker build time.

Q107. nginx in FE image? Resume-derived

Serves SPA; custom nginx.conf. SPA fallback is a typical class (refresh on /chatbot must rewrite to index.html). I would confirm nginx.conf if they open it.

Q108. React 19 + Router 7? Resume-derived

From frontend-docs and package.json. Nested layout with Outlet + Sidebar.

Q109. ChatProvider duties? Resume-derived

chats, currentChatId, messages, load/create/delete, favorites, feedback — architecture 05 API list. Persistence Nest /chat; generation /queryDB/chat-query.

Q110. InstaRecon if they pivot from GitHub? Resume-derived

Security-awareness demo, consent, no production attacks. Then Ylogx isolation and SQL RAG. No phishing steps.

Q111. GiftedBooks vs ConvBI RAG? Resume-derived

GiftedBooks: PDF RAG sub-300 ms, 99.5% uptime. ConvBI: SQL RAG over Tally facts with RLS. Different corpus, different intern/project lane.

Q112. IQVIA LangGraph vs this LangChain? Resume-derived

IQVIA: Deep Research 200+ sites, hybrid Azure AI Search + GraphDB, LangSmith, 200+ page BRDs. ConvBI: one SQL extractor chain, ten tables. Do not say LangGraph on Ylogx.

Q113. Horizon if they hear “production”? Resume-derived

Horizon is ERC rover, GStreamer 60 FPS, ZED 2, costmap −55%. Not ECS. Different intern (Feb–Jun 2024).

Q114. Argus if they hear “cameras”? Resume-derived

YOLOv9 73%→89% mAP, 15k images, 24 FPS, 20+ cameras. Not ConvBI dashboards. No Haar as confirmed first attempt.

Q115. What is not in this intern? Resume-derived

Kafka, EKS-as-operated, Datadog, Qdrant, Spring, Java production, shard. Skills-line Kubernetes ≠ Fargate task I shipped.

Q116. OA-as-R1 trap for this chapter? IE-asked

If an IE numbered OA as Round 1, their “Round 3” may be my R2 analogue. My R1 13 Aug, R2 18 Aug, R3 done. This book is leftover / possible R4. I do not invent R3 questions.

Q117. Fluency slot pastes a tree? IE-asked

Write the tree first (Distance K in chapter 05, LC 7623949 as reported). Then one Fluency sentence if they still ask. Do not force ConvBI.

Q118. Rate limiter? IE-asked

Independent SDE I live-round count 1, OA+3 system design, not UTA two-DSA. Not implemented in ConvBI Nest.

Q119. Login Tracker? IE-asked

Unverified. Mentor prep only. Not this codebase.

Q120. 10× this system in one breath. Standard CS

More deny fixtures, RESET ROLE on pool return, desired tasks, query plans, then maybe a real Redis with role in the key. No shard story. Isolation first.

Q121. Why Sequelize not Prisma? Standard CS

This repo uses sequelize-typescript decorators and raw query with transactions for SET ROLE. I did not migrate ORMs as intern scope.

Q122. Why not execute dashboard SQL as SUPERUSER and filter in app? Resume-derived

A JOIN that is logically correct still returns extra org rows. Postgres policy is the last gate. That is the bar for three tiers.

Q123. Body-parser vs Multer? Standard CS

JSON reports use body-parser 50mb. ZIPs use Multer memoryStorage. Mixing them is how you OOM a task — 2×200MB plus JSON. Desired memory 3072 MB is the task size, not a promise I invent a heap dump for.

Q124. Nodemailer Ethereal in a task def? Resume-derived

SMTP_* env names exist. I do not recite hosts or mailboxes. Signup/forgot-password send HTML templates.

Q125. If they open ConvBI-Bar-Raiser-Interview.html in the repo? Resume-derived

Thin project book in the ConvBI root. This notebook chapter is the codebase-grounded version. Speak from live files, not from that HTML’s interviewer-scoring voice.

T. Keep-straight metric lanes

LaneWhenNumbers you may speakDo not move onto ConvBI
Ylogx / ConvBINov 2024–Oct 2025 intern40% faster reports; 99.9% uptime; SQL RAG +65%; RLS+RBAC 3 tiers; Redis −35% bot DB latency (resume cache-aside; this Nest snapshot has a 5 min Map); 30 dashboards +60% ops; sub-210 ms; CloudFront / ECS / Docker / ALB / Route 53LangGraph, Azure Search, YOLOv9 mAP, ERC 17th, PDF sub-300 ms
IQVIAApr 2026–presentLangGraph Deep Research 200+ websites; Hybrid RAG Azure AI Search + GraphDB; 200+ page BRDs; LangSmithTally ZIP, SET ROLE, 30 dashboards
HorizonFeb–Jun 2024ERC 2024 17th/80+; GStreamer 60 FPS; +40% obstacle detection; ZED 2 2M+ pts/s; costmap −55% collisionNest/ECS
ArgusprojectYOLOv9 73%→89% mAP; 15k images; 24 FPS; −50% violations; 20+ cameras; 2× complianceHaar as confirmed first attempt
GiftedBooksprojectRAG PDF sub-300 ms; 99.5% uptime; +35% reading; +50% engagement; 2.5× comprehension; doubts hours → 3–10 minGitHub currently mismatches AegisAI; resume wins
StratifyLabsproject−30% ML iteration; marketplace 50+ models; WebGL/URDF; Gemini RAG botsConvBI ChatOpenAI path

Education: CUSAT CSE 8.42; IEDC Tech Team; 8 hackathons (CodeRecet 1st, MLH Best Project, Magnathon 2.0 runner-up). No invented missed ERC, missed 99.9%, manager fight, mentee count, AWS bill, Qdrant, p95, cache TTL as a resume number, student headcount.

Companions: 15 Ylogx live path, 14 why-stack, 09 projects, 20 stack defense, Round 4 projects, Answer-BIBLE.md, Question-Research-BIBLE.md, R3-R4-Answer-Bible.md.