Confidential

Morgan Stanley Prep

Private preparation workspace. Enter the password to continue.

Iris Software → Morgan Stanley · Interview Prep

Full-Stack Developer,
Angular & Generative AI

Everything you need for Friday: the frame that wins, two demos to walk, likely questions with answers, deep briefs on your gap topics, plus flashcards and a printable drill sheet.

Client · Morgan Stanley Vendor · Iris (Ajay Singh) Rate · $95/hr C2C Location · NYC hybrid, 3 days
Interview in
01 — The Frame

What the manager actually wants

Read the JD's verbs, not its noun list. They are hiring an AI-leverage engineer who outputs Angular — not an Angular veteran who dabbles in AI. That distinction is your whole advantage. Lead with it.

The three real asks (from Ajay's call)
  • Use AI to code fast against their Java + Python codebases and databases
  • Work in Angular (React experience valued)
  • Teach the team AI-assisted coding best practices
Your positioning in one line

"I build production AI systems and I train engineers to do it safely — I ship with LLMs every day and I measure what I ship."

Strengths vs Gaps — know which is which

Lead with   RAG architecture · evals & measurement · AI-assisted development at scale · teaching/enablement · Python · prompt engineering · full-stack shipping

Drill before Friday   Angular specifics · Java + Spring Boot · OOP fundamentals · microservices patterns · SQL/vector-DB specifics · LangChain vs LlamaIndex vs Semantic Kernel

Demeanor — say nothing about it, just do it

Your early emails to Ajay read a touch prickly (skip-the-screen, recording objection). The manager is engaged now, so it worked — but in the room be collaborative, curious about their stack, low-ego. Ask about their AI-adoption pain. Show the depth; let them conclude you're senior. Do not wave off the OOP fundamentals — answer them cleanly.

02 — Walk These

Three demos that prove range

A system-depth demo proves you can build, a full-stack + security demo proves range, and a meta demo proves you scale it to their team. Together: senior IC and force-multiplier — which is what justifies a contractor at a bank. Have the tabs pre-loaded and logged in before the call. Deep technical Q&A for each is in the next section.

Lead demo · system depth

Ask the Declaration askthedeclaration.com

A deployed RAG system with a measured eval improvement: 93.3% → 97.8%. That number is the point — you don't just wire an LLM, you measure and improve it.

  • Front end: persona pages, reader-lens views, opt-in in-browser (WebGPU) generation
  • Back end: three-signal retrieval pipeline, corpus chunking (108 chunks), cross-document lineage
  • The story: "For an enterprise you can't ship LLM output you haven't measured."
Say this"I'll show you the retrieval architecture and how I ran a measured eval to push faithfulness from 93 to 98 percent — because at a bank, un-measured LLM output is a liability, not a feature."
Third demo · full-stack + a security story banks love

Paris Transit Helper React · serverless · CI scraper · Gemini

A React app that helps tourists with Paris's 2025–26 fare reform. Small, but it touches the whole stack: a Puppeteer scraper in GitHub Actions keeps fares fresh (commits JSON to git → auto-redeploy), and the Gemini assistant sits behind a serverless proxy so the API key never ships to the browser.

  • Full-stack + DevOps: React front end, Netlify function backend, cron-driven CI data pipeline — no server, no DB
  • The security story: you caught that the proxy was an open, unauthenticated endpoint and hardened it (origin check, rate limit, length cap, server-built prompt) — exactly the instinct a bank wants
  • Senior candor: single-turn chat, regex-brittle scraper with a confidence flag that degrades gracefully instead of crashing
Say this"It's small, but every piece does real work — scraping, CI automation, serverless, and an LLM integration. The part I'm proudest of is catching that my own AI proxy was an open endpoint anyone could drain, then locking it down. That's the security reflex you want on someone touching your systems."
Support · back end + evals

PROBE Framework

framework.swapniltamse.com

Python serverless API, 32 automated tests, measures AI behavior against defined principles. Your answer to "how do you validate LLM-generated code for enterprise?" — you have an actual instrument.

Support · the "teach the team" proof

Coaching + Partner Network

You run an AI-coaching practice and an internal Anthropic partner-network training path, and you've shipped 30+ production apps with AI-assisted development. Not a claim — a track record. This is the third ask.

The Angular / React honesty play — rehearse verbatim

"My production front-end work is React and Next.js, so I'll be direct: I am not an Angular veteran. But the job here is using LLMs to generate and validate UI components, and that workflow transfers cleanly — component contracts, prompt scaffolding, validating generated code against tests. I let the model handle boilerplate while I own architecture and review, so I ramp on framework specifics fast. I would rather tell you that honestly than oversell." Candor + the AI-leverage frame turns your one gap into a demo of exactly the skill they want.

03 — Project Deep-Dives

The specific technical questions

This is the section for when they stop being impressed and start drilling. Each project opens with its architecture diagram, then a list of the exact questions you might get — open each one and answer out loud before you read it. Pulled from your own per-project prep notes.

1Ask the Declaration — RAG, embeddings, on-devicediagram + 12 Q

Architecture in one breath: at build time (Node) the corpus is parsed into 108 structure-aware chunks, embedded with all-MiniLM-L6-v2 (384-dim, L2-normalized) into one static JSON. At runtime the browser embeds your question with the same model via Transformers.js and scores it. No servers, no API keys, no database. The Aug upgrade added hybrid retrieval + a reranker with a measured eval.

Architecture — build once, search on-device
 BUILD TIME · Node.js                    RUNTIME · your browser
 ──────────────────────                  ────────────────────────
 founding texts                          your question
      │                                       │
 build-corpus.js                         Transformers.js
   → 108 structure-aware chunks            all-MiniLM-L6-v2
      │                                    (quantized ONNX, web worker)
 build-embeddings.js                          │
   → all-MiniLM-L6-v2, L2-norm           query vector (384-dim)
      │                                       │
 index.json ───────────────────────►    ┌──────────────────────────────┐
   one 451 KB static file               │ dense · BM25 · cross-encoder  │ 3 signals
   no server / no DB / no key           └───────────────┬──────────────┘
                                                        │
                                        top passages + exact citations
                                        + curated answer  (cosine ≥ 0.60)
                                        + optional on-device synthesis (LaMini-77M)
Walk me through the retrieval pipeline end to end.

Build time: parse founding docs into 108 chunks along their own semantic seams → embed each with all-MiniLM-L6-v2 → L2-normalize → ship as a 451 KB JSON. Runtime: the browser loads the same quantized ONNX model, embeds the query, and scores it. The upgraded path runs three signals — dense vector similarity, BM25 keyword, and a cross-encoder reranker — then returns top passages with citations.

Why structure-aware chunking instead of fixed token windows?

Founding documents carry their own boundaries: each grievance is one accusation, each amendment one right, each section one power. Chunking on those seams means every chunk is a complete thought with a citation a human recognizes — "Amendment IV" with full text, not "chunk 47 starting mid-sentence." The transferable rule: find the document's atomic unit first — contracts have clauses, API docs have endpoints, runbooks have steps.

Why L2-normalize the embeddings?

Once every vector is unit length, cosine similarity reduces to a plain dot product — no arccos, no division at query time. Search becomes a single multiply-and-add loop.

How does search actually run, and how fast is it?

108 passages × 384 dimensions = 41,472 multiplications — under a millisecond on any device. A sorted array is the right structure when the corpus fits in memory; no vector database and no approximate-nearest-neighbor index needed. You reach for ANN/HNSW only once the corpus outgrows memory.

What is the "three-signal" retrieval, and why hybrid?

Dense vectors catch meaning, BM25 catches exact terms (names, numbers), and a ms-marco-MiniLM cross-encoder reranks the merged candidates by scoring query-passage pairs directly. Hybrid + rerank beats any single signal on recall — dense alone misses exact-term matches, keyword alone misses paraphrases.

How do you know retrieval got better — did you measure it?

Yes — there's an eval harness (eval/run-eval.js) over a labeled question set. The upgrade moved measured recall from 93.3% to 97.8%, with the multi-hop slice at 100%. I also tested a bigger embedding model (bge-base) and rejected it on the numbers — measured, not assumed. "I measured and rejected an option" is the senior signal.

How do you prevent hallucination?

In the curated path the AI only does retrieval and question-matching — the short answers and 108 passage explainers are hand-written at build time, so nothing generates text from scratch. The optional browser-side synthesis model (LaMini-Flan-T5-77M) is constrained to the retrieved passages as its only input, so it can't introduce facts that aren't there, and its output is labeled "computed."

What's the semantic router / curated-answer layer?

27 curated Q&A pairs embedded alongside the corpus. The query is scored against them; above a 0.60 cosine threshold a human-written modern-English short answer shows above the founders' passages. The threshold is empirical: paraphrases of covered questions score 0.63–0.84, off-topic queries stay under 0.20, so the gap kills false positives.

How does browser-side inference work without freezing the UI?

Transformers.js runs a quantized ONNX build of the model (22.9 MB), cached in the browser's Cache API after the first visit. The key line is env.backends.onnx.wasm.proxy = true, which moves inference into a web worker. Without it, ONNX ran on the main thread and blocked for the whole embedding pass.

Tell me about a performance problem you debugged.

Lighthouse mobile the night before launch. First, render-blocking Google Fonts (fixed with the media="print" / onload swap). That exposed a second issue: Total Blocking Time jumped to 4,500 ms because the blank screen had been hiding ONNX inference on the main thread. Moving inference to a worker dropped TBT under 10 ms. Lesson: optimizing one metric can reveal another — sequence matters.

What's the cost model at scale?

Marginal cost per query is zero, at 10 users or 10 million, because each visitor brings their own compute. The heavy bytes (22.9 MB model, ~11 MB runtime) come from third-party CDNs; the Vercel origin serves ~600 KB per cold visit, and the model caches after first load. Free tier covers ~170,000 cold visits/month.

When would you NOT use this architecture?

Private data (the whole index ships to every visitor), large corpora (the index download outgrows its welcome), or when you need generated prose of real quality (a 77M-param browser model isn't GPT-4). It's for small, public, read-heavy corpora — docs, policy texts, FAQs. Matching the tool to the problem is the actual engineering judgment.

2PROBE — AI evaluation & governancediagram + 10 Q

Architecture in one breath: a six-stage pipeline that turns one AI principle at a time into a score out of 100 with the evidence attached. Every arrow is an independently testable seam. 32 passing tests, a live demo, a serverless API.

Pipeline — principle to control
 Principle ──emits──►  Probe   (carries a rubric)
                         │ prompt
                         ▼
                       Target   ← the LLM under test, behind an interface
                         │ answer
                         ▼
   assess(rubric, ──►   Judge   ← validated FIRST:
     exchange)            │        identical answers must score equal
                          │ score 0–1
                          ▼
                       Metric ──►  Report   (score /100 + evidence bundle)

 one contract for the whole engine:   evaluate(principle, target)
Tell me about a system you designed.

PROBE. Six stages, each a component with one job: a principle emits probes carrying a rubric, the target model answers, a judge scores the exchange against the rubric, a metric aggregates, a report bundles the evidence. Because each stage sits behind an interface, I can test them in isolation.

How do you know your evaluation is correct? You're scoring a model with a model.

Same reason you trust any validated model — you check it against known cases first. The judge has a reliability check: feed it two identical answers and it must score them equal, or none of its other numbers mean anything. That's gated as a real integration test before the judge grades anything.

Tell me about a hard technical decision / a refactor.

v1 measured fairness by how far two answers diverged from each other. That broke for groundedness — one answer checked against given facts, not two answers compared — and for prompt-injection and refusal. The choice was bolt on special cases or find the shape that fits all four. I unified it: every principle emits probes carrying a rubric, and the judge answers one question, assess(rubric, exchange) → 0–1. Four principles became one machine with different rubrics. Lesson: when an abstraction strains, unify it, don't wrap it in conditionals.

How would you extend it to non-chatbot models?

The whole engine is one contract: evaluate(principle, target). The target doesn't have to be a chatbot — a classical-ML evaluator (credit, fraud, pricing) implements the same contract and plugs in without touching the pipeline. Honest caveat: that's a designed seam, not shipped in v1. Keeping that qualifier on every time is what makes the rest credible.

Tell me about shipping it / a production problem.

The Vercel serverless deploy failed twice. I read the actual traceback each time — fixed the package bundling and the requirements location. I also switched an async job model to a synchronous endpoint, because serverless functions don't share memory between requests, so the job state was vanishing.

How is a non-deterministic LLM inside a deterministic test suite?

The target and judge are behind interfaces, so the core suite swaps in fakes — zero network calls, runs in under a second. The one live-judge test is gated behind an API key. That's what lets me trust the numbers: the plumbing is proven deterministically, and only the model call is non-deterministic.

Why not just use an existing eval library?

Existing tools give you a benchmark score. They don't give a governance owner a named principle, a threshold set in advance, and an audit bundle. The framing — policy to control — is the contribution, not the model call.

What does it actually measure today? Give me numbers.

LLM behavior only in v1, deliberately scoped. Four worked principles: gender fairness, groundedness, prompt-injection resistance, refusal-appropriateness. 32 passing tests, 1 gated live-judge integration test, core suite under 1 second with zero network calls, groundedness ships with a 0.85 pass threshold.

Where does this sit next to a governance framework (NIST AI RMF / ISO 42001)?

Those are governance lifecycles — frame, classify, assess, design controls, measure, prove. PROBE isn't a competitor; it's the instrument you plug into the measure step. A framework says you must measure and evidence a control. It doesn't produce the number. PROBE does — the score and the evidence bundle for one principle at a time.

Isn't the credit-model part vaporware?

Fair challenge, and I say it plainly: it's a designed and documented extension point, not shipped code. I built the contract so it can exist, because a measurement framework that could only ever look at chatbots would be measuring the wrong thing in a bank — the high-risk models are credit, fraud, and pricing.

3Paris Transit Helper — full-stack, CI, secured LLMdiagram + 10 Q

Architecture in one breath: three loosely-coupled pieces, no shared DB — a React SPA (four tabs), a Netlify serverless function proxying Google Gemini (keeps the key off the browser), and a Puppeteer scraper in GitHub Actions that refreshes fares daily, commits fares.json to git only on a real diff, and triggers a redeploy.

Architecture — two lanes, no server, no DB
 CI DATA PIPELINE · daily cron           APP · no server, no DB
 ─────────────────────────────          ───────────────────────
 GitHub Actions  06:00 UTC              React SPA (4 tabs)
        │                                    │ imports at build
 Puppeteer scraper                      fares.json ◄── commit (only on diff)
   iledefrance-mobilites.fr                  │
   layered regex + confidence           user → AI Assistant tab
        │                                    │ POST { prompt }
 fares.json ──git diff?──► commit            ▼
        │  (only if changed)            Netlify Function (serverless)
        ▼                                    │ API key stays server-side
 Netlify auto-rebuild ──────────────►        ▼
                                        Google Gemini API
Give me the 90-second version.

Real travel problem: Paris's 2025–26 fare reform split one ticket into separate metro and bus products, so every English tourist guide went out of date at once. I built a four-tab React app — what to buy, card-rejected help, troubleshooting, and a free-form AI assistant. It stays current for free: a Puppeteer scraper runs each morning in GitHub Actions, reads the official Ile-de-France prices, and writes a JSON file that only commits when something changed, which redeploys the site. The Gemini assistant sits behind a serverless function so the key never ships to the browser.

Why scrape into a committed file instead of fetching live?

Fares change rarely, so per-request freshness isn't worth a server or DB. A committed JSON file is free to host, gives me an audit trail in git history, and the daily cron keeps it current enough. The cost is a rebuild per change, which is fine at this cadence.

How do you keep the scraper from breaking when the site changes?

Layered extraction — labeled text first (Full price / Reduced price), then price-class CSS selectors, then a catch-all euro-amount regex. Each page is wrapped in its own try/catch, the workflow uses continue-on-error, and a confidence flag only promotes to "High" when the primary metro price actually parses. It degrades to defaults instead of crashing.

Why put Gemini behind a serverless function?

To keep the API key server-side. Calling Gemini from React would bake the key into the browser bundle. The function is a thin proxy that validates the request and forwards it.

You found a security issue in your own app — walk me through it.

The proxy shipped as an open, unauthenticated endpoint: no origin check, no rate limit, no prompt-size cap, and it forwarded the client-supplied prompt verbatim. Anyone could POST arbitrary prompts and drain the paid Gemini quota. The fix is origin/referer check + rate limit + max-length cap + building the prompt server-side instead of trusting the client body. Catching that in my own code is the instinct you'd want on someone touching bank systems.

Does the assistant remember the conversation?

No — it's single-turn. Chat history is kept in React state for display but isn't sent back; each call sends the system prompt plus the current question. I left multi-turn out for simplicity and cost, and I call that out as a known limitation rather than hiding it.

How is the system prompt applied, and what would you improve?

Right now it's concatenated with the user question client-side into one prompt string. The cleaner version uses Gemini's dedicated system-instruction field and builds the prompt server-side — which also closes the injection gap from trusting the client's text.

What breaks first over time or at scale?

The regex scraper against the French site. If they restructure the fare pages or change wording, extraction returns null, confidence stays Medium, and the app falls back to defaults. It's the most fragile dependency — the fix is structured selectors or an official data export, plus a CI test that fails loudly when the primary price is null instead of silently degrading.

The chatbot and the accurate fare data are disconnected — why?

Honest gap: the static system prompt even tells the model not to give specific numbers, so fare answers come from Gemini's training data, not the scraped fares.json. The highest-leverage fix is injecting the live fares into the prompt — a small RAG-style grounding step that turns two disconnected features into one authoritative product.

What about discoverability / SEO?

It's a client-rendered CRA, so fetching the URL returns basically just the title — no content or Open Graph for crawlers. For a discovery-dependent tourist tool that's the biggest miss; the fix is prerender/SSR (react-snap, or a framework with SSG) plus real meta and OG tags.

04 — Likely Questions

Answers, framed

Click to open. Each has a one-line FRAME (the strategy) and a say-this. Rehearse the frames, not the words.

How would you use AI to generate Angular components against our Java/Python backend?
Frame · workflow, not magic

Talk the pipeline: define the component contract and the API shape first → feed the backend's OpenAPI/schema as context → generate → validate against tests and types → human review. The senior move: RAG over their own codebase so generated components match house patterns instead of generic scaffolding.

Say this"I'd never let a model free-hand a component. I give it the contract — the API response shape from your OpenAPI spec, your design-system tokens, an example of an existing component — then generate, run it against unit tests and the type-checker, and review. The trick at enterprise scale is grounding generation in your codebase so it writes code that looks like yours, not like a tutorial."
How do you validate LLM-generated code for an enterprise / regulated environment?
Frame · gates, not vibes

Tests + type-checking + linting + security scanning + human review gate. Reference PROBE: define the behavior, measure it continuously. "Never merge generated code you haven't measured."

Say this"Same discipline as any code: it goes through the same CI gates — tests, static analysis, security scan, peer review. AI doesn't get a fast-lane. For AI-specific behavior I add evals — the way I built PROBE, you define the principle you care about and score against it before shipping."
How would you get our team adopting AI-assisted coding?
Frame · real use case, session one

Your coaching methodology: start with one real task on their repo in the first session, establish guardrails, build a repeatable workflow. Not "here's a tool," but "here's your Tuesday, faster and safer."

Say this"I don't run abstract trainings. Session one, we take a real ticket from your backlog and do it together with the tooling, so people see it work on their own code. Then we codify the guardrails — what AI can touch, what needs review — so adoption is safe, not cowboy. I do exactly this in my coaching practice."
Explain the difference between Angular and React. Which do you prefer?
Frame · framework vs library, honest lean

Angular = opinionated framework (TypeScript-first, built-in DI, RxJS, modules/standalone components, CLI, router, forms all included). React = library (JSX, hooks, one-way data flow, you assemble the ecosystem). Angular's structure is an asset in a large bank codebase — consistency across teams.

Say this"React is where my production hours are, but I actually like that Angular is opinionated — in a big org, batteries-included means every team's code looks the same, DI and RxJS are standard, and onboarding is faster. For an enterprise front end that's a feature, not a constraint."
Walk us through a full-stack system you designed end to end.
Frame · Ask the Declaration, front + back + the number

Front end (persona/reader-lens UI) → API (three-signal retrieval) → corpus (chunking, lineage) → the eval loop (93→98%). Emphasize the seams: retrieval, generation, and measurement as separable, testable stages.

Design a REST API for [X]. What are your conventions?
Frame · resources, verbs, status codes, idempotency

Nouns for resources, HTTP verbs for actions, correct status codes, statelessness, versioning (/v1), pagination, and idempotency (PUT/DELETE idempotent, POST not). Mention auth (JWT/OAuth2) and validation at the boundary. See the REST brief below.

We have Java and Python codebases. How do you decide which to use / how do they coexist?
Frame · right tool, clean seams

Java/Spring Boot for the transactional, strongly-typed core services; Python/FastAPI for the AI/ML and data layers where the ecosystem lives (LangChain, LlamaIndex, model SDKs). They talk over REST/gRPC or a queue. Don't force one language across a seam it doesn't fit.

Say this"I'd keep the AI services in Python where the ecosystem is — LangChain, the model SDKs, eval tooling — and let the Java core stay Java. They meet at a REST or gRPC boundary with a clear contract. The mistake is dragging Python into the transactional core or reimplementing the AI stack in Java just for uniformity."
What are the risks of AI-generated code, and how do you mitigate them?
Frame · you're the adult in the room

Risks: subtle bugs, hallucinated APIs, license/IP leakage, security holes, over-trust. Mitigations: review gates, tests, security scanning, no secrets in prompts, RAG over vetted internal code, and teaching people when not to trust it. This answer signals maturity — banks love it.

05 — Deep Briefs

Your gap topics, cold

Collapsible so you can drill one at a time. These are the areas to over-prepare because your daily work doesn't cover them. Skim strengths; study these.

AOOP Fundamentals (Java-flavored)~5 min

Ajay flagged an OOP screen. This is the most likely "gotcha" round because it's easy to nail and easy to fumble if you're rusty.

The four pillars

PillarOne-liner
EncapsulationBundle data + behavior; hide internal state behind private fields + getters/setters. Protects invariants.
AbstractionExpose what, hide how. Interfaces / abstract classes define a contract; callers don't see internals.
Inheritance"is-a" reuse via extends. Java: single class inheritance, multiple interface inheritance.
PolymorphismSame call, different behavior. Compile-time = overloading; runtime = overriding via dynamic dispatch.

Abstract class vs interface (Java 8+) — a classic

Abstract classInterface
Can hold state (instance fields), constructorsNo instance state; only constants
Single inheritance onlyA class can implement many
Use for a shared base with common state/logicUse for a capability/contract
Methods: concrete + abstractdefault/static (Java 8), private (Java 9); otherwise abstract

Rule of thumb: "is-a with shared state" → abstract class. "can-do capability, mixable" → interface. Modern Java leans on interfaces + composition.

SOLID (name + one line each)

#PrincipleMeaning
SSingle ResponsibilityA class has one reason to change.
OOpen/ClosedOpen to extension, closed to modification.
LLiskov SubstitutionSubtypes must be usable wherever the base is.
IInterface SegregationMany small interfaces beat one fat one.
DDependency InversionDepend on abstractions, not concretions.

Fast hits they may ask

Overloading vs overriding: overloading = same name, different params, resolved at compile time; overriding = subclass redefines a superclass method, resolved at runtime. Composition over inheritance: prefer "has-a" — more flexible, avoids fragile hierarchies. equals()/hashCode(): if you override one, override both; equal objects must have equal hash codes. Access modifiers: privatedefault (package) → protectedpublic. Checked vs unchecked exceptions: checked = compiler-enforced (IOException); unchecked = runtime (NullPointerException).

BJava & the JVM~5 min

Platform basics

JDK (dev kit: compiler + tools) ⊃ JRE (runtime libs) ⊃ JVM (executes bytecode). Java compiles to platform-independent bytecode; the JVM JITs it to native. Managed memory with garbage collection.

Collections you must know

TypeUse / note
ArrayListDynamic array; fast random access, slow mid-insert.
LinkedListDoubly-linked; fast insert/remove, slow index access.
HashMapO(1) average key→value; no order.
TreeMapSorted keys (red-black tree); O(log n).
HashSetUnique elements, backed by HashMap.

Modern Java (8 → 17/21)

Streams + lambdas: declarative data pipelines — filter, map, collect. Optional: null-safety wrapper. Generics: type-safe containers. Records (16): immutable data carriers. var (10): local type inference. Sealed classes, switch expressions, virtual threads (21) if you want to sound current.

Concurrency (likely a probe)

synchronized for mutual exclusion; volatile for visibility (not atomicity); ExecutorService for thread pools; CompletableFuture for async composition; AtomicInteger for lock-free counters. HashMap is not thread-safe — use ConcurrentHashMap.

CSpring Boot~4 min

The core idea

Inversion of Control: the framework creates and wires your objects (beans) via Dependency Injection. You declare dependencies; Spring supplies them. Prefer constructor injection (testable, immutable, no null surprises).

Stereotype annotations

AnnotationLayer
@RestControllerWeb/API layer; returns JSON.
@ServiceBusiness logic.
@RepositoryData access; translates DB exceptions.
@ComponentGeneric Spring-managed bean.
@Configuration + @BeanManual bean definitions.

REST mapping

@RestController
@RequestMapping("/api/v1/claims")
class ClaimController {
  @GetMapping("/{id}")
  Claim get(@PathVariable Long id) { ... }

  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  Claim create(@RequestBody @Valid ClaimDto dto) { ... }
}

Also know: @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan. Spring Data JPA repositories give you CRUD for free. @ControllerAdvice + @ExceptionHandler for global error handling. Default bean scope is singleton. Actuator for health/metrics.

DAngular 12+~6 min · study hardest

Building blocks

Component = class + template + styles, declared with @Component. Module (@NgModule) groups components/services — though modern Angular (14+) favors standalone components. Service = injectable singleton for logic/data, marked @Injectable.

Data binding — the four types

SyntaxDirection
{{ value }}Interpolation — component → view
[prop]Property binding — component → view
(event)Event binding — view → component
[(ngModel)]Two-way ("banana in a box")

Directives

Structural (change DOM): *ngIf, *ngFor, *ngSwitch (new control flow @if/@for in v17+). Attribute (change appearance/behavior): ngClass, ngStyle.

Component communication

@Input() passes data parent → child; @Output() + EventEmitter sends events child → parent. Shared service for unrelated components.

Lifecycle hooks (name the big ones)

ngOnInit (init, fetch data), ngOnChanges (input changes), ngAfterViewInit (view ready), ngOnDestroy (cleanup — unsubscribe here).

RxJS — the part people fear

Angular is Observable-first. HttpClient returns Observables. Use the async pipe in templates to auto-subscribe/unsubscribe. Key operators: map, filter, switchMap (cancel previous — great for type-ahead), debounceTime, catchError. Always unsubscribe (or use the async pipe / takeUntilDestroyed) to avoid leaks.

Forms, routing, change detection, signals

Reactive forms (FormGroup/FormControl, typed, testable) vs template-driven (ngModel, simple). Routing: RouterModule, <router-outlet>, routerLink. Change detection: default checks the whole tree; OnPush only re-renders on input reference change or events — a key perf lever. Signals (v16+) are Angular's new fine-grained reactivity.

CLI

ng new, ng generate component x, ng serve, ng build. This is exactly the boilerplate you'd have an LLM scaffold and then refine.

EMicroservices & System Design~4 min

vs monolith

Independent deploy/scale, tech heterogeneity, fault isolation — at the cost of network complexity, distributed data, and ops overhead. "Start monolith, split when a seam hurts" is a mature answer.

The pieces

ConcernTool / pattern
Entry pointAPI Gateway (routing, auth, rate-limit)
Find servicesService discovery (Eureka, Consul, k8s DNS)
Sync callsREST / gRPC
Async / decoupleMessage queue (Kafka, RabbitMQ)
DataDatabase-per-service
Distributed txnSaga pattern (choreography or orchestration)
Failure isolationCircuit breaker (Resilience4j)
Package / runDocker + Kubernetes

Sync vs async: REST for request/response; events for decoupling and resilience. Idempotency matters for retries. 12-factor app principles signal ops maturity.

FREST APIs & SQL~4 min

REST essentials

MethodIdempotent?Use
GETYesRead
POSTNoCreate
PUTYesReplace
PATCHNoPartial update
DELETEYesRemove

Status codes: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 429 Too Many Requests, 500 Server Error, 502/503 upstream. Principles: stateless, resource nouns, versioned, paginated, HATEOAS (bonus). Auth: JWT (stateless bearer token), OAuth2 (delegated).

SQL you'll be quizzed on

Joins: INNER (match both), LEFT (all left + matches), RIGHT, FULL. Indexes speed reads, slow writes — index what you filter/join on. ACID: Atomicity, Consistency, Isolation, Durability. Isolation levels: Read Uncommitted → Read Committed → Repeatable Read → Serializable. SQL vs NoSQL: relational/ACID/structured vs flexible-schema/horizontal-scale. Redis: in-memory cache + pub/sub; Mongo: document store.

N+1 — the interview favorite

Fetching a list then querying per-row is the N+1 problem. Fix with a join / JOIN FETCH / batch load. Name it and you sound experienced.

GRAG, Embeddings & Vector DBs~4 min · your strength, sharpen specifics

The pipeline

Ingest → chunkembed (text→vector) → store in vector DB → retrieve (nearest neighbors to query embedding) → optional rerank → stuff into prompt → generate. You've built this; just be crisp on the vocabulary.

Similarity + search

Cosine similarity (angle, most common), dot product, Euclidean. ANN (approximate nearest neighbor) via HNSW or IVF makes it fast at scale. Hybrid search = dense vectors + sparse/BM25 keyword — best recall.

Vector DB landscape

OptionCharacter
PineconeManaged, serverless, production-easy.
ChromaDBOSS, local/dev-friendly, embedded.
WeaviateOSS, hybrid search, GraphQL.
pgvectorPostgres extension — "stay in your DB."
Azure AI SearchEnterprise/MS-stack fit (relevant here).

Eval metrics: faithfulness (grounded in context?), answer relevance, context precision/recall. This is your differentiator — most candidates can't name these.

HLangChain vs LlamaIndex vs Semantic Kernel~3 min
FrameworkBest atNote
LangChainOrchestration: chains, agents, tools, memoryPython/JS; LCEL for composition; LangGraph for stateful multi-agent
LlamaIndexData/RAG: indexing + query engines over your dataRetrieval-optimized; strong node parsers/retrievers
Semantic KernelEnterprise SDK: plugins, planners, connectorsMicrosoft; C#/Python/Java — fits an MS/Azure shop

One-liner to say: "LangChain for orchestration, LlamaIndex when retrieval is the hard part, Semantic Kernel if the shop is .NET/Azure and wants first-class Microsoft support. They overlap; I pick by where the team already lives." Given Morgan Stanley's Microsoft/Azure footprint, Semantic Kernel + Azure AI Search is a smart thing to name-drop.

IAI-Assisted Coding — Best Practices (your home turf)~3 min

This is the "teach the team" round — you should sound like the most thoughtful person they've talked to.

The generation workflow

Contract first (types, API shape) → ground the model (house patterns, examples, RAG over the repo) → generate → validate (tests, types, lint, security) → review → refactor. The human owns architecture; the model owns boilerplate.

Guardrails to name

  • No secrets/PII in prompts — critical at a bank
  • AI code goes through the same CI gates, no fast-lane
  • Tests are the contract that catches hallucinated APIs
  • RAG over vetted internal code beats free-hand generation
  • Teach when not to trust it — the meta-skill

Tool literacy

Be fluent that Copilot (inline), Cursor (IDE-native agent), and Claude Code (terminal agent) are different postures. You can speak to trade-offs from real use — most candidates parrot one tool.

06 — Active Recall

Flashcards

Click the card to flip. Mark Got it or Review — the deck remembers, so you can re-run only what you missed. Filter to a single topic to drill your weak spot. Keys: ←/→ navigate, space flips, K got-it, J review.

Question
click to reveal answer
click to flip back
1 / 0
07 — Rapid Fire

Drill sheet

Cover the right column, answer out loud, uncover. Printable — hit print for a paper version to run in the cab. These are the exact facts an OOP/fundamentals screen fishes for.

1 OOP & Java

2 Spring Boot & REST

3 Angular

4 Microservices & SQL

5 RAG, Vectors & GenAI

08 — Land It

Close strong

Questions to ask them
  • "What does the AI-adoption curve look like on the team today — who's already using it, and where's the friction?"
  • "Is the Angular work greenfield or modernizing an existing app?"
  • "When you say generate UI with LLMs — is that a dev-productivity play, or shipping AI features to users?"
  • "What does 'good' look like for this role in 90 days?"
  • "How do you currently gate AI-generated code before merge?"
Logistics checklist
  • Both demo tabs pre-loaded & logged in before 3:00
  • Resume open in a tab; know your own bullets cold
  • Confirm interviewer names with Ajay — send them to me for background
  • Quiet room, wired connection, camera on, notes off-screen
  • If offer talk starts: it's $95/hr C2C via Iris — don't renegotiate live, say "works, let's confirm through Ajay"
The one sentence to leave them with

"You're not just getting someone who codes with AI — you're getting someone who can make your whole team faster and safer at it, and who measures what ships. That's the multiplier."