📖 Glossary
Gemini Code Assist
Google's AI coding assistant integrated in IDEs and Cloud Workbench, providing completions, chat, and autonomous Agent Mode.
Code Completion
AI prediction of the next code tokens as you type, shown as ghost text before you accept the suggestion.
Inline Suggestion
Ghost-text code proposals shown in the editor — press Tab to accept, Escape to dismiss.
Smart Actions
Context-menu AI operations available by right-clicking code: explain, fix, generate tests, add docs, and more.
Chat Panel
Conversational AI interface inside the IDE for Q&A, code generation, and multi-turn context-aware assistance.
Agent Mode
Autonomous multi-step mode where Gemini reads your codebase, proposes a plan, and executes file changes with your approval.
Medallion Architecture
Bronze → Silver → Gold data pipeline pattern: raw ingestion, cleaned/validated, and business-ready aggregated data tiers.
PySpark
Python API for Apache Spark, used for distributed data processing across large datasets in Dataproc clusters.
BigQuery
Google's serverless, highly scalable cloud data warehouse — query petabytes of data using standard SQL.
Dataproc
Google Cloud managed Spark/Hadoop service that provisions clusters, runs jobs, and auto-scales without manual setup.
Cloud Composer
Google's managed Apache Airflow service for orchestrating data workflows using Python DAG definitions.
DAG (Directed Acyclic Graph)
Airflow workflow definition that specifies tasks and their dependencies — no cycles allowed, tasks run in dependency order.
Data Lineage
Tracking the flow and transformation of data from its source through each processing stage to its final destination.
Schema Validation
Automated checks that incoming data matches expected field names, types, and constraints before processing continues.
OpenSpec
AI-agent specification system that defines field-level contracts between teams, consumed by Gemini and Claude as structured context.
CI/CD
Continuous Integration / Continuous Delivery — automated pipeline that builds, tests, and deploys code on every commit.
, '')))\",\n nameCol);\n }\n}" }, {"type":"code","title":"test/NameNormalizerServiceTest.java — Unit Tests for §9-503 Logic","lang":"java","label":"src/test/java/com/ucc/api/NameNormalizerServiceTest.java","content":"// src/test/java/com/ucc/api/NameNormalizerServiceTest.java\n// Unit tests for the §9-503 name normalizer — run with: mvn test\npackage com.ucc.api;\n\nimport com.ucc.api.service.NameNormalizerService;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvSource;\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass NameNormalizerServiceTest {\n\n private final NameNormalizerService normalizer =\n new NameNormalizerService();\n\n @ParameterizedTest\n @CsvSource({\n \"'Acme Transport LLC', 'ACME TRANSPORT'\",\n \"'SMITH-JONES INC.', 'SMITH JONES'\",\n \"'Pacific Co.', 'PACIFIC'\",\n \"'First National Corp', 'FIRST NATIONAL'\",\n \"'Bay Area Ltd.', 'BAY AREA'\",\n \"'Lone Star LP', 'LONE STAR'\",\n \"'Delta Holdings, L.L.C.', 'DELTA HOLDINGS'\",\n \"'acme transport llc', 'ACME TRANSPORT'\"\n })\n void normalizesDebtorNames(String input, String expected) {\n assertEquals(expected, normalizer.normalizeDebtorName(input));\n }\n\n @Test\n void handlesNullInput() {\n assertEquals(\"\", normalizer.normalizeDebtorName(null));\n }\n\n @Test\n void handlesEmptyInput() {\n assertEquals(\"\", normalizer.normalizeDebtorName(\"\"));\n }\n\n @Test\n void handlesWhitespaceOnly() {\n assertEquals(\"\", normalizer.normalizeDebtorName(\" \"));\n }\n\n @Test\n void preservesNonSuffixWords() {\n // 'Incorporate' is NOT a legal suffix — should not be stripped\n String result = normalizer.normalizeDebtorName(\n \"Incorporate Solutions Group\");\n assertTrue(result.contains(\"INCORPORATE\"));\n }\n}","desc":"

👤 Developer: Create this test file at src/test/java/com/ucc/api/NameNormalizerServiceTest.java. Run mvn test — all tests should pass. If any fail, fix your NameNormalizerService first.

🤖 AI Tool: Ask Gemini: 'Generate additional edge-case tests for NameNormalizerService — include Unicode names, names with numbers, and double-spaced names.'

"}, { "type": "explain", "title": "Code Review with Gemini — 3 Ways", "content": "Code Review with Gemini — 3 Ways\n

Gemini can review your code at three different points in your workflow. Each catches different types of issues.

\n
\n
\n
WHERE TO USE EACH
\n
\n
\n
1. IDE Chat — Inline Review
\n
Select code → chat panel → \"Review this for bugs\". Instant feedback while you code.
\n
\n
\n
2. Gemini CLI — Batch Review
\n
gemini -f file.java \"review\". Best for reviewing entire files or running in CI.
\n
\n
\n
3. GitHub PR Review
\n
Automatic review on every PR. Covers the full diff with severity ratings. (Phase 5)
\n
\n
\n
\n
\n
LIVE EXAMPLE — REVIEWING NameNormalizerService.java
\n
\n
Gemini Code Assist
\n
\n
YOU Review service/NameNormalizerService.java for correctness, edge cases, and §9-503 compliance. Are there any name patterns it would incorrectly normalize?
\n
GEMINI\nCode Review: service/NameNormalizerService.java

\n✅ Strengths
\n• Correctly uppercases and strips whitespace before comparison
• Removes common entity suffixes (LLC, INC, CORP, LP, LTD)
• Uses word-boundary regex to avoid partial matches


\n⚠️ Issues Found (2)
\n1. Missing suffix: CO. (with period) — \"Acme Co.\" normalizes to \"ACME CO\", not \"ACME\". §9-503 treats these as the same entity.
2. Hyphenated names: \"Smith-Jones LLC\"\"SMITH-JONES\" — but some states file as \"SMITH JONES\". Consider stripping hyphens.

\n💡 Suggested fix:
\nsuffixes = [r'LLC.?', r'INC.?', r'CORP.?', r'LP', r'LTD.?', r'CO.?']\n
\n
\n
\n
\n
\n\n
Why code review matters before Agent Mode: In Phase 3, Agent Mode will use NameNormalizerService.java as a dependency when building FilingSearchService.java. A bug in the normalizer cascades into incorrect search results — catching it here saves debugging time later.
" }, { "type": "prompt", "title": "Code Review Prompts", "content": "# Inline Review (IDE Chat — select code first)\n\n\"Review this function for correctness, edge cases, and performance.\nFlag any issues that would cause incorrect §9-503 name matching.\"\n\n\"Does this Java Record model cover all the fields in the UCC-1 filing form?\nWhat required fields am I missing?\"\n\n\"Review this for security: are there any injection risks,\nunvalidated inputs, or PII fields that should be masked in logs?\"\n\n\"Explain what this code does, then list every assumption it makes.\nWhich assumptions could break in production?\"\n\n# Batch Review (Gemini CLI)\n\ngemini -f service/NameNormalizerService.java
\"Review for §9-503 correctness. List every debtor name pattern\n that would normalize incorrectly. Provide a fix for each.\"\n\ngemini -f service/FilingSearchService.java -f dto/Filing.java
\"Review the search logic. Does it correctly handle:\n - Case-insensitive matching?\n - Names with punctuation (commas, periods, hyphens)?\n - State code validation?\"\n\n# Pre-commit Review\n\ngemini -f $(git diff --name-only HEAD)
\"Review these changed files. Focus on: breaking changes to the API contract,\n missing test coverage, and any regressions vs the existing mock data tests.\"\n\n# Security-focused Review\n\n\"Act as a security engineer. Review this Spring Boot endpoint for:\n OWASP Top 10 vulnerabilities, missing input validation,\n unhandled exceptions that leak stack traces, and auth bypass risks.\"", "desc": "

👤 Developer: Run this prompt with your code file open in the editor. Review the AI feedback critically — accept suggestions that improve clarity or safety, reject stylistic changes that break team conventions.

🤖 AI Tool: Performs a structured code review covering security, correctness, performance, and spec compliance. It does not have access to your git history, so provide PR context in the prompt.

" }, { "type": "prompt", "title": "UCC Domain Chat Prompts", "label": "IDE Chat Panel — Paste and adapt these prompts", "content": "# Explain Code Prompts\n\"Explain this Spring service method in terms of §9-503 rules.\n What edge cases could cause a debtor name to be seriously misleading?\"\n\n\"Walk me through this FilingSearchService method step by step.\n What's the runtime complexity and how would it scale to 1M filings?\"\n\n# Generate Tests Prompts\n\"Generate JUnit 5 tests for the UCCNameNormalizer class.\n Include cases for: LLC variants, trade names vs legal names,\n names with special characters, empty strings, and Unicode debtor names.\"\n\n\"Write JUnit 5 tests for the LienRiskScoreService.\n Use filing fixtures with: blanket liens, expired filings,\n cross-state debtors, and entities with zero active liens.\"\n\n# Refactor Prompts\n\"Refactor this nested if-else chain into a clean stream pipeline.\n Preserve all §9-503 business rules and use proper Java types.\"\n\n\"This batch processing endpoint takes 45 seconds for 1000 entities. Identify\n performance bottlenecks and suggest specific optimizations\n (parallel streams, caching, async processing).\"\n\n# Architecture / Design Prompts\n\"Design a JPA entity model for storing UCC-1 and UCC-3 filings\n that supports: entity search by normalized name, lien lifecycle\n tracking, and efficient lien risk score computation.\n Include indexing and query optimization recommendations.\"\n\n\"What's the best approach for implementing fuzzy entity matching\n across 847K UCC filings in a Spring Boot API? Compare Levenshtein\n distance, soundex, and trigram similarity for §9-503 compliance.\"", "desc": "

👤 Developer: These prompts teach Gemini the UCC domain so its answers become domain-specific. Run them once at the start of each coding session. After running them, ask domain questions like \"What is a debtor search key?\" — Gemini should answer in UCC terms, not generic terms.

🤖 AI Tool: Use these prompts as direct input. Each is structured to produce a specific output format — modify the UCC-specific values but preserve the structural pattern.

" }, { "type": "explain", "title": "Gemini Code Assist 2026 — New Capabilities", "content": "\n
\n
\n 🎯\n
Next Edit Predictions
\n
AI suggests code edits throughout the file — not just at your cursor. Predicts where you'll need to change next based on your current edit pattern.
\n Preview · VS Code + IntelliJ\n
\n
\n 🔀\n
Inline Diff
\n
Chat-generated code suggestions are highlighted directly in your editor with visual diffs — accept, reject, or edit hunks individually without leaving the file.
\n GA · VS Code + IntelliJ\n
\n
\n 🧠\n
Persistent GitHub Memory
\n
Gemini Code Assist on GitHub remembers previous PR interactions — context from past reviews carries forward into future pull requests automatically.
\n GitHub\n
\n
\n 📄\n
Outline Auto-Docs
\n
Automatically generates English summaries of code blocks in the Outline tab — instant lightweight documentation without writing a single docstring.
\n IDE Plugin\n
\n
\n \n
Batched Tool Approvals
\n
Agent Mode now supports approving multiple tool calls at once — review a batch of file writes, shell commands, and API calls in one click.
\n Agent Mode\n
\n
\n 🖥️\n
Real-time Shell Output
\n
Agent Mode streams live terminal output — watch tests run, builds compile, and scripts execute in real-time inside the agent panel.
\n Agent Mode\n
\n
\n
\n Powered by Gemini 3
\n All Gemini Code Assist tiers now use Gemini 3 Flash for completions and chat, and Gemini 3.1 Pro for Agent Mode — delivering next-generation intelligence across the full development lifecycle.\n
" }, { "type": "explain", "title": "Quick Reference: What to Type in the Chat Panel", "content": "

New to Gemini? Start with these proven prompts. Select the code you want to work with first, then type in the Gemini chat panel.

\n
\n
\n 🔍\n
Understand Code
\n
/explain this code
\n
Get a plain-English breakdown of what selected code does, line by line.
\n
\n
\n 🐛\n
Find Bugs
\n
Find bugs in this function
\n
Gemini reviews selected code for logic errors, off-by-one bugs, null-pointer risks, and anti-patterns.
\n
\n
\n 🧪\n
Write Tests
\n
Write a unit test for this method
\n
Generates JUnit 5 / JUnit / Jest tests with arrange-act-assert structure and edge-case coverage.
\n
\n
\n ♻️\n
Refactor
\n
Refactor this to use async/await
\n
Rewrites callback-heavy or synchronous code to modern async patterns. Also try: ‘simplify this’, ‘split into smaller functions’.
\n
\n
\n 📖\n
Document
\n
Add docstrings to this function
\n
Generates Google-style, NumPy, or JSDoc comments. Specify the style if you have a preference.
\n
\n
\n \n
Optimise
\n
Make this more efficient
\n
Identifies O(n²) loops, redundant DB calls, and memory leaks. Suggests vectorised, cached, or batched alternatives.
\n
\n
\n
Pro tip: Always select code first before typing your prompt — Gemini uses the selection as context. Without a selection, it answers from general knowledge only.
" } ] }, { "id": "agent-mode", "num": "03", "title": "Agent Mode", "subtitle": "Autonomous Multi-Step Coding — Let Gemini Drive", "icon": "🤖", "color": "#7c3aed", "gradient": "linear-gradient(135deg,#7c3aed,#4c1d95)", "description": "By the end of this phase you will have Agent Mode build a complete §9-503 Silver Layer transformer autonomously — reading files, writing code, running tests, and iterating on failures without you typing a single line of code. Agent Mode changes how you approach multi-step engineering tasks.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
⚠️ Before starting: The FilingSearchController you create in this phase replaces the HealthController from Phase 1. Delete HealthController.java before proceeding — both controllers map to /api and Spring Boot will refuse to start with duplicate mappings.
" }, { "type": "explain", "content": "
🔨 Phase 3 — FilingSearchService.java + UccApiApplication.java (wired) + tests/ Use a single Agent Mode prompt to build the full SearchService, wire it into UccApiApplication.java, write JUnit 5 tests, and run them. After this phase your API is fully functional locally.
\n
\n
\n \n
Phase 1–2
\n
skeleton + models ✓
\n
\n
\n
\n 🔨\n
Phase 3
\n
search + tests ← Agent Mode
\n
\n
\n
\n \n
Phase 4
\n
CLI + CI pipeline
\n
\n
\n
\n \n
Phase 5–8
\n
GitHub, Jira, MCP, Gov
\n
\n
\n
\n
AFTER AGENT MODE COMPLETES — run these to verify:
\n
mvn test
\n
# Expected: 5 passed
\n
mvn spring-boot:run
\n
curl -X POST http://localhost:8080/api/search \\
\n
  -H \"Content-Type: application/json\" \\
\n
  -d '{\"debtorName\": \"Acme Transport LLC\"}'
\n
# Returns: {\"results\":[...],\"total\":2,\"normalizedQuery\":\"ACME TRANSPORT\"}
\n
" }, { "type": "explain", "title": "💻 No Agent Mode? Create Files Manually", "content": "
\n
💻 NO AGENT MODE — FOLLOW THIS PATH
\n

Agent Mode generates three files in one step from a single prompt. Without it, copy the three files shown in the sections below — the end result is identical.

\n
\n
\n
STEP 1 — Copy service/FilingSearchService.java from the section below
\n

Contains: mock filing database (11 filings, 4 states) + search() with state and risk-score filters.

\n
\n
\n
STEP 2 — Copy updated UccApiApplication.java from the section below
\n

Adds POST /search wired to search().

\n
\n
\n
STEP 3 — Copy test/FilingSearchControllerTest.java from the section below
\n

Then run:

\nmvn test\n
\n
\n
STEP 4 — Test the running API with curl
\nmvn spring-boot:run &\ncurl -s -X POST http://localhost:8080/search \
-H 'Content-Type: application/json' \
-d '{\"debtorName\": \"Acme Transport LLC\"}'
\n
{\"results\":[...], \"total\": 3, \"normalizedQuery\": \"ACME TRANSPORT\"}
\n
\n
\n
\n✅ Checkpoint: mvn test shows 8+ tests passing. POST /search returns filings with normalized query.\n
\n
\n
\n
SECTIONS YOU CAN SKIP (require Gemini Agent Mode / GCP)
\n
\n⚠️ Agent Mode End-to-End Walkthrough\n⚠️ Agent Mode + MCP\n
\n
" }, {"type":"explain","title":"Run the Tests — Expected Output","content":"

Run the full test suite to confirm everything works:

$ mvn verify

test/FilingSearchControllerTest.java::test_health_check PASSED
test/FilingSearchControllerTest.java::test_search_by_debtorName PASSED
test/FilingSearchControllerTest.java::test_search_case_insensitive PASSED
test/FilingSearchControllerTest.java::test_search_with_state_filter PASSED
test/FilingSearchControllerTest.java::test_search_no_results PASSED
test/FilingSearchControllerTest.java::test_get_filing_by_id PASSED
test/FilingSearchControllerTest.java::test_get_filing_not_found PASSED

---------- coverage: 92% ----------
Name                          Stmts   Miss   Cover
service/FilingSearchService.java      28      2     93%
service/NameNormalizerService.java          12      1     92%
7 passed in 0.45s
\u2705 Checkpoint: All 7 tests should pass with 90%+ coverage. If any test fails, check that dto/Filing.java and service/NameNormalizerService.java from Phase 02 are in place.
"}, { "type": "code", "title": "src/main/java/com/ucc/api/service/FilingSearchService.java — Built by Agent Mode", "lang": "java", "content": "// ucc-api/src/main/java/com/ucc/api/service/FilingSearchService.java\n// Agent Mode generates this from a single prompt -- including mock data + search logic\npackage com.ucc.api.service;\n\nimport com.ucc.api.dto.*;\nimport org.springframework.stereotype.Service;\nimport java.time.LocalDate;\nimport java.util.List;\nimport java.util.Optional;\n\n@Service\npublic class FilingSearchService {\n\n private final NameNormalizerService normalizer;\n\n private static final List MOCK_FILINGS = List.of(\n new Filing(\"CA-2024-001\", \"Acme Transport LLC\", null,\n \"First National Bank\", \"CA\",\n LocalDate.of(2024, 1, 15), null, null, 72.5),\n new Filing(\"CA-2024-002\", \"ACME TRANSPORT LLC\", null,\n \"Pacific Credit Union\", \"CA\",\n LocalDate.of(2024, 3, 8), null, null, 72.5),\n new Filing(\"TX-2024-015\", \"Lone Star Freight Inc\", null,\n \"Texas Commerce Bank\", \"TX\",\n LocalDate.of(2024, 2, 20), null, null, 45.0)\n new Filing(\"NY-2024-003\", \"Empire State Logistics LLC\", null,\n \"Chase Manhattan\", \"NY\",\n LocalDate.of(2024, 4, 12), null, null, 88.3),\n new Filing(\"FL-2024-007\", \"Sunshine Distribution Corp\", null,\n \"SunTrust Bank\", \"FL\",\n LocalDate.of(2024, 1, 30), null, null, 61.0),\n new Filing(\"CA-2024-009\", \"Pacific Rim Trading Co\", null,\n \"Bank of America\", \"CA\",\n LocalDate.of(2024, 5, 5), null, null, 33.7),\n new Filing(\"TX-2024-022\", \"Lone Star Freight Inc\", null,\n \"Wells Fargo\", \"TX\",\n LocalDate.of(2024, 6, 18), null, null, 45.0),\n new Filing(\"NY-2024-011\", \"Hudson Valley Materials Inc\", null,\n \"Citibank NA\", \"NY\",\n LocalDate.of(2024, 3, 25), null, null, 55.2),\n new Filing(\"FL-2024-019\", \"Gulf Coast Shipping LLC\", null,\n \"Regions Bank\", \"FL\",\n LocalDate.of(2024, 7, 2), null, null, 92.1),\n new Filing(\"CA-2024-031\", \"Bay Area Tech Solutions Inc\", null,\n \"Silicon Valley Bank\", \"CA\",\n LocalDate.of(2024, 8, 14), null, null, 27.8)\n );\n\n public FilingSearchService(NameNormalizerService normalizer) {\n this.normalizer = normalizer;\n }\n\n public SearchResponse search(SearchRequest request) {\n String normalizedQuery = normalizer.normalizeDebtorName(\n request.debtorName());\n\n List results = MOCK_FILINGS.stream()\n .filter(f -> normalizer.normalizeDebtorName(\n f.debtorName()).equals(normalizedQuery))\n .filter(f -> request.state() == null\n || f.state().equalsIgnoreCase(request.state()))\n .filter(f -> request.minRiskScore() == null\n || (f.lienRiskScore() != null\n && f.lienRiskScore() >= request.minRiskScore()))\n .toList();\n\n return new SearchResponse(results, results.size(),\n normalizedQuery);\n }\n\n public Optional getById(String filingId) {\n return MOCK_FILINGS.stream()\n .filter(f -> f.filingId().equals(filingId))\n .findFirst();\n }\n}", "desc": "

👤 Developer: Review this before committing. Check for: correct imports, no hardcoded credentials, edge cases handled, naming consistent with existing files.

🤖 AI Tool: Produced this autonomously from your spec and existing codebase context. Verify the output rather than assuming correctness — AI tools occasionally miss edge cases on first generation.

" }, { "type": "code", "title": "ucc-api/controller/FilingSearchController.java — Wired by Agent Mode", "lang": "java", "content": "// controller/FilingSearchController.java\npackage com.ucc.api.controller;\n\nimport com.ucc.api.dto.*;\nimport com.ucc.api.service.FilingSearchService;\nimport jakarta.validation.Valid;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.server.ResponseStatusException;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/api\")\npublic class FilingSearchController {\n\n private final FilingSearchService searchService;\n\n public FilingSearchController(FilingSearchService svc) {\n this.searchService = svc;\n }\n\n @GetMapping(\"/health\")\n public Map health() {\n return Map.of(\"status\", \"ok\", \"version\", \"0.3.0\");\n }\n\n @PostMapping(\"/search\")\n public SearchResponse searchFilings(\n @Valid @RequestBody SearchRequest request) {\n return searchService.search(request);\n }\n\n @GetMapping(\"/filings/{filingId}\")\n public Filing getFilingById(@PathVariable String filingId) {\n return searchService.getById(filingId)\n .orElseThrow(() -> new ResponseStatusException(\n HttpStatus.NOT_FOUND,\n \"Filing \" + filingId + \" not found\"));\n }\n}", "desc": "

👤 Developer: Agent Mode modified the existing UccApiApplication.java to add the search endpoint. Compare the diff carefully — verify Agent Mode did not remove the /health endpoint or break existing imports when adding the new route.

🤖 AI Tool: Generated this Java from the surrounding project context. Cross-check naming conventions and imports against your existing files before committing.

" }, { "type": "code", "title": "src/test/java/com/ucc/api/FilingSearchControllerTest.java — Generated by Agent Mode", "lang": "java", "content": "// ucc-api/src/test/java/com/ucc/api/FilingSearchControllerTest.java\n// Agent Mode writes these tests after building FilingSearchService\n// Run: mvn verify\npackage com.ucc.api;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.ucc.api.dto.SearchRequest;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.MockMvc;\n\nimport static org.hamcrest.Matchers.*;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;\n\n@SpringBootTest\n@AutoConfigureMockMvc\nclass FilingSearchControllerTest {\n\n @Autowired MockMvc mockMvc;\n @Autowired ObjectMapper objectMapper;\n\n @Test\n void healthCheck() throws Exception {\n mockMvc.perform(get(\"/api/health\"))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.status\").value(\"ok\"));\n }\n\n @Test\n void searchByDebtorName() throws Exception {\n var request = new SearchRequest(\n \"Acme Transport LLC\", null, null);\n mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(request)))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.total\").value(1))\n .andExpect(jsonPath(\"$.normalizedQuery\")\n .value(\"ACME TRANSPORT\"));\n }\n\n @Test\n void searchCaseInsensitive() throws Exception {\n var upper = new SearchRequest(\n \"ACME TRANSPORT LLC\", null, null);\n var lower = new SearchRequest(\n \"acme transport llc\", null, null);\n String r1 = mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(upper)))\n .andReturn().getResponse().getContentAsString();\n String r2 = mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(lower)))\n .andReturn().getResponse().getContentAsString();\n // Both should return same total — \u00a79-503 normalization is case-insensitive\n assertEquals(r1, r2);\n }\n\n @Test\n void searchWithStateFilter() throws Exception {\n var request = new SearchRequest(\n \"Acme Transport LLC\", \"CA\", null);\n mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(request)))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.results[*].state\")\n .value(everyItem(is(\"CA\"))));\n }\n\n @Test\n void searchNoResults() throws Exception {\n var request = new SearchRequest(\n \"Nonexistent Entity XYZ\", null, null);\n mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(request)))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.total\").value(0));\n }\n\n @Test\n void getFilingById() throws Exception {\n mockMvc.perform(get(\"/api/filings/CA-2024-001\"))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.filingId\")\n .value(\"CA-2024-001\"));\n }\n\n @Test\n void getFilingNotFound() throws Exception {\n mockMvc.perform(get(\"/api/filings/INVALID-999\"))\n .andExpect(status().isNotFound());\n }\n\n @Test\n void searchWithMinRiskScore() throws Exception {\n var request = new SearchRequest(\n \"Acme Transport LLC\", null, 80.0);\n mockMvc.perform(post(\"/api/search\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(objectMapper.writeValueAsString(request)))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.total\").value(0));\n }\n}", "desc": "

👤 Developer: Review this before committing. Check for: correct imports, no hardcoded credentials, edge cases handled, naming consistent with existing files.

🤖 AI Tool: Produced this autonomously from your spec and existing codebase context. Verify the output rather than assuming correctness — AI tools occasionally miss edge cases on first generation.

" }, { "type": "explain", "title": "Agent Mode + MCP — Extend the Agent with External Tools", "content": "
Why MCP servers matter for data engineers? Without MCP, Agent Mode can only read and write files in your local project. With a BigQuery MCP server, Agent Mode can query your actual UCC tables to investigate data quality issues, validate pipeline outputs, and generate reports. The difference between 'tell me about the schema' and 'here is the schema I just queried' is everything.
\n\n

Agent Mode in Gemini Code Assist can be extended with MCP (Model Context Protocol) servers via the Gemini CLI — connect your agent to BigQuery, Jira, GitHub, and Spring Boot Actuator without leaving the IDE.

\n
\n
\n 🤖\n
Agent Mode
\n
Gemini 3.1 Pro
\n
\n
\n
\n 📡\n
MCP Client
\n
built into plugin
\n
\n
\n
\n 🗄️\n
BigQuery MCP
\n
query UCC data
\n
\n
·
\n
\n 🐙\n
GitHub MCP
\n
create PRs
\n
\n
·
\n
\n 🔵\n
Jira MCP
\n
update tickets
\n
\n
\n
\n
\n 1\n
Add MCP server
to settings.json
\n
\n
\n 2\n
Agent discovers
available tools
\n
\n
\n 3\n
You describe
the goal
\n
\n
\n 4\n
Agent calls tools
with your approval
\n
\n
\n 5\n
Real-time output
streamed to panel
\n
\n
\n
\n

How Gemini Agent Mode Processes Your Request

\n
1
PLANGemini reads your request and the open files/workspace. It creates an internal execution plan listing which files to create, edit, or delete.
2
EXECUTEGemini makes file edits one at a time. Each edit is shown as a diff in the IDE. You can approve, reject, or ask for changes mid-execution.
3
VERIFYAfter edits: Gemini checks if the terminal shows errors (if you have a running dev server). It can self-correct based on visible output.
4
ITERATEFor complex tasks: Gemini loops — write code → run tests → read errors → fix → repeat. You stay in control via approve/reject at each step.
\n
Pro tip: Open your gemini.md context file BEFORE starting Agent Mode. Gemini reads it automatically and applies your project conventions without you having to repeat them in every prompt.
" }, { "type": "explain", "title": "How Agent Mode Works — The Autonomous Loop", "content": "
Why Agent Mode changes everything? Completions and chat require you to write and accept code one block at a time. Agent Mode takes a high-level goal ('Build the §9-503 transformer with tests') and handles the entire implementation loop — reading files, writing code, running tests, fixing errors — until the goal is achieved. Your role shifts from typist to goal-setter.
\n\n
\n
\n 1\n
You give a
high-level task
\n
\n
\n 2\n
Gemini reads
your codebase
\n
\n
\n 3\n
Plans a
multi-step approach
\n
\n
\n 4\n
Writes + edits
files autonomously
\n
\n
\n 5\n
Runs tests
validates output
\n
\n
\n 6\n
Shows you
a diff to review
\n
\n
\n
\n
\n 🔍\n
Workspace Awareness
\n
Reads your entire project tree — understands imports, dependencies, patterns
\n
\n
\n 🛠️\n
Tool Invocation
\n
Runs shell commands, git, npm, test runners — all within your terminal
\n
\n
\n 🔁\n
Iterative Refinement
\n
If tests fail, it re-diagnoses and retries — fully autonomous loop
\n
\n
\n 👁️\n
Human in the Loop
\n
You review every file diff before accepting — you stay in control
\n
\n
" }, {"type":"explain","title":"Agent Mode Diff Review — What You See","content":"
When Agent Mode finishes a task, it shows a diff for your approval:
  # service/FilingSearchService.java\n- results = MOCK_FILINGS.stream()\n-            .filter(f -> f.debtorName == request.debtorName]\n+ normalizedQuery = normalizeDebtorName(request.debtorName)\n+ results = [f for f in MOCK_FILINGS\n+            if normalizeDebtorName(f.debtorName) == normalizedQuery]
Always review Agent diffs before accepting. Check: (1) Are imports added? (2) Do existing tests still pass? (3) Does the change match your intent? Click Accept to apply or Reject to discard and refine your prompt.
"}, { "type": "explain", "content": "Agent Mode vs Chat vs Completion — When to Use Each\n

Gemini Code Assist offers three interaction modes with very different capabilities. Choosing the right mode determines whether you get a hint, a block of code, or a complete feature implementation.

\n\n \n \n \n \n \n \n \n \n \n
DimensionAgent ModeChatInline Completion
Autonomy🤖 Fully autonomous💬 Interactive, guided⚡ Single suggestion
File operations✅ Reads + writes files❌ Read-only context❌ Current file only
Terminal access✅ Runs commands❌ No execution❌ No execution
StepsUp to 40 stepsSingle responseSingle completion
Best forNew features, refactors, test suitesQuestions, design, reviewCode while typing
ModelGemini 3.1 ProGemini 3 FlashGemini 3 Flash
LatencyMinutes (complex)Seconds<1 second
UCC use caseBuild entire Silver layer transformerDebug a Spark schema errorComplete a filter condition
\n
\n When Agent Mode shines: Tasks that span multiple files, require iterative refinement, or need terminal feedback (test failures, linting errors). Think \"implement the entire §9-503 Silver layer\" — not \"fix this one function.\"\n
" }, { "type": "explain", "content": "How Agent Mode Works — The Execution Loop\n

Agent Mode uses a ReAct-style (Reason → Act → Observe) loop powered by Gemini 3.1 Pro's tool-calling capabilities. Each step is visible in the Agent panel — you can pause, redirect, or reject any action.

\n
\n
\n
REASON
\n
Gemini reads your task description and existing codebase context. It creates a step-by-step plan: \"1. Read existing schema files. 2. Understand current Silver transformer. 3. Identify §9-503 gaps. 4. Implement normalization class. 5. Run tests.\"
\n
\n
\n
ACT
\n
Executes tool calls: read_file (loads schemas, existing code), write_file (creates new files or patches), run_terminal (JUnit 5, linting, spark-submit), search_codebase (finds usages, related functions).
\n
\n
\n
OBSERVE
\n
Reads tool output (test failures, lint warnings, file contents) and adjusts the plan. If JUnit 5 fails with a schema mismatch, Gemini diagnoses the error, fixes the code, and re-runs — autonomously.
\n
\n
\n
\n
\n
TOOLS AVAILABLE
\n
\n 📁 read_file / list_directory
\n ✏️ write_file / patch_file
\n 💻 run_terminal (bash/zsh)
\n 🔍 search_codebase (grep/find)
\n 🌐 fetch_url (docs, APIs)
\n 🔌 MCP server tools (custom)\n
\n
\n
\n
GUARDRAILS
\n
\n 🚫 Cannot push to git (you control commits)
\n 🚫 Cannot deploy to GCP (you approve)
\n ⚠️ Destructive ops require confirmation
\n 📋 Full audit log of every action taken
\n ⏸️ Pause/reject any step mid-execution
\n 🔄 Rollback: all file changes tracked\n
\n
\n
" }, { "type": "config", "title": "GEMINI.md — Project Configuration", "desc": "

👤 Developer: 👤 What you do: Create a file named GEMINI.md in your repo root and paste the content below. ⚡ What happens: Agent Mode reads GEMINI.md at the start of every session as its authoritative project brief — it learns your tech stack, conventions, and banned patterns before writing a single line of code.Tip: GEMINI.md is to Gemini Code Assist what CLAUDE.md is to Claude Code. Spend 15 minutes writing a good one and Agent Mode will immediately give you project-aware responses instead of generic Java or Spring Boot boilerplate.

🤖 AI Tool: Reads this configuration at session start to understand your project structure, dependencies, and environment. Keep it current as your project evolves.

", "lang": "markdown", "label": "GEMINI.md", "content": "# ucc-api — Gemini Agent Guide\n\n## Project Overview\nLocal Spring Boot REST API for UCC lien filing search.\nRuns with: mvn spring-boot:run (http://localhost:8080)\n\n## File Structure\nucc-api/\n├── UccApiApplication.java # Spring Boot app + route wiring\n├── pom.xml # Maven dependencies\n├── GEMINI.md # this file\n├── models/\n│ └── src/main/java/com/ucc/api/\n│ ├── UccApiApplication.java\n│ ├── controller/\n│ │ └── FilingSearchController.java # REST endpoints\n│ ├── dto/\n│ │ ├── Filing.java # Java Record: Filing\n│ │ ├── SearchRequest.java # Java Record: search input\n│ │ └── SearchResponse.java # Java Record: search output\n│ └── service/\n│ ├── NameNormalizerService.java # §9-503 name normalization\n│ └── FilingSearchService.java # search + mock data (→ repository in Phase 7)\n└── src/test/java/com/ucc/api/\n ├── FilingSearchControllerTest.java # MockMvc integration tests\n └── NameNormalizerServiceTest.java # Unit tests for normalizer\n\n## Domain Rules — CRITICAL\n- Debtor name matching uses §9-503 normalization (strip suffixes, uppercase, remove punctuation)\n- normalizeDebtorName() in service/NameNormalizerService.java is the canonical implementation\n- SearchService.search() applies normalization before comparing names\n- Mock data uses realistic CA/TX/NY/FL UCC-1 filing records\n\n## Running Locally\nmvn dependency:resolve\nmvn spring-boot:run\n# Test: curl -X POST http://localhost:8080/api/search -H \"Content-Type: application/json\" -d '{\"debtorName\":\"Acme Transport LLC\"}'\n\n## Running Tests\nmvn verify\n\n## Gemini Agent Instructions\n- Always read this file before making changes\n- When adding new endpoints, add corresponding tests in tests/\n- Keep mock data in MOCK_FILINGS list in FilingSearchService.java (min 10 entries)\n- Do not add real credentials or GCP project IDs to any file\n- Repository pattern refactor goes in repository/ package (Phase 7)" }, { "type": "scenario", "title": "Agent Mode End-to-End Walkthrough", "desc": "

👤 Developer: Follow each step in sequence. Do not skip ahead — later steps depend on state created by earlier ones.

🤖 AI Tool: Handles the multi-step execution. Your role is to review output at each checkpoint and provide corrections if the output drifts from the spec.

", "content": "

This walkthrough shows Agent Mode autonomously implementing the SearchService for the ucc-api from a single high-level prompt — reading your models, writing the service, adding mock data, and running tests until they all pass.

AGENT MODE PROMPT
\"Read GEMINI.md and dto/Filing.java. Implement SearchService in service/FilingSearchService.java with 10 realistic mock UCC-1 filings across CA, TX, NY, FL. Add search() and getById() methods. Then write JUnit 5 tests in test/FilingSearchControllerTest.java, run them with JUnit 5, and fix any failures.\"
AGENT MODE — EXECUTION LOG
Reading GEMINI.md... found domain rules and file structure
Reading dto/Filing.java... found Filing, SearchRequest, SearchResponse
Reading service/NameNormalizerService.java... found normalizeDebtorName()
Writing service/FilingSearchService.java... (SearchService + 10 mock filings)
Writing test/FilingSearchControllerTest.java... (7 test cases)
Running: mvn test
test_health_check PASSED
test_search_by_debtorName PASSED
test_search_case_insensitive PASSED
test_search_with_state_filter PASSED
test_search_no_results PASSED
test_get_filing_by_id PASSED
test_get_filing_not_found PASSED
7 passed in 0.43s — Coverage: 94%
" }, { "type": "prompt", "title": "High-Impact Agent Mode Prompts", "label": "Start Agent Mode with Ctrl+Shift+P → \"Gemini: Start Agent\"", "content": "# ucc-api Agent Mode Prompts\n\n## Build a complete feature\n\"Read GEMINI.md and the existing service/FilingSearchService.java.\n Add pagination to the /search endpoint:\n - Accept cursor (filingId) and page_size (default 20) query params\n - Return next_cursor in the response if more results exist\n - Add a test for paginated results in test/FilingSearchControllerTest.java\n Run JUnit 5 and fix any failures before finishing.\"\n\n## Add a new endpoint\n\"Read GEMINI.md and dto/Filing.java.\n Add a GET /states endpoint that returns a list of US states\n with their filing counts from MOCK_FILINGS.\n Add the route to UccApiApplication.java, write tests, run JUnit 5.\"\n\n## Fix failing tests\n\"Run mvn test. For each failing test:\n 1. Show me the assertion error\n 2. Identify whether the bug is in the service or the test\n 3. Fix the root cause (not just the test assertion)\n 4. Re-run to confirm all tests pass.\"\n\n## Add input validation\n\"Review UccApiApplication.java and dto/Filing.java for missing input validation.\n Add Jakarta Validation annotations for:\n - state: must be a valid 2-letter US state code\n - min_risk_score: must be between 0 and 100\n - debtorName: must be at least 2 characters\n Update the relevant tests to cover validation errors (400 responses).\"\n\n## Refactor for BigQuery (prep for Phase 7)\n\"Read GEMINI.md and service/FilingSearchService.java.\n Refactor SearchService to use a repository pattern:\n - Create db/repository.java with a FilingRepository abstract base class\n - Move MOCK_FILINGS to db/MockFilingRepository.java\n - FilingSearchService.java should accept a repository in constructor\n This will make it easy to swap in the BigQuery repository in Phase 7.\n Update tests to inject the mock repository.\"", "desc": "

👤 Developer: Use these prompts to direct the AI agent on multi-step tasks. Provide the task in one message — avoid drip-feeding instructions, which leads to context fragmentation.

🤖 AI Tool: Breaks the task into subtasks, executes each using available tools, and reports back. Monitor tool call outputs at each step to catch drift before it compounds.

" } ] }, { "id": "gemini-cli", "num": "04", "title": "Gemini CLI", "subtitle": "Terminal-First AI — Scripts, CI/CD, Automation", "icon": "💻", "color": "#f59e0b", "gradient": "linear-gradient(135deg,#f59e0b,#b45309)", "description": "By the end of this phase you will have Gemini CLI installed and integrated into your GitHub Actions pipeline for AI-powered CI steps. The CLI lets you run Gemini on any file, script, or repo from the terminal — no IDE required and no copy-paste needed.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Install the Gemini CLI and authenticate with your Google account via the terminal
  • Run one-shot prompts and interactive sessions from the command line
  • Pipe shell output into Gemini for analysis and automated fixes
  • Integrate Gemini CLI commands into a GitHub Actions CI workflow
" }, { "type": "explain", "content": "
🔨 Phase 4 — pom.xml (verified) + CI pipeline Use the Gemini CLI to scan your project files and generate a complete pom.xml, then ask it to write a GitHub Actions CI that runs your JUnit 5 suite. No GCP credentials needed for CI — just Java + JUnit 5.
\n
\n
\n \n
Phase 1–3
\n
API + tests ✓
\n
\n
\n
\n 🔨\n
Phase 4
\n
pom.xml + ci.yml
\n
\n
\n
\n \n
Phase 5
\n
GitHub PR review
\n
\n
\n
\n \n
Phase 6–8
\n
Jira, MCP, Gov
\n
\n
\n
\n
CLI COMMANDS — run from the ucc-api/ directory:
\n
gemini -f UccApiApplication.java -f services/ -f models/ \\
\n
  \"Scan these files and generate pom.xml with pinned versions\"
\n
gemini -f UccApiApplication.java -f tests/ \\
\n
  \"Write a GitHub Actions CI workflow: checkout, Java 21, mvn verify with coverage\"
\n
" }, { "type": "explain", "title": "💻 No Gemini CLI? Write CI Manually", "content": "
\n
💻 NO GEMINI CLI — FOLLOW THIS PATH
\n

The Gemini CLI requires a GCP account and gcloud auth login. Without it, copy the .github/workflows/ci.yml shown in this phase, and run the equivalent checks locally with the commands below.

\n
\n
\n
STEP 1 — Copy .github/workflows/ci.yml from the section below
\n

This is the exact YAML gemini-cli would generate. Push to GitHub and CI runs automatically.

\n
\n
\n
STEP 2 — Run lint checks locally (what the CLI does)
\n# Java formatting check (uses Checkstyle via Maven)\nmvn checkstyle:check # verify code style\n# If Checkstyle not configured, skip — CI will catch it\n
\n
\n
STEP 3 — Run tests with coverage (what the CI pipeline checks)
\n# Run tests with coverage via Maven Surefire + JaCoCo\nmvn verify # runs all tests\n# Add JaCoCo plugin to pom.xml for coverage reports\n
TOTAL ... 96% <-- passes the 85% threshold
\n
\n
\n
STEP 4 — Security scan (optional)
\n# Use OWASP dependency-check for security scanning\nmvn org.owasp:dependency-check-maven:check\n
\n
\n
\n✅ Checkpoint: All tests pass with mvn verify. .github/workflows/ci.yml exists in the repo.\n
\n
\n
\n
SECTIONS YOU CAN SKIP (require Gemini CLI / GCP)
\n
\n⚠️ Installing & Configuring the Gemini CLI\n⚠️ Gemini CLI Settings File\n⚠️ Power CLI Workflows\n
\n
" }, { "type": "config", "title": "ucc-api/.github/workflows/ci.yml — Generated by Gemini CLI", "lang": "yaml", "content": "# ucc-api/.github/workflows/ci.yml\n# Generated by: gemini -f src/ \"Write GitHub Actions CI for this Spring Boot app\"\n\nname: UCC API CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\njobs:\n test:\n name: Test (Java 21)\n runs-on: ubuntu-latest\n\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n\n - name: Set up JDK 21\n uses: actions/setup-java@v4\n with:\n java-version: '21'\n distribution: 'temurin'\n cache: 'maven'\n\n - name: Run tests\n run: mvn verify --batch-mode\n\n - name: Upload coverage\n uses: codecov/codecov-action@v4\n if: always()\n\n lint:\n name: Checkstyle\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-java@v4\n with:\n java-version: '21'\n distribution: 'temurin'\n cache: 'maven'\n - run: mvn checkstyle:check", "desc": "

👤 Developer: Add this file to .github/workflows/ in your repo. Update the Java/Node version and secret names to match your GitHub repository settings.

🤖 AI Tool: Can generate and debug GitHub Actions workflows on request. Paste failing workflow logs back to the AI — it can diagnose YAML indentation errors and missing permissions.

" }, { "type": "explain", "title": "Gemini CLI Now Runs on Gemini 3 Flash", "content": "
Why use the CLI instead of the IDE? The Gemini CLI works on any machine, in CI/CD pipelines, and in server environments with no GUI. It lets you pipe files directly into Gemini, automate AI-powered code reviews in GitHub Actions, and use Gemini in shell scripts. The IDE extension and the CLI complement each other — use both.
\n\n

The Gemini CLI was updated in March 2026 to use Gemini 3 Flash — delivering near-Pro reasoning at the terminal with 3× lower latency than before.

\n
\n
\n
\n
faster than
2.0 Pro CLI
\n
\n
\n
1M
\n
token context
for repo analysis
\n
\n
\n
High
\n
thinking level
for complex debug
\n
\n
\n
Free
\n
personal use
tier available
\n
\n
\n
\n Set thinking level in CLI:
\n gemini --thinking high \"Why is this query slow?\" < query.sql
\n Thinking levels: minimal (fastest) → lowmediumhigh (most thorough)\n
" }, { "type": "explain", "title": "Gemini CLI — What You Can Do", "content": "\n
\n
\n 📁\n
Summarize Repos
\n
gemini \"summarize this codebase\" — instant project overview
\n Explore\n
\n
\n 🐛\n
Debug in Terminal
\n
Pipe error output directly to Gemini for instant root cause analysis
\n Debug\n
\n
\n 📝\n
Generate Scripts
\n
Describe the task — get a working bash/Java script back
\n Generate\n
\n
\n 🔄\n
Refactor Files
\n
Pass file paths and transformation instructions — get diff output
\n Refactor\n
\n
\n 🌐\n
Google Search
\n
Built-in grounding — answers cite live web results automatically
\n Grounded\n
\n
\n
" }, { "type": "explain", "content": "Installing & Configuring the Gemini CLI\n

The gemini CLI is a Node.js tool distributed via npm. It authenticates via the same Google Cloud identity as the IDE plugin — no separate setup needed if you've already configured gcloud.

\n
\n
\n
INSTALL
\n
\n npm install -g @google/gemini-cli
\n gemini --version
\n gemini auth login\n
\n
\n
\n
QUICK TEST
\n
\n gemini \"What is §9-503?\"
\n gemini -f schema.java \"Review this\"
\n gemini --model pro \"Complex task\"\n
\n
\n
\n\n \n \n \n \n \n \n \n \n
CLI FlagDescriptionUCC Platform Example
-f <file>Include file as contextgemini -f src/main/java/com/ucc/api/service/NameNormalizerService.java \"Add §9-503 validation\"
-d <dir>Include directory as contextgemini -d ./pipeline/ \"Explain the data flow\"
--modelSelect model (flash/pro)gemini --model pro \"Complex architecture review\"
-o <file>Write output to filegemini \"Generate test suite\" -o test_lien_score.java
--jsonReturn structured JSONgemini --output-format json \"Classify this filing type\"
-sStream outputgemini -s \"Explain this 500-line DAG\"
--sandboxAllow code executiongemini --sandbox \"Run and fix the failing test\"
" }, { "type": "config", "title": "Gemini CLI Settings File", "desc": "
Install the Gemini CLI first (run in your terminal)
# Step 1: Install globally\n#   @google/gemini-cli — Gemini AI in your terminal, no IDE needed\nnpm install -g @google/gemini-cli\n\n# Step 2: Authenticate\ngemini auth login           # opens browser for Google OAuth\n\n# Step 3: Verify\ngemini --version            # should print version number
👤 Developer: Create ~/.gemini/config.json (macOS/Linux) or %USERPROFILE%\\.gemini\\config.json (Windows) and paste the settings below. The project field must match your GCP project ID — without it, CLI requests use personal quota instead of your organisation's.

🤖 AI Tool: Not involved in this setup. The Gemini CLI is a standalone tool you run from your terminal — VS Code does not need to be open.", "lang": "json", "label": "~/.gemini/settings.json", "content": "{\n \"defaultModel\": \"gemini-3-flash\",\n \"agentModel\": \"gemini-3.1-pro\",\n \"project\": \"ucc-lien-risk-prod\",\n \"region\": \"us-central1\",\n\n \"context\": {\n \"autoInclude\": [\"GEMINI.md\", \"openapi.yaml\"],\n \"maxFileSize\": \"100KB\",\n \"maxDirFiles\": 50\n },\n\n \"output\": {\n \"defaultFormat\": \"markdown\",\n \"codeHighlighting\": true,\n \"maxTokens\": 8192\n },\n\n \"safety\": {\n \"blockHarmfulContent\": true,\n \"logAllRequests\": true,\n \"auditLogPath\": \"~/.gemini/audit.log\"\n },\n\n \"mcpServers\": {\n \"bigquery-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/bigquery/index.js\"],\n \"env\": {\n \"GOOGLE_CLOUD_PROJECT\": \"ucc-lien-risk-prod\",\n \"BQ_DATASET\": \"ucc_pipeline\"\n }\n },\n \"github-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/github/index.js\"],\n \"env\": {\n \"GITHUB_TOKEN\": \"${GITHUB_TOKEN}\",\n \"GITHUB_REPO\": \"acme-corp/ucc-lien-risk\"\n }\n }\n },\n\n \"aliases\": {\n \"review\": \"Review this code for §9-503 compliance, performance, and security. Use severity tags.\",\n \"test\": \"Generate a comprehensive JUnit 5 test suite with UCC domain fixtures.\",\n \"explain\": \"Explain this code step by step in terms of the UCC filing domain.\",\n \"schema\": \"Analyze this BigQuery schema and suggest optimizations for UCC query patterns.\"\n }\n}" }, { "type": "code", "title": "CI/CD Pipeline Integration — GitHub Actions", "desc": "

👤 Developer: 👤 What you do: Add this workflow to .github/workflows/gemini-ci.yml in your repo. ⚡ What happens: Every pull request triggers Gemini CLI to review the diff for BigQuery anti-patterns, security issues, and UCC domain logic errors — results posted as a PR comment before human review.Tip: The GEMINI_API_KEY secret is set in your GitHub repo under Settings → Secrets → Actions. Use a service account key with minimal permissions (only BigQuery read + Gemini API) for CI/CD environments, not your personal developer key.

🤖 AI Tool: Generated this yaml from the surrounding project context. Cross-check naming conventions and imports against your existing files before committing.

", "lang": "yaml", "label": ".github/workflows/gemini-ci.yml", "content": "name: Gemini AI-Assisted CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\njobs:\n # ── AI Code Review ──────────────────────────────────────────────────\n ai-review:\n name: Gemini Code Review\n runs-on: ubuntu-latest\n if: github.event_name == 'pull_request'\n steps:\n - uses: actions/checkout@v4\n\n - name: Set up Gemini CLI\n run: npm install -g @google/gemini-cli\n\n - name: Authenticate via API Key\n run: echo \"Using GEMINI_API_KEY from repository secrets\"\n env:\n GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}\n\n - name: AI review changed files\n run: |\n CHANGED=$(git diff --name-only origin/main...HEAD -- 'src/main/java/**/*.java')\n if [ -n \"$CHANGED\" ]; then\n for file in $CHANGED; do\n echo \"=== Reviewing $file ===\"\n gemini -f \"$file\" \
\"Review this Spring Boot service file. Check for:\n 1. Missing input validation (Java Record validators)\n 2. §9-503 normalization applied consistently\n 3. All public methods covered by tests in tests/\n 4. No hardcoded credentials or project IDs\n Rate each: PASS / WARN / FAIL with explanation.\"\n done\n fi\n\n # ── Tests + Coverage ──────────────────────────────────────────────────\n test:\n name: Test (Java 21)\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions/setup-java@v4\n with:\n java-version: '21'\n distribution: 'temurin'\n cache: 'maven'\n\n - name: Run tests\n run: mvn verify --batch-mode\n\n # ── Lint ─────────────────────────────────────────────────────\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-java@v4\n with:\n java-version: '21'\n distribution: 'temurin'\n cache: 'maven'\n - run: mvn checkstyle:check" }, { "type": "prompt", "title": "Power CLI Workflows", "label": "Terminal — Supercharge your daily workflow", "content": "# Gemini CLI one-liners for ucc-api development\n\n# Explain a complex function\ngemini -f ucc-api/service/NameNormalizerService.java \
\"Explain the normalizeDebtorName() function step by step.\n What §9-503 edge cases does it handle?\n What inputs would it normalize incorrectly?\"\n\n# Review a service file\ngemini -f ucc-api/service/FilingSearchService.java \
\"Review SearchService for correctness and completeness.\n Does it handle: case-insensitive matching, state filtering,\n missing fields, empty results? List any gaps.\"\n\n# Generate missing tests\ngemini -f ucc-api/service/FilingSearchService.java \
-f ucc-api/test/FilingSearchControllerTest.java \
\"What test cases are missing from FilingSearchControllerTest.java?\n Generate the missing tests. Focus on edge cases:\n names with punctuation, single-word names, state code validation.\"\n\n# Generate Java Record validators\ngemini -f ucc-api/dto/Filing.java \
\"Add Jakarta Validation annotations to SearchRequest:\n - state: @Pattern(regexp=\"[A-Z]{2}\") optional 2-letter US state code\n - minRiskScore: @Min(0) @Max(100) double\n - debtorName: @NotBlank @Size(min=2) String\"\n\n# Document an endpoint\ngemini -f ucc-api/UccApiApplication.java \
\"Generate OpenAPI @Operation annotations for each endpoint.\n Include: summary, description, response examples,\n and error cases (400, 404, 400).\"\n\n# Scan for security issues\ngemini -f ucc-api/UccApiApplication.java -f src/main/java/com/ucc/api/service/ \
\"Security review: check for SQL injection risk,\n unvalidated inputs, error messages that leak internals,\n and missing rate limiting. Rate each finding: HIGH/MEDIUM/LOW.\"", "desc": "

👤 Developer: These CLI command sequences automate repetitive UCC API development tasks. Each workflow is a multi-command sequence — run them in your terminal with the UCC API repo as your working directory. The diff-review and PR-description workflows save the most time in daily use.

🤖 AI Tool: Use these prompts as direct input. Each is structured to produce a specific output format — modify the UCC-specific values but preserve the structural pattern.

" } ] }, { "id": "github", "num": "05", "title": "GitHub Integration", "subtitle": "AI-Powered PR Reviews, Actions & Issue Triage", "icon": "🐙", "color": "#6e40c9", "gradient": "linear-gradient(135deg,#6e40c9,#4a1d96)", "description": "By the end of this phase you will have Gemini Code Assist connected to your GitHub repo as an OAuth app and reviewing pull requests automatically. Every PR will receive structured AI feedback with severity ratings before a human reviewer opens it.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Install the Gemini Code Assist GitHub App on your repository
  • Trigger automatic AI PR review summaries on pull requests
  • Use Gemini in GitHub Actions to run issue triage and label suggestions
  • Understand how Gemini's PR feedback differs from a human code review
" }, { "type": "explain", "content": "
🔨 Phase 5 — db/Input Validation via PR Review Open a pull request adding @Valid annotations and error handling to your DTOs and controller. Gemini Code Assist automatically reviews the PR and flags missing edge cases.
\n
\n
\n \n
Phase 1–4
\n
API + CI ✓
\n
\n
\n
\n 🔨\n
Phase 5
\n
Validation + Errors (PR)
\n
\n
\n
\n \n
Phase 6
\n
Jira stories
\n
\n
\n
\n \n
Phase 7–8
\n
MCP + Governance
\n
\n
\n

Create branch feat/input-validation, add @Valid annotations and GlobalExceptionHandler.java, open a PR — Gemini reviews automatically within seconds.

" }, { "type": "explain", "content": "Gemini Code Assist for GitHub — Setup & Architecture\n

Gemini Code Assist for GitHub is a GitHub OAuth App that connects to your organization's repositories. Once installed, it automatically reviews every pull request and can be invoked manually via PR comments.

\n
\n
\n
INSTALLATION
\n
\n 1. Go to marketplace.github.com → \"Gemini Code Assist\"
\n 2. Install for your org: acme-corp
\n 3. Select repositories: ucc-lien-risk
\n 4. Authorize with your Google Cloud project
\n 5. Configure via .gemini/config.yaml in repo root\n
\n
\n
\n
WHAT IT DOES
\n
\n ✦ Reviews every PR automatically on open/push
\n ✦ Posts structured feedback as PR comments
\n ✦ Responds to @gemini-code-assist review
\n ✦ Generates missing tests on request
\n ✦ Triages new issues with labels + summary
\n ✦ Checks security, style, and §9-503 compliance\n
\n
\n
\n
\n
PR COMMENT COMMANDS
\n \n \n \n \n \n \n \n \n
CommandAction
@gemini-code-assist reviewTrigger a fresh review of the full PR
@gemini-code-assist explainPlain-English summary of all changes
@gemini-code-assist generate testsCreate tests for changed functions
@gemini-code-assist security reviewDeep security audit of the diff
@gemini-code-assist fix <comment>Auto-fix a specific review finding
@gemini-code-assist summarizeOne-paragraph PR summary for release notes
\n
" }, { "type": "config", "title": "Gemini GitHub Configuration", "desc": "

👤 Developer: 👤 What you do: Add this config to your repo root as .gemini/github.yaml after installing the Gemini GitHub app. ⚡ What happens: Gemini Code Assist reviews every PR with UCC-specific focus areas: BigQuery performance, data quality, and §9-503 regulatory compliance. High and critical severity issues are flagged as blocking.Tip: Install the Gemini Code Assist GitHub app at github.com/apps/gemini-code-assist. You need repo admin access to install it. The app posts PR comments as gemini-code-assist[bot] — team members can respond to its comments directly in the PR thread.

🤖 AI Tool: Reads this configuration at session start to understand your project structure, dependencies, and environment. Keep it current as your project evolves.

", "lang": "yaml", "label": ".gemini/config.yaml", "content": "# Gemini Code Assist — GitHub Integration Configuration\n# Docs: cloud.google.com/gemini/docs/codeassist/github-integration\n\nreview:\n # Trigger automatic review on PR open and every push to PR branch\n auto_review: true\n trigger_on: [opened, synchronize, reopened]\n\n # Always review these paths regardless of change size\n always_review_patterns:\n - \"src/main/java/com/ucc/api/service/**\"\n - \"src/main/java/com/ucc/api/dto/**\"\n - \"src/main/java/com/ucc/api/UccApiApplication.java\"\n\n # Skip review for these paths (no logic changes)\n ignore_patterns:\n - \"**/*.md\"\n - \"pom.xml\"\n - \".github/workflows/**\"\n\n # Severity levels to comment on\n min_severity: WARNING # SUGGESTION | WARNING | ERROR\n\n # Custom review instructions for ucc-api\n custom_prompt: |\n You are reviewing a Spring Boot UCC filing search API (ucc-api).\n Focus on:\n 1. §9-503 name normalization: normalizeDebtorName() must be called\n before any debtor name comparison — flag if bypassed\n 2. Input validation: all endpoint inputs must have Java Record validators\n 3. Test coverage: every new service method needs a test in tests/\n 4. No hardcoded credentials, project IDs, or real PII in mock data\n 5. Consistent error handling: use ResponseStatusException with appropriate HTTP status codes" }, {"type":"code","title":"dto/SearchRequest.java — Add @Valid Annotations (Your PR Content)","lang":"java","label":"src/main/java/com/ucc/api/dto/SearchRequest.java","content":"// src/main/java/com/ucc/api/dto/SearchRequest.java\n// Enhanced with Bean Validation — this is the code you PR in Phase 5\npackage com.ucc.api.dto;\n\nimport jakarta.validation.constraints.*;\n\npublic record SearchRequest(\n @NotBlank(message = \"debtorName is required\")\n @Size(min = 2, max = 200, message = \"debtorName must be 2-200 chars\")\n String debtorName,\n\n @Pattern(regexp = \"^[A-Z]{2}$\", message = \"state must be a 2-letter code\")\n String state,\n\n @Min(value = 0, message = \"minRiskScore must be >= 0\")\n @Max(value = 100, message = \"minRiskScore must be <= 100\")\n Double minRiskScore\n) {}","desc":"

👤 Developer: Replace your existing SearchRequest.java with this validated version. Create a new git branch: git checkout -b feat/input-validation, commit the change, and push to open a PR. Gemini Code Assist reviews it automatically.

🤖 AI Tool: Gemini reviews the PR within seconds — expect it to flag missing error response handling and suggest adding a @ControllerAdvice for consistent 400 responses.

"}, {"type":"code","title":"controller/GlobalExceptionHandler.java — Consistent Error Responses","lang":"java","label":"src/main/java/com/ucc/api/controller/GlobalExceptionHandler.java","content":"// src/main/java/com/ucc/api/controller/GlobalExceptionHandler.java\n// Handles validation errors and returns structured JSON error responses\npackage com.ucc.api.controller;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.*;\nimport java.time.Instant;\nimport java.util.*;\n\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n @ExceptionHandler(MethodArgumentNotValidException.class)\n @ResponseStatus(HttpStatus.BAD_REQUEST)\n public Map handleValidation(\n MethodArgumentNotValidException ex) {\n List> fieldErrors = ex.getBindingResult()\n .getFieldErrors().stream()\n .map(e -> Map.of(\n \"field\", e.getField(),\n \"message\", e.getDefaultMessage()))\n .toList();\n return Map.of(\n \"timestamp\", Instant.now().toString(),\n \"status\", 400,\n \"error\", \"Validation Failed\",\n \"fieldErrors\", fieldErrors);\n }\n}","desc":"

👤 Developer: Create this file alongside your SearchRequest changes — add it to the same PR branch. This gives Gemini two related files to review together, producing richer feedback.

🤖 AI Tool: Gemini will likely suggest adding more exception handlers (e.g., for ResponseStatusException) and may recommend logging the validation failures.

"}, { "type": "scenario", "title": "PR Review Walkthrough — ucc-api Search Enhancement PR", "desc": "

👤 Developer: Follow each step in sequence. Do not skip ahead — later steps depend on state created by earlier ones.

🤖 AI Tool: Handles the multi-step execution. Your role is to review output at each checkpoint and provide corrections if the output drifts from the spec.

", "content": "

PR #12: \"feat(search): add risk score filter and state validation\" — 3 files changed, +67 −19 lines

GEMINI CODE ASSIST — AUTOMATED PR REVIEW
⚠ WARNING — ucc-api/dto/Filing.java
minRiskScore field has no validation bounds. A caller can pass -5 or 999 — both are accepted silently. Add: @Min(0) @Max(100) Double minRiskScore
💡 SUGGESTION — ucc-api/service/FilingSearchService.java
The new filterByRisk() helper method is not covered by any test in test/FilingSearchControllerTest.java. Add a test for: minimum score of 0, maximum of 100, and a score that filters out all results.
✅ PASS — ucc-api/UccApiApplication.java
State validation correctly uses state.toUpperCase() before passing to SearchRequest. Error handling returns proper 400 with field-level detail. No credentials or hardcoded values detected.
" }, {"type":"explain","title":"Verify GitHub Integration","content":"
\u2705 Checkpoint — Verify GitHub App Installation:
  1. Go to your repository on GitHub \u2192 Settings \u2192 Integrations
  2. You should see gemini-code-assist listed under GitHub Apps
  3. Open any PR — within ~5 minutes, gemini-code-assist[bot] should post a review comment
  4. If no comment appears, check that the app has Read & Write permissions on Pull Requests
\u26a0\ufe0f Note: The GitHub App may take up to 5 minutes to post its first review — this is normal.
"}, { "type": "prompt", "title": "GitHub Integration Prompts", "label": "Use these in PR comments to invoke Gemini", "content": "# PR Comment Commands for the UCC Platform\n\n## Targeted review\n@gemini-code-assist review\nFocus specifically on: §9-503 name matching correctness,\ndata quality log completeness, and Spring Boot performance.\nCompare our fuzzy match implementation against the GEMINI.md thresholds.\n\n## Generate missing tests\n@gemini-code-assist generate tests\nGenerate JUnit 5 tests for the SearchRequest validation changes in this PR.\nMust include: blank debtor names, invalid state codes,\nnegative risk scores, null fields, and boundary conditions at score 0 and 100.\n\n## Security audit\n@gemini-code-assist security review\nAudit the new Spring Boot endpoints in this PR for:\n- Missing @PreAuthorize annotations\n- Request parameter injection vectors\n- Improper error handling that exposes entity PII in stack traces\n\n## Explain for reviewers\n@gemini-code-assist explain\nGive a plain-English walkthrough of all changes for a reviewer\nwho is not familiar with §9-503 rules but understands Spring Boot.\n\n## Auto-fix a finding\n@gemini-code-assist fix\nFinding: SearchRequest.java — minRiskScore has no validation bounds.\nFix: add @Min(0) @Max(100) to the minRiskScore field.\nAdd @NotBlank to the debtorName field.\nUpdate FilingSearchController to return 400 on validation errors.", "desc": "

👤 Developer: Use these prompts with the Gemini GitHub App installed on your repo. The PR review prompt is the most valuable — paste it in a PR comment to get a structured review covering security, correctness, and spec compliance. Run it on every PR before merging.

🤖 AI Tool: Use these prompts as direct input. Each is structured to produce a specific output format — modify the UCC-specific values but preserve the structural pattern.

" } ] }, { "id": "jira", "num": "06", "title": "Jira Integration", "subtitle": "AI-Powered Planning via Atlassian Intelligence + Gemini", "icon": "📋", "color": "#2684ff", "gradient": "linear-gradient(135deg,#2684ff,#0052cc)", "description": "By the end of this phase you will have Gemini Code Assist connected to Jira and generating sprint-ready user stories with acceptance criteria from a single epic description. AI-powered sprint velocity predictions and tech debt scoring will be available on every UCC ticket.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Connect Gemini Code Assist to your Jira Cloud instance via the IDE plugin
  • Generate user stories and acceptance criteria from a Jira ticket inside VS Code
  • Break epics into sprint-ready sub-tasks using Gemini's planning prompts
  • Link code changes back to Jira issues automatically during development
" }, { "type": "explain", "content": "
🔨 Phase 6 — Jira stories for ucc-api v2 Your API works but has no pagination, authentication, or rate limiting. Use Gemini in Jira to break a v2 epic into sprint-ready stories with acceptance criteria and story point estimates.
\n
\n
\n \n
Phase 1–5
\n
API + BigQuery ✓
\n
\n
\n
\n 🔨\n
Phase 6
\n
v2 sprint stories
\n
\n
\n
\n \n
Phase 7
\n
MCP live queries
\n
\n
\n
\n \n
Phase 8
\n
Enterprise controls
\n
\n
\n

Jira epic prompt: \"Break this epic into stories: Add pagination (cursor-based), JWT auth, and per-client rate limiting to the ucc-api Spring Boot service. Team velocity 40pts, 2-week sprint.\"

" }, { "type": "explain", "content": "Gemini + Jira — Setup & Capabilities\n

The Gemini Code Assist Jira integration is available via the Atlassian Marketplace (Google-published app). It connects your Jira project to Gemini, enabling AI-powered project intelligence at every SDLC phase.

\n\n \n \n \n \n \n \n \n \n
CapabilityWhere it appearsUCC Platform example
Epic decompositionEpic detail view → AI buttonBreak \"Implement Silver Layer\" into 12 specific stories with effort points
Story generationSprint board → \"Generate stories\"Auto-create §9-503 normalization stories from a 2-sentence requirement
Acceptance criteriaStory editor → AI assistGiven/When/Then for entity linking with fuzzy match scenarios
Code-to-story linkingPR descriptions → Jira via webhookAuto-link merged PR to the Jira story based on branch name + PR description
Sprint velocitySprint planning viewPredict sprint completion risk based on historical velocity + story complexity
Bug triageBug reporter → AI labelAuto-classify new bugs: §9-503 violation, data quality, performance, security
Release notesRelease page → GenerateUser-facing release notes from merged PR list + Jira story summaries
\n
\n
INSTALLATION
\n
\n 1. Jira Settings → Apps → Find new apps → Search \"Gemini Code Assist\"
\n 2. Install the Google-published app → Authorize
\n 3. Connect your GCP project: ucc-lien-risk-prod
\n 4. Set Jira project context: UCC-PLATFORM
\n 5. Configure team velocity baseline: 42 story points / sprint (2 weeks)\n
\n
" }, { "type": "scenario", "title": "Epic → Stories → Acceptance Criteria Workflow", "desc": "

👤 Developer: Work through each check in order. Do not mark a check complete until you have run the verification command and seen the expected result.

🤖 AI Tool: Each acceptance criterion maps to a specific tool behavior. If a check fails, ask the AI tool: \"Why would [criterion] fail?\" with your current configuration pasted in.

", "content": "
\n
\n
EPIC — UCC-142
\n
Add Pagination, Validation & API Documentation to ucc-api
\n
Enhance the ucc-api search endpoint with cursor-based pagination, input validation, and OpenAPI documentation for the credit analyst team.
\n
→ Click \"✨ Generate Stories\" in Jira Epic view
\n
\n
\n
GEMINI GENERATES — 8 STORIES IN 12 SECONDS
\n
\n
\n
UCC-143: Cursor-Based Pagination (8 pts)
\n
Add cursor (filingId) and pageSize parameters to POST /api/search — return nextCursor in response
\n
\n
\n
UCC-144: Input Validation with @Valid (5 pts)
\n
Add @NotBlank, @Size, @Min/@Max annotations to SearchRequest — return 400 with field-level errors
\n
\n
\n
UCC-145: OpenAPI / Swagger Documentation (5 pts)
\n
Add springdoc-openapi dependency, annotate DTOs and endpoints — serve Swagger UI at /swagger-ui
\n
\n
\n
UCC-146: Structured Error Responses (3 pts)
\n
Create ErrorResponse DTO with timestamp, status, message, fieldErrors — use @ControllerAdvice
\n
\n
+ 4 more stories: Rate limiting, health endpoint enhancements, search result sorting, integration tests
\n
\n
\n
\n
ACCEPTANCE CRITERIA — AI GENERATED FOR UCC-143
\n
\n Given an entity with 4 active UCC-1 liens in BigQuery Silver
\n When the Gold scorer runs compute_active_lien_score(entity_id)
\n Then the score component returns 32 (4/5 * 40 max points)

\n Given an entity with 6+ active liens
\n When compute_active_lien_score is called
\n Then the score is capped at 40 (maximum for this component)

\n Given a lien with lapse_date in the past and no continuation filed
\n When scoring runs
\n Then the lapsed lien is NOT counted toward active_lien_count

\n Given an entity with zero active liens
\n When compute_active_lien_score is called
\n Then score returns 0 and entity still appears in gold_risk_profiles\n
\n
\n
" }, {"type":"code","title":"service/FilingSearchService.java — Add Cursor-Based Pagination","lang":"java","label":"src/main/java/com/ucc/api/service/FilingSearchService.java (updated)","content":"// Updated search method with cursor-based pagination\n// Implements Jira story UCC-143\npublic SearchResponse search(SearchRequest request) {\n String normalizedQuery = normalizer.normalizeDebtorName(\n request.debtorName());\n int pageSize = request.pageSize() != null\n ? request.pageSize() : 20;\n\n List allMatches = MOCK_FILINGS.stream()\n .filter(f -> normalizer.normalizeDebtorName(\n f.debtorName()).equals(normalizedQuery))\n .filter(f -> request.state() == null\n || f.state().equalsIgnoreCase(request.state()))\n .filter(f -> request.minRiskScore() == null\n || (f.lienRiskScore() != null\n && f.lienRiskScore() >= request.minRiskScore()))\n .toList();\n\n // Apply cursor: skip filings up to and including the cursor ID\n List afterCursor = allMatches;\n if (request.cursor() != null) {\n int idx = -1;\n for (int i = 0; i < allMatches.size(); i++) {\n if (allMatches.get(i).filingId()\n .equals(request.cursor())) {\n idx = i; break;\n }\n }\n afterCursor = idx >= 0\n ? allMatches.subList(idx + 1, allMatches.size())\n : allMatches;\n }\n\n List page = afterCursor.stream()\n .limit(pageSize).toList();\n String nextCursor = page.size() == pageSize\n ? page.get(page.size() - 1).filingId() : null;\n\n return new SearchResponse(page, allMatches.size(),\n normalizedQuery, nextCursor, pageSize);\n}","desc":"

👤 Developer: Replace your search() method with this paginated version. It implements story UCC-143 from the Jira epic above. The cursor is a filing ID — the client sends the last filingId it received to get the next page.

🤖 AI Tool: Ask Gemini: 'Write JUnit 5 tests for the paginated search — test first page, second page via cursor, empty cursor, and invalid cursor.'

"}, { "type": "prompt", "title": "Jira AI Prompts for UCC Project", "label": "Use in Jira AI sidebar (Story Editor → AI Assist)", "content": "# Story Generation Prompts\n\n\"Break this epic into implementable user stories for a 2-week sprint.\n Team velocity: 42 points. Tech stack: Spring Boot 3.3, Java 21 Records, JUnit 5, Maven.\n Apply §9-503 business rules. Estimate story points using Fibonacci scale.\"\n\n\"Generate a user story for: As a credit analyst, I need to search UCC filings\n by debtor name and see all associated entities (via §9-503 entity linking)\n so I can assess total lien exposure before approving a loan.\"\n\n# Acceptance Criteria Prompts\n\n\"Write Given/When/Then acceptance criteria for this story.\n Include: the happy path, §9-503 edge cases (trade names, misspellings),\n performance requirement (< 200ms API response), and error handling.\"\n\n\"Add non-functional requirements: the paginated search endpoint must respond\n in < 200ms for pages of 20 results across 1M filings.\n Format as testable criteria with measurable thresholds.\"\n\n# Sprint Planning\n\n\"Review our sprint backlog of 11 stories (85 points).\n Our team velocity is 42 points per 2-week sprint.\n Which stories have the highest risk of not completing?\n Suggest a prioritized sprint plan that fits within velocity.\"\n\n# Bug Triage\n\n\"This bug was filed: 'Entity SMITH TRUCKING LLC is showing 0 liens\n but we have 3 active UCC-1 filings for Smith Trucking in our records.'\n Classify the bug type, identify likely root cause areas in our service layer\n (entity linking? name normalization? search query logic?), and suggest\n investigation steps. Assign priority based on business impact.\"", "desc": "

👤 Developer: Use these prompts in the Jira AI assistant (click the AI button in any issue or board). The sprint planning prompt generates the best results when your epic has at least 3 linked Confluence pages — Jira AI reads them automatically for context.

🤖 AI Tool: Use these prompts as direct input. Each is structured to produce a specific output format — modify the UCC-specific values but preserve the structural pattern.

" }, { "type": "explain", "content": "Velocity Intelligence & Sprint Risk Scoring\n

Gemini analyzes your Jira sprint history to surface completion risk early — before sprint review day surprises. It tracks team velocity trends, story complexity signals, and external dependencies.

\n
\n
\n
🔴 HIGH
\n
Sprint Risk
\n
78 points planned vs 42-point velocity. 3 stories have external dependencies on the GCP infrastructure team. Recommend: defer UCC-146 (cross-state scorer) to next sprint.
\n
\n
\n
42→38
\n
Velocity Trend
\n
4-sprint downward trend. Pattern: §9-503 stories consistently take 1.3× estimated points due to edge case complexity. Adjust estimates for normalization stories.
\n
\n
\n
12 days
\n
Projected Completion
\n
Gold layer epic (143-150) projected to complete in 12 working days at current velocity. 85% confidence interval: 10–16 days.
\n
\n
\n
\n Tech Debt Radar: Gemini scans merged PRs for tech debt signals (TODO comments, skipped tests, workaround flags) and creates Jira tech debt stories automatically. On the UCC platform, it flagged 3 silver-layer workarounds added during a crunch sprint — each linked to the original story that caused the compromise.\n
" } ] }, { "id": "mcp-servers", "num": "07", "title": "MCP Servers", "subtitle": "Extending Agent Mode with Custom Tools", "icon": "🔌", "color": "#10b981", "gradient": "linear-gradient(135deg,#10b981,#065f46)", "description": "By the end of this phase you will have a custom BigQuery MCP server configured in Gemini Agent Mode, giving it direct SQL query capability against your UCC data pipeline tables. MCP servers are the tool layer that turns Agent Mode from a code suggester into a full-stack engineering partner.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Understand the Model Context Protocol (MCP) and why it extends Agent Mode
  • Configure an MCP server entry in VS Code so Gemini can call external tools
  • Use a BigQuery MCP tool to let Gemini query live data during agentic tasks
  • Build and register a custom MCP tool for your own project's internal API
" }, { "type": "explain", "content": "
🔨 Phase 7 — Repository Pattern + MCP Integration Refactor FilingSearchService to use a repository interface (local exercise). Optionally configure the BigQuery MCP server for live data access, generate realistic test fixtures, and update db/bigquery_client.java with the correct schema.
\n
\n
\n \n
Phase 1–6
\n
Full API + stories ✓
\n
\n
\n
\n 🔨\n
Phase 7
\n
BigQuery MCP live data
\n
\n
\n
\n \n
Phase 8
\n
Enterprise governance
\n
\n
\n
\n \n
Done!
\n
Production-ready API
\n
\n
\n

Agent Mode + MCP prompt: \"Use the BigQuery MCP to query ucc_data.bronze_filings. Get the actual schema and 5 sample rows. Update db/bigquery_client.java to match the real schema and replace MOCK_FILINGS in FilingSearchService.java with a real query.\"

" }, { "type": "explain", "content": "MCP in Gemini Agent Mode — Architecture\n

When Agent Mode is running a task, it can invoke MCP tools alongside its built-in capabilities (read_file, write_file, run_terminal). MCP servers run locally as Node.js/Java processes, exposing tools, resources, and prompts to the agent.

\n
\n
\n
\n
🤖
\n
Gemini Agent Mode
\n
Reasons, plans, executes
\n
\n
\n
\n
🔌
\n
MCP Servers
\n
BigQuery · GitHub · Jira
\n
\n
\n
\n
🌐
\n
External Systems
\n
GCP · APIs · DBs
\n
\n
\n
\n\n \n \n \n \n \n
MCP ServerTools ExposedUCC Use Case
BigQuery MCPquery_table, list_tables, describe_schema, get_row_countAgent queries Gold layer to validate risk scores, check data quality
GitHub MCPlist_prs, get_pr_diff, create_pr, add_comment, get_issueAgent creates PRs, links to Jira stories, posts review findings
Jira MCPget_story, create_story, update_status, add_comment, search_issuesAgent updates story status, links commits, creates bug reports
Dataproc MCPsubmit_job, get_job_status, get_job_logsAgent submits Spark jobs, monitors progress, retrieves error logs
" }, { "type": "config", "title": "Gemini CLI — MCP Server Configuration", "desc": "

👤 Developer: Add this block to the specified settings file. Replace placeholder paths and environment variable values with your actual project paths.

🤖 AI Tool: Reads this configuration to discover available MCP servers. After updating the file, restart the AI tool session for the new servers to appear.

", "lang": "json", "label": ".vscode/settings.json (MCP section)", "content": "{\n \"mcpServers\": {\n // ── BigQuery UCC Server ─────────────────────────────────────────────\n \"bigquery-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/bigquery/dist/index.js\"],\n \"env\": {\n \"GOOGLE_CLOUD_PROJECT\": \"ucc-lien-risk-prod\",\n \"BQ_DATASET\": \"ucc_pipeline\",\n \"BQ_LOCATION\": \"US\"\n },\n \"description\": \"BigQuery access to UCC pipeline tables (bronze, silver, gold)\"\n },\n\n // ── GitHub UCC Server ───────────────────────────────────────────────\n \"github-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/github/dist/index.js\"],\n \"env\": {\n \"GITHUB_TOKEN\": \"${env:GITHUB_TOKEN}\",\n \"DEFAULT_REPO\": \"acme-corp/ucc-lien-risk\",\n \"DEFAULT_BRANCH\": \"main\"\n },\n \"description\": \"GitHub API for PRs, issues, and code operations\"\n },\n\n // ── Jira UCC Server ─────────────────────────────────────────────────\n \"jira-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/jira/dist/index.js\"],\n \"env\": {\n \"JIRA_BASE_URL\": \"https://acme-corp.atlassian.net\",\n \"JIRA_TOKEN\": \"${env:JIRA_API_TOKEN}\",\n \"JIRA_EMAIL\": \"${env:JIRA_EMAIL}\",\n \"DEFAULT_PROJECT\": \"UCC\"\n },\n \"description\": \"Jira API for story management and sprint tracking\"\n },\n\n // ── Dataproc UCC Server ─────────────────────────────────────────────\n \"dataproc-ucc\": {\n \"command\": \"node\",\n \"args\": [\"./mcp-servers/dataproc/dist/index.js\"],\n \"env\": {\n \"GOOGLE_CLOUD_PROJECT\": \"ucc-lien-risk-prod\",\n \"DATAPROC_REGION\": \"us-central1\",\n \"DATAPROC_CLUSTER\": \"ucc-pipeline-cluster\"\n },\n \"description\": \"Submit and monitor Spark jobs on GCP Dataproc\"\n }\n }\n}" }, { "type": "code", "title": "BigQuery MCP Server — UCC Data Access", "desc": "

👤 Developer: 👤 What you do: Save this as mcp-servers/bigquery-mcp.js in your repo and run npm install @modelcontextprotocol/sdk @google-cloud/bigquery. ⚡ What happens: Agent Mode gains a query_bigquery tool it can call directly — it can now investigate data quality issues, validate pipeline outputs, and explore UCC table schemas without leaving the IDE.Tip: Test the MCP server works before using it in Agent Mode: run node mcp-servers/bigquery-mcp.js and verify it starts without errors. Then restart VS Code and check that Agent Mode lists bigquery in its available tools.

🤖 AI Tool: Generated this javascript from the surrounding project context. Cross-check naming conventions and imports against your existing files before committing.

", "lang": "javascript", "label": "mcp-servers/bigquery/src/index.ts", "content": "import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { BigQuery } from '@google-cloud/bigquery';\n\nconst bq = new BigQuery({ projectId: process.env.GOOGLE_CLOUD_PROJECT });\nconst DATASET = process.env.BQ_DATASET || 'ucc_pipeline';\n\nconst server = new Server(\n { name: 'bigquery-ucc', version: '1.0.0' },\n { capabilities: { tools: {} } }\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: 'query_ucc_data',\n description: 'Execute a BigQuery SQL query against the UCC pipeline dataset. ' +\n 'Tables: bronze_filings, silver_entities, silver_normalized, gold_risk_profiles, dq_log',\n inputSchema: {\n type: 'object',\n properties: {\n sql: { type: 'string', description: 'BigQuery Standard SQL query' },\n max_rows: { type: 'number', description: 'Maximum rows to return (default: 100, max: 1000)' }\n },\n required: ['sql']\n }\n },\n {\n name: 'describe_table',\n description: 'Get the schema and row count for a UCC pipeline BigQuery table',\n inputSchema: {\n type: 'object',\n properties: {\n table_name: {\n type: 'string',\n enum: ['bronze_filings', 'silver_entities', 'silver_normalized',\n 'gold_risk_profiles', 'dq_log'],\n description: 'Table to describe'\n }\n },\n required: ['table_name']\n }\n },\n {\n name: 'get_entity_risk_profile',\n description: 'Get the complete lien risk profile for a specific entity by ID',\n inputSchema: {\n type: 'object',\n properties: {\n entity_id: { type: 'string', description: 'UCC entity identifier' }\n },\n required: ['entity_id']\n }\n },\n {\n name: 'get_dq_log',\n description: 'Get recent data quality rejection events from the pipeline DQ log',\n inputSchema: {\n type: 'object',\n properties: {\n reason_code: { type: 'string', description: 'Filter by reason code (e.g., ENTITY_LINK_FAILED)' },\n limit: { type: 'number', description: 'Number of records (default: 50)' }\n }\n }\n }\n ]\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n if (name === 'query_ucc_data') {\n const maxRows = Math.min(args.max_rows || 100, 1000);\n const [rows] = await bq.query({\n query: args.sql,\n location: process.env.BQ_LOCATION || 'US',\n maximumBytesBilled: '1000000000' // 1GB cost guard\n });\n const limited = rows.slice(0, maxRows);\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n row_count: limited.length,\n rows: limited,\n truncated: rows.length > maxRows\n }, null, 2)\n }]\n };\n }\n\n if (name === 'describe_table') {\n const [meta] = await bq.dataset(DATASET).table(args.table_name).getMetadata();\n const [rows] = await bq.query({\n query: `SELECT COUNT(*) as cnt FROM \\`${DATASET}.${args.table_name}\\``\n });\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n schema: meta.schema.fields,\n row_count: rows[0].cnt,\n created: meta.creationTime,\n modified: meta.lastModifiedTime\n }, null, 2)\n }]\n };\n }\n\n if (name === 'get_entity_risk_profile') {\n const [rows] = await bq.query({\n query: `SELECT * FROM \\`${DATASET}.gold_risk_profiles\\`\n WHERE entity_id = @entity_id LIMIT 1`,\n params: { entity_id: args.entity_id }\n });\n if (rows.length === 0) throw new Error(`Entity ${args.entity_id} not found in Gold layer`);\n return { content: [{ type: 'text', text: JSON.stringify(rows[0], null, 2) }] };\n }\n\n if (name === 'get_dq_log') {\n const reasonFilter = args.reason_code\n ? `WHERE reason_code = @reason_code`\n : '';\n const limit = Math.min(args.limit || 50, 500);\n const [rows] = await bq.query({\n query: `SELECT * FROM \\`${DATASET}.dq_log\\` ${reasonFilter} ORDER BY created_at DESC LIMIT ${limit}`,\n params: args.reason_code ? { reason_code: args.reason_code } : {}\n });\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({ row_count: rows.length, rows }, null, 2)\n }]\n };\n }\n\n throw new Error(`Unknown tool: ${name}`);\n});\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);" }, {"type":"code","title":"repository/FilingRepository.java — Repository Interface (Local Exercise)","lang":"java","label":"src/main/java/com/ucc/api/repository/FilingRepository.java","content":"// src/main/java/com/ucc/api/repository/FilingRepository.java\n// Extract the data layer behind an interface — prepares for BigQuery swap\npackage com.ucc.api.repository;\n\nimport com.ucc.api.dto.Filing;\nimport java.util.List;\nimport java.util.Optional;\n\npublic interface FilingRepository {\n List findAll();\n Optional findById(String filingId);\n}","desc":"

👤 Developer: Create a new repository/ package under src/main/java/com/ucc/api/. This interface separates data access from business logic — the same pattern you'd use to swap mock data for a real database.

🤖 AI Tool: Tell Agent Mode: 'Extract MOCK_FILINGS from FilingSearchService into a FilingRepository interface + InMemoryFilingRepository. Use constructor injection. All existing tests must still pass.'

"}, {"type":"code","title":"repository/InMemoryFilingRepository.java — Mock Data Implementation","lang":"java","label":"src/main/java/com/ucc/api/repository/InMemoryFilingRepository.java","content":"// src/main/java/com/ucc/api/repository/InMemoryFilingRepository.java\n// Contains the mock filing data — swap with BigQueryFilingRepository when ready\npackage com.ucc.api.repository;\n\nimport com.ucc.api.dto.Filing;\nimport org.springframework.stereotype.Repository;\nimport java.time.LocalDate;\nimport java.util.*;\n\n@Repository\npublic class InMemoryFilingRepository implements FilingRepository {\n\n private static final List FILINGS = List.of(\n new Filing(\"CA-2024-001\", \"Acme Transport LLC\", null,\n \"First National Bank\", \"CA\",\n LocalDate.of(2024, 1, 15), null, null, 72.5),\n new Filing(\"CA-2024-002\", \"ACME TRANSPORT LLC\", null,\n \"Pacific Credit Union\", \"CA\",\n LocalDate.of(2024, 3, 8), null, null, 72.5),\n new Filing(\"TX-2024-015\", \"Lone Star Freight Inc\", null,\n \"Texas Commerce Bank\", \"TX\",\n LocalDate.of(2024, 2, 20), null, null, 45.0),\n new Filing(\"NY-2024-003\", \"Empire State Logistics LLC\", null,\n \"Chase Manhattan\", \"NY\",\n LocalDate.of(2024, 4, 12), null, null, 88.3),\n new Filing(\"FL-2024-007\", \"Sunshine Distribution Corp\", null,\n \"SunTrust Bank\", \"FL\",\n LocalDate.of(2024, 1, 30), null, null, 61.0),\n new Filing(\"CA-2024-009\", \"Pacific Rim Trading Co\", null,\n \"Bank of America\", \"CA\",\n LocalDate.of(2024, 5, 5), null, null, 33.7),\n new Filing(\"TX-2024-022\", \"Lone Star Freight Inc\", null,\n \"Wells Fargo\", \"TX\",\n LocalDate.of(2024, 6, 18), null, null, 45.0),\n new Filing(\"NY-2024-011\", \"Hudson Valley Materials Inc\", null,\n \"Citibank NA\", \"NY\",\n LocalDate.of(2024, 3, 25), null, null, 55.2),\n new Filing(\"FL-2024-019\", \"Gulf Coast Shipping LLC\", null,\n \"Regions Bank\", \"FL\",\n LocalDate.of(2024, 7, 2), null, null, 92.1),\n new Filing(\"CA-2024-031\", \"Bay Area Tech Solutions Inc\", null,\n \"Silicon Valley Bank\", \"CA\",\n LocalDate.of(2024, 8, 14), null, null, 27.8)\n );\n\n @Override\n public List findAll() { return FILINGS; }\n\n @Override\n public Optional findById(String filingId) {\n return FILINGS.stream()\n .filter(f -> f.filingId().equals(filingId))\n .findFirst();\n }\n}","desc":"

👤 Developer: This implementation holds the same mock data that was in FilingSearchService. After creating both files, update FilingSearchService to accept a FilingRepository via constructor injection instead of hardcoding MOCK_FILINGS.

🤖 AI Tool: The MCP BigQuery server (shown below) provides live data. To use it, create a BigQueryFilingRepository that implements the same interface — Spring auto-wires the active @Repository bean.

"}, {"type":"code","title":"service/FilingSearchService.java — Refactored with Repository Injection","lang":"java","label":"src/main/java/com/ucc/api/service/FilingSearchService.java (refactored)","content":"// src/main/java/com/ucc/api/service/FilingSearchService.java\n// Refactored: data access delegated to FilingRepository\npackage com.ucc.api.service;\n\nimport com.ucc.api.dto.*;\nimport com.ucc.api.repository.FilingRepository;\nimport org.springframework.stereotype.Service;\nimport java.util.List;\nimport java.util.Optional;\n\n@Service\npublic class FilingSearchService {\n\n private final NameNormalizerService normalizer;\n private final FilingRepository repository;\n\n public FilingSearchService(NameNormalizerService normalizer,\n FilingRepository repository) {\n this.normalizer = normalizer;\n this.repository = repository;\n }\n\n public SearchResponse search(SearchRequest request) {\n String normalizedQuery = normalizer.normalizeDebtorName(\n request.debtorName());\n\n List results = repository.findAll().stream()\n .filter(f -> normalizer.normalizeDebtorName(\n f.debtorName()).equals(normalizedQuery))\n .filter(f -> request.state() == null\n || f.state().equalsIgnoreCase(request.state()))\n .filter(f -> request.minRiskScore() == null\n || (f.lienRiskScore() != null\n && f.lienRiskScore() >= request.minRiskScore()))\n .toList();\n\n return new SearchResponse(results, results.size(),\n normalizedQuery);\n }\n\n public Optional getById(String filingId) {\n return repository.findById(filingId);\n }\n}","desc":"

👤 Developer: Replace your FilingSearchService with this version. The key change: MOCK_FILINGS is gone — data comes from the injected FilingRepository. Run mvn test — all existing tests still pass because Spring autowires InMemoryFilingRepository.

🤖 AI Tool: Agent Mode can do this refactor in one step. The prompt: 'Refactor FilingSearchService to use constructor-injected FilingRepository instead of hardcoded MOCK_FILINGS. Extract data into InMemoryFilingRepository. All tests must still pass.'

"}, { "type": "scenario", "title": "Agent Mode + MCP — Full Pipeline Analysis", "desc": "

👤 Developer: 👤 How to follow along: Open Agent Mode (Ctrl+Shift+G → Agent tab) and paste the prompt from the next section. ⚡ What happens: Agent Mode uses the BigQuery MCP to run SQL queries against your UCC tables, identifies the root cause of the data quality issue, and generates a fix — all autonomously without you writing a single SQL statement.Tip: You can watch Agent Mode's BigQuery calls in the chat panel — it shows the exact SQL it runs and the result. If a query fails, Agent Mode reads the error and self-corrects. This is the most powerful demo of what MCP + Agent Mode can do for data engineering.

🤖 AI Tool: Can assist at each decision point. Describe your specific situation when the scenario diverges from your project context — the AI adapts its guidance.

", "content": "
\n

Your Dataproc Gold job ran overnight and the credit team reports entity \"ACME TRANSPORT LLC\" shows a risk score of 0 — but they know the entity has active liens. You task Agent Mode to investigate.

\n
\n
YOUR PROMPT
\n Entity \"ACME TRANSPORT LLC\" has a risk score of 0 in the Gold layer\n but the credit team says they have 4 active UCC liens. Investigate\n using the BigQuery MCP tools and find where in the pipeline the\n entity is being lost or miscounted.\n
\n
\n
\n
MCP CALL
\n
\n
query_ucc_data: Check Gold layer
\n
SQL: SELECT * FROM gold_risk_profiles WHERE entity_id LIKE '%ACME%TRANSPORT%' LIMIT 10 → Returns 0 rows. Entity not in Gold layer at all.
\n
\n
\n
\n
MCP CALL
\n
\n
query_ucc_data: Check Silver layer
\n
SQL: SELECT * FROM silver_normalized WHERE match_key LIKE '%ACME%TRANSPORT%' → Returns 4 rows with match_key ACME TRANSPORT. Entity EXISTS in Silver.
\n
\n
\n
\n
MCP CALL
\n
\n
get_dq_log: Check rejection events
\n
Filter: entity_id LIKE 'ACME%' → Finds 4 DQ log entries with reason_code ENTITY_LINK_FAILED — the entity fails the Gold join because its entity_id format changed after the Silver schema migration last Tuesday.
\n
\n
\n
\n
READS FILE
\n
\n
Reads pipeline/gold/RiskScorerService.java
\n
Finds the entity_id join condition: silver.entity_id == gold_profiles.id — but after the Silver migration, the field was renamed from entity_id to canonical_entity_id. The Gold job wasn't updated.
\n
\n
\n
\n
WRITES FIX
\n
\n
Patches risk_scorer.java + writes tests
\n
Updates join condition to canonical_entity_id, adds a test for the field migration scenario, and creates a Jira bug report via GitHub MCP with the root cause analysis attached.
\n
\n
\n
\n
\n ✓ Root cause found in 4 tool calls. Fix applied. Tests written. Bug documented in Jira. Total time: ~45 seconds.\n
\n
" }, {"type":"explain","title":"Verify MCP Server","content":"
\u2705 Checkpoint — Verify MCP Server is Running:
  1. Build the server: cd mcp-servers/bigquery && npm install && npm run build
  2. You should see: BigQuery UCC MCP Server compiled successfully
  3. Verify your ~/.gemini/settings.json has the bigquery-ucc entry under mcpServers
  4. Test with: gemini “List all tables in the ucc_filings dataset”
\u26a0\ufe0f Note: MCP server integration is available via the Gemini CLI. Configure servers in ~/.gemini/settings.json. IDE Agent Mode does not directly connect to MCP servers.
"}, { "type": "prompt", "title": "Agent Mode + MCP Power Prompts", "label": "Agent Mode with MCP servers connected", "content": "# Data Investigation (requires BigQuery MCP)\n\n\"Use the BigQuery MCP to check data quality across all three layers:\n 1. Count records in bronze_filings, silver_normalized, gold_risk_profiles\n 2. Identify entities present in Silver but missing from Gold\n 3. Check the dq_log for the top 5 rejection reason codes in the last 7 days\n 4. Summarize the data loss percentage between layers\n 5. Create a Jira bug for any loss > 0.5%\"\n\n# Full-stack verification (requires BigQuery + GitHub MCP)\n\n\"After today's Gold layer run, verify end-to-end data quality:\n 1. Query gold_risk_profiles for the 5 entities with highest risk scores\n 2. For each entity, verify their Silver layer source data makes sense\n 3. Check that blanket_lien_flag matches the collateral description in Bronze\n 4. If any inconsistency found, create a GitHub issue with full details\"\n\n# Sprint automation (requires GitHub + Jira MCP)\n\n\"Daily standup prep:\n 1. Get all open PRs in the ucc-lien-risk repo assigned to me\n 2. For each PR, summarize the changes and current review status\n 3. Get my assigned Jira stories in the current sprint and their status\n 4. Identify any blockers (PRs with critical review findings, stories In Progress > 3 days)\n 5. Format as a standup update I can paste into Slack\"", "desc": "

👤 Developer: Use these prompts to direct the AI agent on multi-step tasks. Provide the task in one message — avoid drip-feeding instructions, which leads to context fragmentation.

🤖 AI Tool: Breaks the task into subtasks, executes each using available tools, and reports back. Monitor tool call outputs at each step to catch drift before it compounds.

" } ] }, { "id": "governance", "num": "08", "title": "Enterprise Controls", "subtitle": "Data Privacy, Audit Trails & ISO 42001 Compliance", "icon": "🏛️", "color": "#64748b", "gradient": "linear-gradient(135deg,#475569,#1e293b)", "description": "By the end of this phase you will have an enterprise policy configuration for Gemini Code Assist with CMEK encryption, VPC-SC isolation, and Cloud Logging audit trails. These controls satisfy your security team's requirements before Gemini is used on sensitive UCC financial data.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Enable Customer-Managed Encryption Keys (CMEK) for Gemini Code Assist data
  • Configure data-residency and code-snippet retention settings in the GCP console
  • View and export the Gemini audit trail from Cloud Logging
  • Map Gemini controls to ISO 42001 AI governance requirements
" }, { "type": "explain", "content": "
🔨 Phase 8 — Audit Trail + Enterprise Controls Your API is functionally complete. Add request audit logging locally, then explore GCP enterprise controls: CMEK encryption, VPC-SC perimeter, Cloud Logging, and ISO 42001 AI usage policy.
\n
\n
\n \n
Phase 1–7
\n
Full API + MCP ✓
\n
\n
\n
\n 🔨\n
Phase 8
\n
CMEK + audit + policy
\n
\n
\n
\n 🎉\n
Complete!
\n
Production-ready
\n
\n
\n
\n 🚀\n
Deploy
\n
Cloud Run + GKE
\n
\n
\n

After this phase your ucc-api is ready for a production GCP deployment with full enterprise compliance controls in place.

" }, { "type": "explain", "content": "Data Privacy Architecture — Where Your Code Goes\n

The most important question for enterprise adoption: does Google train its models on my code? The answer for Gemini Code Assist Enterprise: No. Here's the exact data flow:

\n
\n
\n
✓ SAFE
\n
Completions and chat are processed in Google Cloud (Vertex AI), not shared with third parties. Requests are ephemeral — not stored after processing. No code is used for model training for Enterprise customers.
\n
\n
\n
CMEK
\n
Customer-Managed Encryption Keys — All prompts and responses are encrypted with keys you control in Cloud KMS. Key rotation and revocation is under your team's control, not Google's.
\n
\n
\n
VPC-SC
\n
VPC Service Controls — Wrap the Gemini API endpoint in a VPC perimeter. Requests from outside your approved network are blocked. Critical for UCC PII data (debtor names, entity IDs).
\n
\n
\n
REGION
\n
Data Residency — Choose US, EU, or APAC regions for all Gemini processing. For the UCC platform: us-central1 for UCCSA data that cannot leave US jurisdiction.
\n
\n
\n\n \n \n \n \n \n \n
Security ControlConfigurationUCC Requirement
Model training opt-outAutomatic for Enterprise tier✅ UCC filing data cannot train Google models
Prompt loggingCloud Logging (configurable)✅ All AI interactions logged for audit
Access controlIAM: roles/cloudaicompanion.user✅ Only approved engineers can use Gemini
Network isolationVPC-SC perimeter✅ Gemini calls stay within GCP network
Key managementCloud KMS CMEK✅ Keys controlled by security team
" }, { "type": "explain", "content": "
\n

Enterprise Data Governance — What Leaves Your Environment

\n
✅ Stays In Your Environment

✓ Your local files not in open tabs
✓ Git history and secrets in .env
✓ Database credentials
✓ Audit logs (written to Cloud Logging)
✓ Model weights (hosted by Google)
⚠️ Sent to Google for Inference

→ Content of open editor tabs
→ Your gemini.md context file
→ Prompt text you type in chat
→ Selected code for review/explain
→ Terminal output (if Agent Mode active)
\n
0
Data used for training (Enterprise)
CMEK
Encryption option
VPC-SC
Network isolation
ISO 42001
AI governance standard
" }, { "type": "explain", "content": "Cloud Logging Audit Trails — Every AI Interaction Recorded\n

Every Gemini Code Assist interaction generates structured audit log entries in Cloud Logging. These logs are the foundation of your ISO 42001 AI management system audit trail.

\n
\n
// Cloud Logging entry — Gemini completion request
\n
{
\n
\"logName\": \"projects/ucc-lien-risk-prod/logs/cloudaicompanion.googleapis.com\",
\n
\"severity\": \"INFO\",
\n
\"protoPayload\": {
\n
\"methodName\": \"google.cloud.aicompanion.v1.CodeAssistService.CompleteCode\",
\n
\"authenticationInfo\": { \"principalEmail\": \"j.smith@acme-corp.com\" },
\n
\"requestMetadata\": { \"callerIp\": \"10.0.1.42\", \"userAgent\": \"vscode-gemini/2.1.0\" },
\n
\"resourceName\": \"projects/ucc-lien-risk-prod/locations/us-central1\"
\n
},
\n
\"jsonPayload\": {
\n
\"model\": \"gemini-3-flash\",
\n
\"input_tokens\": 847,
\n
\"output_tokens\": 312,
\n
\"latency_ms\": 1240,
\n
\"feature\": \"CODE_COMPLETION\"
\n
}
\n
}
\n
\n
\n
\n
📊 BigQuery Log Sink Query
\n
\n SELECT principalEmail,
\n COUNT(*) as requests,
\n SUM(input_tokens) as tokens
\n FROM gemini_audit_log
\n WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
\n GROUP BY 1
\n ORDER BY 2 DESC\n
\n
\n
\n
🚨 Alert Policy
\n
\n Alert when:
\n • Single user > 50K tokens/day (potential data exfiltration)
\n • Agent Mode actions > 20 file writes/session (runaway agent)
\n • Requests from IPs outside VPC-SC perimeter
\n • Response contains PII keywords (debtor SSN, EIN)\n
\n
\n
" }, {"type":"code","title":"config/AuditInterceptor.java — Request/Response Audit Trail","lang":"java","label":"src/main/java/com/ucc/api/config/AuditInterceptor.java","content":"// src/main/java/com/ucc/api/config/AuditInterceptor.java\n// Logs every API request — method, path, status, duration\npackage com.ucc.api.config;\n\nimport jakarta.servlet.http.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.HandlerInterceptor;\n\n@Component\npublic class AuditInterceptor implements HandlerInterceptor {\n\n private static final Logger log =\n LoggerFactory.getLogger(AuditInterceptor.class);\n\n @Override\n public boolean preHandle(HttpServletRequest req,\n HttpServletResponse res, Object handler) {\n req.setAttribute(\"startTime\", System.currentTimeMillis());\n return true;\n }\n\n @Override\n public void afterCompletion(HttpServletRequest req,\n HttpServletResponse res, Object handler, Exception ex) {\n long start = (long) req.getAttribute(\"startTime\");\n long duration = System.currentTimeMillis() - start;\n log.info(\"audit | method={} path={} status={} duration={}ms\",\n req.getMethod(), req.getRequestURI(),\n res.getStatus(), duration);\n }\n}","desc":"

👤 Developer: Create this interceptor in the config/ package. It logs every API call with method, path, HTTP status, and response time — this is the local equivalent of Cloud Logging audit trails.

🤖 AI Tool: Ask Gemini: 'Review AuditInterceptor.java — does it handle all edge cases? What about async requests and error paths?'

"}, {"type":"code","title":"config/WebConfig.java — Register the Audit Interceptor","lang":"java","label":"src/main/java/com/ucc/api/config/WebConfig.java","content":"// src/main/java/com/ucc/api/config/WebConfig.java\n// Registers AuditInterceptor for all /api/** endpoints\npackage com.ucc.api.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.*;\n\n@Configuration\npublic class WebConfig implements WebMvcConfigurer {\n\n private final AuditInterceptor auditInterceptor;\n\n public WebConfig(AuditInterceptor auditInterceptor) {\n this.auditInterceptor = auditInterceptor;\n }\n\n @Override\n public void addInterceptors(InterceptorRegistry registry) {\n registry.addInterceptor(auditInterceptor)\n .addPathPatterns(\"/api/**\");\n }\n}","desc":"

👤 Developer: Create this configuration class to wire the interceptor. After restarting the app, every API call produces a structured log line. Run curl http://localhost:8080/api/health and check the terminal for the audit log.

🤖 AI Tool: Agent Mode can scaffold both files in one step: 'Add a request audit interceptor that logs method, path, status, and duration for all /api/** endpoints. Register it via WebMvcConfigurer.'

"}, {"type":"config","title":"application.properties — Structured Logging Configuration","label":"src/main/resources/application.properties (updated for Phase 8)","content":"# src/main/resources/application.properties\n# Updated for Phase 8 — structured logging for compliance\nserver.port=8080\nspring.application.name=ucc-api\n\n# Logging\nlogging.level.com.ucc.api=INFO\nlogging.level.com.ucc.api.config.AuditInterceptor=INFO\nlogging.pattern.console=%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n\n\n# For JSON output (enterprise), add logstash-logback-encoder to pom.xml:\n# logging.config=classpath:logback-spring.xml","desc":"

👤 Developer: Update your application.properties with these logging settings. The structured format makes logs parseable by compliance tools — this is the local equivalent of GCP Cloud Logging.

🤖 AI Tool: For JSON-formatted logs (enterprise requirement), ask Gemini: 'Add logstash-logback-encoder to pom.xml and create logback-spring.xml that outputs JSON to stdout.'

"}, { "type": "config", "title": "Enterprise Policy Configuration", "desc": "

👤 Developer: 👤 What you do: Apply this configuration via gcloud org-policies set-policy and set the IAM roles as shown. ⚡ What happens: Gemini Code Assist is restricted to approved GCP projects, CMEK encryption is enforced on all AI data at rest, and VPC-SC perimeters prevent data exfiltration to external networks.Tip: Enterprise controls require the Gemini Code Assist Enterprise tier (not Standard). Check your subscription at console.cloud.google.com → Gemini Code Assist → Settings → Plan. Apply org policies in a test GCP org first — some policies are difficult to reverse once applied.

🤖 AI Tool: Reads this configuration at session start to understand your project structure, dependencies, and environment. Keep it current as your project evolves.

", "lang": "yaml", "label": "gemini-enterprise-policy.yaml", "content": "# Gemini Code Assist Enterprise Policy — UCC Platform\n# Apply via: gcloud resource-manager org-policies set-policy gemini-enterprise-policy.yaml --project=YOUR_PROJECT\n\n# ── Data Residency ──────────────────────────────────────────────────────────\napiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1\nkind: ResourceManagerPolicy\nmetadata:\n name: gemini-data-residency\nspec:\n constraints/gcp.resourceLocations:\n listPolicy:\n allow:\n values: [\"us-central1\", \"us-east1\"] # US only — UCCSA data jurisdiction\n constraints/iam.allowedPolicyMemberDomains:\n booleanPolicy:\n enforced: true # Must specify GCP project — no cross-project requests\n\n---\n# ── IAM Binding — Who Can Use Gemini ────────────────────────────────────────\n# Only developers in the ucc-engineers group\nresource: \"projects/ucc-lien-risk-prod\"\nbindings:\n - role: \"roles/cloudaicompanion.user\"\n members:\n - \"group:ucc-engineers@acme-corp.com\"\n - role: \"roles/cloudaicompanion.admin\"\n members:\n - \"group:ucc-platform-leads@acme-corp.com\"\n # Explicitly revoke from service accounts (no AI in prod pipelines without approval)\n - role: \"roles/cloudaicompanion.user\"\n members: [] # No service accounts\n condition:\n title: \"Block SA access\"\n expression: \"!resource.name.contains('serviceAccount')\"\n\n---\n# ── Audit Logging Configuration ──────────────────────────────────────────────\nauditConfigs:\n - service: \"cloudaicompanion.googleapis.com\"\n auditLogConfigs:\n - logType: ADMIN_READ\n - logType: DATA_READ\n - logType: DATA_WRITE\n # Sink all Gemini logs to BigQuery for compliance reporting\nlogSinks:\n - name: gemini-audit-to-bq\n destination: \"bigquery.googleapis.com/projects/ucc-compliance/datasets/ai_audit_log\"\n filter: |\n resource.type=\"cloudaicompanion.googleapis.com/Product\"\n severity>=INFO\n\n---\n# ── Agent Mode Restrictions ──────────────────────────────────────────────────\nagentModePolicy:\n maxStepsPerSession: 40\n allowedTools:\n - read_file\n - write_file\n - search_codebase\n - run_terminal\n restrictedTerminalCommands:\n - \"gcloud deploy\" # No direct GCP deployments\n - \"terraform apply\" # No infrastructure changes\n - \"git push\" # No direct remote pushes\n - \"kubectl apply\" # No K8s deployments\n requireApprovalFor:\n - \"delete_file\"\n - \"run_terminal\" # Require user confirmation for any terminal command\n\n---\n# ── ISO 42001 AI System Registry Entry ──────────────────────────────────────\naiSystemRegistry:\n system_id: \"GCA-001\"\n name: \"Gemini Code Assist\"\n purpose: \"AI-assisted software development for UCC Lien Risk Platform\"\n model: \"gemini-3-flash, gemini-3.1-pro\"\n risk_level: \"LOW\" # Internal development tool, not customer-facing\n data_processed: [\"source_code\", \"sql_queries\", \"config_files\"]\n pii_processed: false\n approved_by: \"CISO, 2025-01-15\"\n review_date: \"2026-01-15\"\n controls:\n - CMEK encryption\n - VPC-SC network isolation\n - US data residency\n - Cloud Logging audit trail\n - IAM role-based access\n - No model training on customer code" }, { "type": "scenario", "title": "ISO 42001 Compliance Review", "desc": "

👤 Developer: Walk through this scenario with a real (or test) repository to verify the workflow end-to-end. Note any steps where your team's process differs from what is shown.

🤖 AI Tool: Can simulate portions of this workflow when asked. Use it to draft the PR description, generate review comments, or explain what each automation step does.

", "content": "
\n

ISO 42001 requires organizations to manage AI systems as part of their Management System. For Gemini Code Assist, the quarterly review covers: usage metrics, incident review, control effectiveness, and risk re-assessment.

\n
\n
\n
98.2%
\n
Policy Compliance
\n
All Gemini requests from approved IPs. 0 VPC-SC violations. 1 IAM misconfiguration (resolved same day).
\n
\n
\n
847K
\n
Requests / Quarter
\n
12 active developers. Avg 70K requests/dev/quarter. 67% completions, 28% chat, 5% agent mode.
\n
\n
\n
0
\n
Security Incidents
\n
No PII in prompts detected. No data exfiltration alerts. No unauthorized access attempts.
\n
\n
\n
\n
ISO 42001 CONTROL EFFECTIVENESS
\n \n \n \n \n \n \n \n \n
ControlRequirementStatusEvidence
AI System RegisterAnnex A 6.1✅ CompliantGCA-001 registered, reviewed Q4 2025
Data Processing RecordsAnnex A 8.4✅ CompliantCloud Logging → BigQuery sink, 90-day retention
Human OversightAnnex A 9.3✅ CompliantAgent Mode: human approval for all terminal commands
Risk AssessmentClause 6.1✅ CompliantRISK-AI-003: LOW risk, no customer data processed
Incident ResponseAnnex A 10.1⚠️ In ProgressAI-specific runbook being drafted for Q1 2026
Training RecordsClause 7.2✅ Compliant12 devs completed AI governance training, certs on file
\n
\n
\n Next review action: Complete the AI incident response runbook (Annex A 10.1). Template prompt: Ask Gemini to draft the runbook from NIST AIRIA guidelines — then submit to CISO for approval. Due: 2026-01-31.\n
\n
" } ,{"type":"explain","title":"Verify Enterprise Controls","content":"
\u2705 Checkpoint — Enterprise Configuration:
  1. Verify location policy: gcloud resource-manager org-policies describe constraints/gcp.resourceLocations --project=YOUR_PROJECT
  2. Check audit logs: gcloud logging read “resource.type=audited_resource” --limit=5
  3. Verify CMEK: gcloud kms keys list --keyring=gemini-keys --location=us-central1
  4. Confirm VPC-SC: gcloud access-context-manager perimeters list
"} ] }, { "id": "capstone", "num": "★", "title": "Capstone Project", "subtitle": "Batch Risk Screening API — End-to-End with Gemini", "icon": "🎯", "color": "#f59e0b", "gradient": "linear-gradient(135deg,#f59e0b,#b45309)", "description": "Build a complete Batch Risk Screening feature on the ucc-api using every Gemini Code Assist capability you have learned.", "sections": [ { "type": "explain", "title": "What You'll Learn", "content": "
🎯 What You'll Learn

By the end of this phase:
  • Apply every Gemini capability taught in the course to a single end-to-end project
  • Build the complete ucc-api service from skeleton to Cloud Run deployment using AI assistance
  • Demonstrate how IDE completions, Agent Mode, CLI, GitHub reviews, and MCP tools work together
  • Produce a working portfolio project showing AI-augmented software development
" }, { "type": "explain", "title": "Capstone: Batch Risk Screening API", "content": "
What You'll Build in This Capstone

You already have a working ucc-api that searches UCC filings for one company name at a time. In this capstone you will extend it with a batch screening feature — the ability to check a whole list of companies at once and get back a risk report for each one.

You'll add two new API endpoints, write their models, tests, and documentation — using every Gemini Code Assist feature you learned in this course.

HOW THE API WORKS — DATA FLOW
📋
Input
List of company names
⚖️
Normalize
Strip LLC/Inc → uppercase
🔍
Look Up
Search UCC filing records
⚠️
Score Risk
LOW / MEDIUM / HIGH
📄
Report
JSON per company
THE TWO NEW ENDPOINTS YOU'LL CREATE
POST /batch-screen
Send a list of up to 100 company names. Get back a risk report for every single one — active lien count, risk level, and the filing IDs that triggered the risk.
Request: {\"entityNames\": [\"Acme LLC\", \"River Valley Inc\"]}
GET /risk-report/{entity_name}
Look up one company by name. Returns a detailed risk report. If the company isn't found, returns risk_level: UNKNOWN — never a 404 error.
Request: GET /risk-report/acme+transport+llc
2
New API Endpoints
5
New Java Record Models
6
Tests Generated
7
Gemini Features Used
Estimated time: 45–90 minutes. Each of the 7 steps below has a ✓ Checkpoint command — run it before moving forward. Don't skip checkpoints; they catch issues early.
" }, { "type": "explain", "title": "How You and Gemini Work Together", "content": "
Before You Start — Understand the Pattern

Every step in this capstone follows the same loop. Understanding this loop is more important than any single line of code.

👤 YOU (DEVELOPER)
🤖 GEMINI CODE ASSIST
1.Define the goal — decide what a class, function, or endpoint should do
3.Review the output — read what Gemini wrote, check it makes sense
4.Accept or correct — approve it, fix any bugs, then run the tests
2.Generate the code — reads your existing files, writes the implementation
waiting...
5.Run tests automatically — executes JUnit 5 and reports failures
Why this matters: You are not a passive passenger — Gemini writes code but you decide what to build. Every prompt you write is a specification. Every review you do is quality control. Gemini is fast at generating; you are the expert who knows if the output is correct.
YOUR 7-STEP ROADMAP
1
Create dto/BatchScreenRequest.java
Define 5 Java Record data shapes for the request and response
IDE COMPLETIONS
2
Build POST /batch-screen endpoint
Agent Mode writes the batch processing loop
AGENT MODE
3
Add GET /risk-report endpoint
Agent Mode adds the single-entity lookup
AGENT MODE
4
Generate & run the test suite
Agent Mode writes 6 JUnit 5 tests and runs them
AGENT MODE
5
Run locally & verify with curl
Start the server, hit the endpoints, see real JSON
TERMINAL
6
CLI review & open GitHub PR
Gemini CLI catches issues before merge, bot reviews the PR
CLI + GITHUB
7
Update GEMINI.md documentation
IDE Chat writes the docs for your new endpoints
IDE CHAT
" }, { "type": "explain", "title": "Before You Start — Prerequisites Checklist", "content": "
Verify These 4 Things Before Writing Any Code

If any of these checks fail, fix them first. Trying to build on a broken foundation wastes time.

1ucc-api is running and healthy
Start the server, then test the health endpoint:
$ cd ucc-api && mvn spring-boot:run
In a second terminal: curl http://localhost:8080/api/health → should return {\"status\": \"ok\"}
2All existing tests pass
Run from the ucc-api/ directory:
$ mvn test
... all tests should show PASSED ...
If tests fail here, fix them before continuing — adding new features on top of failing tests makes debugging much harder.
3GEMINI.md exists in ucc-api/
This file gives Gemini context about your project. Check it exists:
$ ls ucc-api/GEMINI.md
ucc-api/GEMINI.md
If it's missing, go back to Phase 01 (IDE Plugin Setup) and create it.
4Gemini Code Assist is active in VS Code
Open VS Code → look for the Gemini icon in the left sidebar (looks like a sparkle ✦). If it's not there, go to Extensions and install Gemini Code Assist. Sign in with your Google account.
All 4 checks pass? Great. Leave the server running in one terminal and open a second terminal for commands. Keep VS Code open with the ucc-api/ folder.
" }, { "type": "explain", "title": "Step 1 — Create dto/BatchScreenRequest.java (IDE Completions)", "content": "
1
Create the Data ModelsIDE COMPLETIONS

What are Java Record models? Think of them as data contracts — they define the exact shape of the JSON that comes in and goes out of your API. Spring Boot uses them to automatically validate inputs and generate the Swagger docs at /docs.

You need 5 models for this feature. Instead of typing them from scratch, you'll use IDE Completions — as you type the beginning of each class, Gemini ghost-texts the rest.

👤 YOU DO
  • Open VS Code, right-click the models/ folder → New File → name it batch.java
  • Type the first line of each import and the start of each class name
  • Press Tab to accept each ghost-text suggestion
  • Review that field names and types match what you expect
🤖 GEMINI DOES
  • Suggests the full import list as you type import jakarta.validation.constraints.*
  • Completes enum values when you start typing public enum RiskLevel {
  • Fills in field names and types for each Java Record model
  • Infers relationships between models based on what you already typed
WHAT IDE COMPLETIONS LOOK LIKE IN VS CODE
dto/BatchScreenRequest.java — IDE Ghost-Text
👤 You type
import jakarta.validation.constraints.* |cursor|
Gemini suggests (press Tab)
Java Record, Field
👤 You type
public enum RiskLevel {
Gemini suggests (press Tab)
LOW = \"LOW\"\n MEDIUM = \"MEDIUM\"\n HIGH = \"HIGH\"\n UNKNOWN = \"UNKNOWN\"
👤 You type
class BatchScreenRequest(Java Record):
Gemini suggests (press Tab)
entityNames: List<String> = Field(..., min_length=1, max_length=100)\n includeSignals: boolean = True
If ghost-text isn't appearing: Open the Gemini Chat panel (sidebar) and type: \"I'm creating models for a batch UCC risk screening API. Models needed: RiskLevel enum, RiskSignal, EntityRiskReport, BatchScreenRequest, BatchScreenResponse.\" This gives Gemini context and completions will start appearing.
Exact actions — follow in order:
In VS Code Explorer panel, right-click the models/ folder → New File → type batch.java → press Enter
Type import jakarta.validation.constraints.* — wait 1 second — Gemini shows a grey suggestion → press Tab
Type from typing import → Tab, then from enum import Enum
Type each class name — e.g., public enum RiskLevel { — Gemini fills in the body. Press Tab to accept, then write the next class.
Compare your result to the reference code below. Field names and types must match exactly. Formatting differences are OK.
✓ CHECKPOINT — run this to verify
# Java verify: \"mvn compile # verify BatchScreenRequest, BatchScreenResponse, EntityRiskReport, RiskSignal, RiskLevel; print('Step 1 complete')\"
Expected: Step 1 complete
" }, { "type": "code", "title": "dto/BatchScreenRequest.java — Reference Code (compare with your output)", "content": "// dto/RiskLevel.java\npackage com.ucc.api.dto;\n\npublic enum RiskLevel { LOW, MEDIUM, HIGH, UNKNOWN }\n\n// dto/RiskSignal.java\npublic record RiskSignal(\n String type,\n String description,\n String severity\n) {}\n\n// dto/EntityRiskReport.java\npublic record EntityRiskReport(\n String entityName,\n String normalizedName,\n RiskLevel riskLevel,\n java.util.List signals,\n int activeLienCount,\n double totalExposure\n) {}\n\n// dto/BatchScreenRequest.java\nimport jakarta.validation.constraints.NotEmpty;\nimport jakarta.validation.constraints.Size;\n\npublic record BatchScreenRequest(\n @NotEmpty @Size(max = 100)\n java.util.List entityNames\n) {}\n\n// dto/BatchScreenResponse.java\npublic record BatchScreenResponse(\n java.util.List reports,\n int totalScreened,\n int highRiskCount,\n int mediumRiskCount,\n int lowRiskCount\n) {}", "desc": "

👤 Developer: Compare your AI-generated output against this reference. Differences in variable names or formatting are acceptable — focus on whether the logic, imports, and key method signatures match.

🤖 AI Tool: Generated this code from your prompt and project context. The reference shows what a well-configured AI tool produces; use it as a quality baseline, not a strict target.

" }, { "type": "explain", "title": "Steps 2 & 3 — Build Both Endpoints with Agent Mode", "content": "
2
Build POST /batch-screenAGENT MODE

What is Agent Mode? It's Gemini's most powerful feature — unlike the Chat panel which just answers questions, Agent Mode can read your files and write code directly into them. It works like a junior developer: you give it a task, it reads the codebase, writes the code, runs the tests, and reports back.

👤 YOU DO (Steps 2 & 3)
  • Open Agent Mode in VS Code (Gemini icon → switch from Chat to Agent)
  • Copy-paste Prompt 1 below → press Enter → wait
  • When Agent finishes: read the diff, check the imports are correct
  • Copy-paste Prompt 2 → press Enter → wait
  • Check /docs in browser to see both new endpoints
🤖 GEMINI DOES (Steps 2 & 3)
  • Reads GEMINI.md, dto/BatchScreenRequest.java, FilingSearchService.java, NameNormalizerService.java
  • Adds the import block for MOCK_FILINGS and normalizeDebtorName
  • Writes the full batchScreen() function with normalization loop
  • Writes risk signal detection (ACTIVE_LIEN, MULTIPLE_CREDITORS)
  • Adds riskReport() endpoint, then runs JUnit 5 to verify
How to open Agent Mode: In VS Code, click the Gemini sparkle icon ✦ in the left sidebar. At the top of the panel, look for a dropdown or toggle that says \"Chat\" — click it and switch to \"Agent\". The Agent panel looks the same but has a note saying it can read and edit files.
Prompt 1 — POST /batch-screen endpoint
STEP 2 — AGENT MODE PROMPT 1 — copy and paste this exactly
Read GEMINI.md, dto/BatchScreenRequest.java, service/FilingSearchService.java, and service/NameNormalizerService.java.\n\nAdd a POST /batch-screen endpoint to UccApiApplication.java that does the following:\n- Import MOCK_FILINGS from services.FilingSearchService\n- Import normalizeDebtorName from services.normalizer\n- Import BatchScreenRequest, BatchScreenResponse, EntityRiskReport, RiskSignal, RiskLevel from models.batch\n- For each name in entityNames:\n - Normalize the name with normalizeDebtorName()\n - Find all matches in MOCK_FILINGS where normalizeDebtorName(f.debtorName) == normalized name\n - If matches found: create ACTIVE_LIEN signal (HIGH if 3+ matches, MEDIUM otherwise)\n - If more than 2 distinct securedParty values: add MULTIPLE_CREDITORS signal\n - Build an EntityRiskReport with the results\n- Return BatchScreenResponse with total/high_risk/medium_risk/low_risk counts\n\nWrap each entity in try/except — on error set risk_level UNKNOWN and error message.\nRun mvn test after writing the endpoint.
What to check in Agent Mode's output:
  • Imports — look for from services.FilingSearchService import MOCK_FILINGS and from services.normalizer import normalizeDebtorName at the top of UccApiApplication.java
  • Dot notation — Filing fields must be accessed as f.filingId, f.securedParty, f.lienRiskScore — NOT as dict keys like f['filingId']
  • If Agent used dict access, correct it: f['filingId']f.filingId (Filing is a Java Record model, not a dict)
✓ CHECKPOINT — run this to verify
curl -s http://localhost:8080/docs | jq . | head -5 # OR open http://localhost:8080/docs in browser
Expected: See /batch-screen listed in Swagger UI
3
Add GET /risk-report/{entity_name}AGENT MODE

This second endpoint is simpler — it looks up one company at a time. The key rule: return risk_level: UNKNOWN if the company isn't found. Never throw a 404, because \"not found\" is valid data (it means no liens).

STEP 3 — AGENT MODE PROMPT 2 — copy and paste this exactly
Add a GET /risk-report/{entity_name} endpoint to UccApiApplication.java.\n\nIt should:\n- Normalize entity_name with normalizeDebtorName()\n- Look up matches in MOCK_FILINGS where normalizeDebtorName(f.debtorName) == normalized name\n- If no matches: return EntityRiskReport with risk_level UNKNOWN, active_lien_count 0\n- If matches found: build signals list with ACTIVE_LIEN signal, return EntityRiskReport\n\nImportant: return the EntityRiskReport object directly (not raise HTTPException 404).\nRun mvn test after adding the endpoint.
✓ CHECKPOINT — run this to verify
curl http://localhost:8080/api/risk-report/acme%20transport%20llc
Expected: {\"input_name\":\"acme transport llc\",\"normalized_name\":\"ACME TRANSPORT\",\"risk_level\":\"MEDIUM\",...}
" }, { "type": "code", "title": "UccApiApplication.java — New Additions Reference (verify Agent Mode output)", "content": "// controller/BatchScreenController.java\npackage com.ucc.api.controller;\n\nimport com.ucc.api.dto.*;\nimport com.ucc.api.service.*;\nimport jakarta.validation.Valid;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.server.ResponseStatusException;\nimport java.util.*;\n\n@RestController\n@RequestMapping(\"/api\")\npublic class BatchScreenController {\n\n private final BatchScreenService batchService;\n\n public BatchScreenController(BatchScreenService svc) {\n this.batchService = svc;\n }\n\n @PostMapping(\"/batch-screen\")\n public BatchScreenResponse batchScreen(\n @Valid @RequestBody BatchScreenRequest request) {\n return batchService.screen(request);\n }\n\n @GetMapping(\"/risk-report/{entityName}\")\n public EntityRiskReport riskReport(\n @PathVariable String entityName) {\n return batchService.getReport(entityName)\n .orElseThrow(() -> new ResponseStatusException(\n HttpStatus.NOT_FOUND,\n \"No report for: \" + entityName));\n }\n}", "desc": "

👤 Developer: Compare your AI-generated output against this reference. Differences in variable names or formatting are acceptable — focus on whether the logic, imports, and key method signatures match.

🤖 AI Tool: Generated this code from your prompt and project context. The reference shows what a well-configured AI tool produces; use it as a quality baseline, not a strict target.

" }, { "type": "explain", "title": "Step 4 — Generate & Run the Test Suite (Agent Mode)", "content": "
4
Generate & Run TestsAGENT MODE

Why write tests? Tests verify your API behaves correctly — both for expected inputs (a known company) and edge cases (empty list, unknown company). Gemini will write the tests and run them, fixing failures before handing back to you.

👤 YOU DO
  • Copy-paste Prompt 3 into Agent Mode → press Enter
  • Watch Agent Mode generate tests/BatchScreenControllerTest.java
  • Watch it run JUnit 5 automatically
  • If all 6 tests pass: you are done with this step
🤖 GEMINI DOES
  • Creates tests/BatchScreenControllerTest.java with 6 test functions
  • Uses Spring Boot MockMvc to make real HTTP calls
  • Tests both happy paths (found) and edge cases (not found, empty input)
  • Runs JUnit 5 and fixes any assertion errors it finds
STEP 4 — AGENT MODE PROMPT 3 — copy and paste this exactly
Read UccApiApplication.java and dto/BatchScreenRequest.java.\nGenerate tests/BatchScreenControllerTest.java with exactly these 6 test functions:\n\n1. testBatchScreenfound\n POST /batch-screen with [\"Acme Transport LLC\"]\n Assert: status 200, total==1, normalized_name==\"ACME TRANSPORT\", active_lien_count >= 1\n\n2. testBatchScreennot_found\n POST /batch-screen with [\"Nonexistent Corp XYZ 99999\"]\n Assert: status 200, risk_level==\"LOW\", active_lien_count==0\n\n3. testBatchScreenmultiple\n POST /batch-screen with [\"Acme Transport LLC\", \"Unknown Co\", \"Lone Star Freight Inc\"]\n Assert: status 200, total==3\n\n4. testBatchScreenempty_list\n POST /batch-screen with {\"entityNames\": []}\n Assert: status 400 (Java Record rejects empty list — this is correct behavior, not a bug)\n\n5. testRiskReport_normalized_match\n GET /risk-report/acme transport, llc (note the comma and lowercase)\n Assert: status 200, normalized_name==\"ACME TRANSPORT\"\n (This proves normalizeDebtorName() strips punctuation and suffixes)\n\n6. testRiskReport_not_found\n GET /risk-report/totally unknown entity 12345\n Assert: status 200, risk_level==\"UNKNOWN\"\n (This proves we return UNKNOWN not 404)\n\nUse Spring Boot MockMvc. Run mvn test after generating.
Understanding the 400 test (testBatchScreenempty_list)

A 400 status means Unprocessable Entity — the input failed validation before your code even ran. Java Record rejects an empty list because min_length=1 in BatchScreenRequest. This is correct behavior — returning 400 instead of 500 means your validation is working. The test asserts 400 on purpose.

✓ CHECKPOINT — run this to verify
mvn test
Expected: 6 passed (BatchScreenControllerTest.java) + all previous tests still passing
" }, { "type": "code", "title": "tests/BatchScreenControllerTest.java — Reference (compare with Agent Mode output)", "content": "// test/BatchScreenControllerTest.java\npackage com.ucc.api;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.MockMvc;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;\n\n@SpringBootTest\n@AutoConfigureMockMvc\nclass BatchScreenControllerTest {\n\n @Autowired MockMvc mockMvc;\n\n @Test\n void batchScreenFound() throws Exception {\n String json = \"\"\"\n {\"entityNames\":[\"Acme Transport LLC\"]}\"\"\";\n mockMvc.perform(post(\"/api/batch-screen\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(json))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.totalScreened\").value(1));\n }\n\n @Test\n void batchScreenNotFound() throws Exception {\n String json = \"\"\"\n {\"entityNames\":[\"Ghost Corp XYZ\"]}\"\"\";\n mockMvc.perform(post(\"/api/batch-screen\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(json))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.reports[0].riskLevel\")\n .value(\"UNKNOWN\"));\n }\n\n @Test\n void batchScreenMultiple() throws Exception {\n String json = \"\"\"\n {\"entityNames\":[\"Acme Transport LLC\",\n \"Lone Star Logistics Corp\"]}\"\"\";\n mockMvc.perform(post(\"/api/batch-screen\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(json))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.totalScreened\").value(2));\n }\n\n @Test\n void batchScreenEmptyList() throws Exception {\n String json = \"\"\"\n {\"entityNames\":[]}\"\"\";\n mockMvc.perform(post(\"/api/batch-screen\")\n .contentType(MediaType.APPLICATION_JSON)\n .content(json))\n .andExpect(status().isBadRequest());\n }\n\n @Test\n void riskReportByName() throws Exception {\n mockMvc.perform(get(\"/api/risk-report/Acme+Transport+LLC\"))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.normalizedName\")\n .value(\"ACME TRANSPORT\"));\n }\n\n @Test\n void riskReportNotFound() throws Exception {\n mockMvc.perform(get(\"/api/risk-report/Ghost+Corp\"))\n .andExpect(status().isNotFound());\n }\n}", "desc": "

👤 Developer: Compare your AI-generated output against this reference. Differences in variable names or formatting are acceptable — focus on whether the logic, imports, and key method signatures match.

🤖 AI Tool: Generated this code from your prompt and project context. The reference shows what a well-configured AI tool produces; use it as a quality baseline, not a strict target.

" }, { "type": "explain", "title": "Step 5 — Run Locally & Verify with curl", "content": "
5
Run Locally & Test LiveTERMINAL

Tests pass, but let's see the real JSON from a live running server. This step gives you confidence that the API works end-to-end, not just in the test harness.

Start the server (if it's not already running):
Terminal 1 — keep this running
$ cd ucc-api && mvn spring-boot:run
Started UccApiApplication in 2.3 seconds (Press CTRL+C to quit)
INFO: Application startup complete.
Test 1 — Batch screen with known + unknown company:
Terminal 2 — curl commands
$ curl -s -X POST http://localhost:8080/api/batch-screen \n  -H \"Content-Type: application/json\" \n  -d '{\"entityNames\": [\"Acme Transport LLC\", \"Unknown Company XYZ\"]}'

Expected response:
{\"total\":2, \"high_risk\":0, \"medium_risk\":1, \"low_risk\":1,
  \"reports\":[{\"input_name\":\"Acme Transport LLC\", \"normalized_name\":\"ACME TRANSPORT\",
    \"risk_level\":\"MEDIUM\", \"active_lien_count\":2, ...}, ...]}
Test 2 — Risk report with name that needs normalization:
$ curl -s http://localhost:8080/api/risk-report/acme%20transport%2C%20llc

Expected response:
{\"input_name\":\"acme transport, llc\", \"normalized_name\":\"ACME TRANSPORT\",
  \"risk_level\":\"MEDIUM\", \"active_lien_count\":2, \"signals\":[...]}
Test 3 — Swagger UI (no curl needed):
Open http://localhost:8080/docs in your browser. You should see 5 endpoints total: GET /health, POST /search, GET /filings/{id}, POST /batch-screen, GET /risk-report/{entity_name}. Click any endpoint → Try it out → fill in test data → Execute.
Common issues:
CompilationError: cannot import name 'MOCK_FILINGS' → MOCK_FILINGS must be at module level in FilingSearchService.java (outside the SearchService class)
NoSuchMethodError: 'dict' object has no attribute 'filingId' → Agent Mode used dict access. Change f['filingId']f.filingId
400 Unprocessable Entity on a valid request → check that entityNames is a list, not a string
✓ CHECKPOINT — run this to verify
curl -s http://localhost:8080/api/batch-screen -X POST -H \"Content-Type: application/json\" -d '{\"entityNames\":[\"Acme Transport LLC\"]}' | jq .
Expected: \"risk_level\": \"MEDIUM\"
" }, { "type": "scenario", "title": "Steps 6 & 7 — CLI Review, GitHub PR & Update GEMINI.md", "desc": "

👤 Developer: Walk through this scenario with a real (or test) repository to verify the workflow end-to-end. Note any steps where your team's process differs from what is shown.

🤖 AI Tool: Can simulate portions of this workflow when asked. Use it to draft the PR description, generate review comments, or explain what each automation step does.

", "content": "

Step 6A — Gemini CLI Code Review

Run the Gemini CLI from the ucc-api/ directory to review your code before opening the PR:

$ gemini -f UccApiApplication.java \n  \"Review the batchScreen and riskReport endpoints I just added.
  Check for:
  1. Input validation gaps — what if entityNames contains empty strings?
  2. Error handling — what if normalizeDebtorName() throws?
  3. Performance — 100 names x full scan of MOCK_FILINGS.
  4. Any edge cases I haven't handled?\"

Read the output carefully. Fix any HIGH severity issues before opening the PR.

Typical suggestions Gemini makes:
  • Strip whitespace: name.trim() before normalizeDebtorName()
  • Guard against None: Objects.requireNonNullElse(f.lienRiskScore(), 0.0)
  • Deduplicate entityNames before processing

Step 6B — Open the GitHub Pull Request

$ git checkout -b feature/batch-risk-screening
$ git add dto/BatchScreenRequest.java tests/BatchScreenControllerTest.java UccApiApplication.java
$ git commit -m \"feat: add POST /batch-screen and GET /risk-report endpoints\"
$ git push origin feature/batch-risk-screening

Go to GitHub \u2192 open a PR from feature/batch-risk-screening \u2192 main. Within a few minutes the Gemini bot will post a review.

The bot typically catches:
  • \u2705 Missing input validation (empty strings in entityNames)
  • \u2705 UNKNOWN risk level not counted in summary
  • \u2705 lienRiskScore is Double — guard against None

Step 7 — Update GEMINI.md (IDE Chat)

Open the Gemini Chat panel in VS Code (not Agent Mode) and paste:

\u{1F4AC} Gemini Chat
Read GEMINI.md and UccApiApplication.java. Add a section called ## New Endpoints to GEMINI.md that documents:
\u2022 POST /batch-screen: what it does, request schema, response schema, one curl example
\u2022 GET /risk-report/{entity_name}: what it does, when it returns UNKNOWN vs MEDIUM/HIGH
Keep it concise — bullet points, not paragraphs.

Review Gemini’s suggestion, accept it, save the file, and commit as part of the PR.

\u2705 Checkpoint: Your PR should contain: dto/BatchScreenRequest.java, updated UccApiApplication.java, tests/BatchScreenControllerTest.java, and updated GEMINI.md. The Gemini GitHub bot should have posted at least one review comment.
" }, { "type": "scenario", "title": "Final Checklist — 10 Items Before You Call It Done", "desc": "

👤 Developer: Work through this top to bottom. Every item tests something different. Don't skip — the items near the bottom catch issues the items above can miss.

🤖 AI Tool: Can assist at each decision point. Describe your specific situation when the scenario diverges from your project context — the AI adapts its guidance.

", "content": "
\u2705 Complete all 10 items before calling the capstone done. Each item verifies a Gemini capability you used during this course.
\u2610
1. mvn spring-boot:run starts with no compilation errors
\u2192 check all imports at the top of UccApiApplication.java exist in their source files
\u2610
2. GET /health still returns {\"status\": \"ok\"}
\u2192 Agent Mode must not have deleted or broken existing endpoints
\u2610
3. /docs shows exactly 5 endpoints including /batch-screen and /risk-report
\u2192 check that both @PostMapping and @GetMapping annotations are in UccApiApplication.java
\u2610
4. POST /batch-screen accepts a JSON list of entity names and returns risk reports
\u2192 verify the request DTO matches the @RequestBody parameter type
\u2610
5. GET /risk-report/{entity_name} returns a single EntityRiskReport
\u2192 check that the path parameter name matches the function argument
\u2610
6. mvn test shows all tests passing (including BatchScreenControllerTest.java)
\u2192 if tests fail, read the assertion error — usually a field name mismatch
\u2610
7. GEMINI.md contains a ## New Endpoints section documenting /batch-screen and /risk-report
\u2192 if missing, paste the Gemini Chat prompt from Step 7 and accept the output
\u2610
8. git log shows at least 2 commits: one for the feature, one for GEMINI.md
\u2192 squash is fine too — the point is that changes are committed and traceable
\u2610
9. The GitHub PR has at least one gemini-code-assist[bot] review comment
\u2192 if no bot comment after 5 minutes, check the .gemini/config.yaml file
\u2610
10. You can explain what each file does to a teammate without reading the code
\u2192 if not, re-read the capstone overview — understanding is the real deliverable
" }, { "type": "explain", "title": "Capstone Complete — What You Learned", "content": "
You just used every Gemini Code Assist feature end-to-end

Here's what you actually did in each step and which phase of the course it came from.

🔧
Phase 01
Set up GEMINI.md so Gemini knows your project before every session
Plugin Setup
Phase 02
IDE ghost-text wrote your Java Record models as you typed class names
Completions
💬
Phase 02
Chat panel provided context when completions weren't triggering
Chat Panel
🤖
Phase 03
Agent Mode built both endpoints and ran tests autonomously
Agent Mode
🖥️
Phase 04
CLI pre-PR review caught input validation and null-check issues
Gemini CLI
🔍
Phase 05
GitHub bot reviewed the PR and flagged schema edge cases
GitHub PR
📋
Phase 06
Jira ticket auto-transitioned to Done when PR was merged
Jira
🔌
Phase 07
MCP server gave Agent Mode live access to filing data context
MCP Servers
🏛️
Phase 08
Governance review approved the batch-screen endpoint for production
Governance
The key insight from this capstone: You didn't write 200 lines of code from scratch — you wrote 4 prompts. Gemini read your existing code, understood the patterns, and generated code that fit your architecture. Your job was to define what to build, review the output, and verify it works. That's a fundamentally different — and more powerful — way to develop software.
" }, { "type": "explain", "title": "Gemini Code Assist — GCP Architecture", "content": "
Gemini Code Assist in the GCP Ecosystem
💻
VS Code
IDE + extension
🤖
Gemini Extension
inline suggestions
☁️
Cloud AI APIs
Gemini Pro model
📋
Codebase Index
full awareness
🚀
GCP Services
BigQuery · Run · GKE
Full Codebase Awareness
Unlike tab-completion tools, Gemini Code Assist indexes your entire repository. When you ask it to “add a new endpoint consistent with the existing pattern”, it actually reads your existing code first.
" }, { "type": "explain", "title": "Common Mistakes", "content": "
⚠️ Common Mistakes & How to Fix Them
  • Accepting all suggestions without review: Gemini can suggest outdated APIs or incorrect imports. Always verify each suggestion before accepting.
  • Vague prompts: \"Fix the bug\" tells Gemini nothing. Describe what the code should do, what input it receives, and what output you expect.
  • Not indexing your codebase: Full Codebase Awareness requires the project to be indexed in Cloud Shell or the IDE extension. Trigger indexing after adding new files.
  • Pasting secrets into Gemini chat: Never send API keys, credentials, or PII to any AI chat interface. Use environment variables or Secret Manager.
  • Skipping test generation: Always use Smart Actions → Generate Tests after writing new functions. Untested AI-generated code hides edge-case bugs.
" }, { "type": "quiz", "title": "Knowledge Check", "questions": [ { "q": "Gemini Code Assist is primarily integrated into which IDE?", "opts": [ "IntelliJ IDEA", "Atom", "VS Code", "Eclipse" ], "ans": 2 }, { "q": "What Gemini feature provides AI suggestions with awareness of your whole codebase?", "opts": [ "Smart Actions", "Full Codebase Awareness", "Cloud Assist", "Code Lens" ], "ans": 1 }, { "q": "Which GCP service provides serverless SQL analytics on large datasets?", "opts": [ "Cloud SQL", "Spanner", "BigQuery", "Dataflow" ], "ans": 2 }, { "q": "Gemini Smart Actions can do which of the following?", "opts": [ "Deploy to Cloud Run", "Explain code, generate tests and fix bugs inline", "Manage IAM policies", "Set up billing alerts" ], "ans": 1 }, { "q": "Which file is equivalent to CLAUDE.md but used with Gemini Code Assist?", "opts": [ "gemini.json", "gemini.md", "ai-context.yaml", "codebase.md" ], "ans": 1 } ] }, { "type": "explain", "title": "✅ Post-Course Assessment", "content": "

Five scenario-based questions testing how you apply the concepts from this course. Select the best answer for each.

Question 1 of 5
You ask Gemini to generate a UCC filing search function. It uses debtorName instead of debtorName as defined in your canonical schema. What prevents this in future prompts?
Question 2 of 5
Gemini generates 15 unit tests for your risk score function. 14 pass, 1 fails on a debtor with 0 active filings. What should you do?
Question 3 of 5
You ask Gemini to explain a 300-line legacy parser. It says: \"This function standardises names using a lookup table.\" You see only regex substitutions — no lookup table. What does this tell you?
Question 4 of 5
After using Gemini to refactor a module, your PR is 800 lines of changes. Your team typically reviews PRs under 200 lines. What should you do before submitting?
Question 5 of 5
Gemini suggests SELECT * in a BigQuery query against a Gold table with 50 columns. You need only 8. What is the risk and correct prompt fix?
" } ] } ]; let state={screen:"landing",activePhase:0}; function render(){document.getElementById('app').innerHTML=state.screen==='landing'?renderLanding():renderCourse();attachEvents();} function renderLanding(){const mp=PHASES.filter(p=>p.id!=='intro');const pills=mp.map((p,i)=>`
${p.icon} ${p.title}${p.sections.filter(s=>s.type!=='explain').length}\u2192
`).join('');return`
AI-Driven SDLC · Gemini Code Assist Edition

Gemini Code Assist — AI Pair Programming

Master Google’s AI coding assistant from IDE completions to autonomous Agent Mode. Learn to use the Gemini CLI, automate GitHub PR reviews, connect MCP servers, and apply enterprise governance controls across the full SDLC.

${pills}
Click any phase to jump directly, or start from the introduction
💻 8 Phases💬 7+ AI Prompts🤖 Agent Mode🛡️ Enterprise Controls
🧠
IDE Integration
Inline completions, chat sidebar, and full Agent Mode in VS Code and JetBrains
Agent Mode
Multi-step autonomous coding — plan, write, test, and iterate without leaving your IDE
🔧
Gemini CLI + MCP
Terminal-native AI with MCP server plugins for BigQuery, GitHub, and Jira
📋
GitHub PR Reviews
Automated AI code review on every pull request with context-aware suggestions
16 Jump \u00b7 \u2190\u2192 Nav \u00b7 Esc Home
`;} function renderCourse(){const p=PHASES[state.activePhase];return`
${renderHeader(p)}
${renderProgress()}
${renderPhaseHeader(p)}${p.sections.map((s,i)=>renderSection(s,i,p.color)).join('')}${renderPhaseQuiz(p)}${renderFooterNav(p)}
`;} function renderHeader(p){return`
|AI-SDLC GEMINI\u203a${p.icon} ${p.title}
${state.activePhase===0?'Introduction':'Phase '+state.activePhase+' of '+(PHASES.length-1)}
`;} function renderProgress(){return PHASES.map((p,i)=>{const isA=i===state.activePhase,isD=i`:'';return`
${isD?'\u2713':p.icon}
${line}`;}).join('');} function renderSidebar(){const tmap={explain:'LEARN',prompt:'PROMPT',code:'CODE',config:'CFG',output:'OUT',scenario:'CASE'};return PHASES.map((p,i)=>{const isA=i===state.activePhase;let h=``;if(isA){h+=`
${p.sections.map((s,si)=>{const m=s.content?.match(/([^<]{2,80})<\/strong>/);const raw=m?m[1]:s.title||'';const lbl=raw.replace(/<[^>]+>/g,'').trim().slice(0,38)||tmap[s.type]||'Section';return`
${tmap[s.type]||'NOTE'}${lbl}
`;}).join('')}
`;}return h;}).join('');} function renderPhaseHeader(p){const explains=p.sections.filter(s=>s.type==='explain').length;const prompts=p.sections.filter(s=>s.type==='prompt').length;const codes=p.sections.filter(s=>s.type==='code'||s.type==='config').length;const scenarios=p.sections.filter(s=>s.type==='scenario').length;const words=p.sections.reduce((a,s)=>a+(s.content||'').replace(/<[^>]+>/g,'').split(/\s+/).length,0);const mins=Math.max(1,Math.round(words/200));var lvl=p.id==='intro'?'beginner':p.num<=3?'beginner':p.num<=6?'intermediate':'advanced';var lvlLabel=lvl==='beginner'?'\u{1F7E2} Beginner':lvl==='intermediate'?'\u{1F7E1} Intermediate':'\u{1F534} Advanced';const meta=`
${explains?`${explains} Concepts`:''} ${prompts?`${prompts} Prompts`:''} ${codes?`${codes} Code Samples`:''} ${scenarios?`${scenarios} Scenarios`:''}~${mins} min read
`;return`
${p.icon}
${p.id==='intro'?'Introduction':'Phase '+p.num}
${p.title}
${p.description}
${meta}${lvlLabel}
`;} function renderSection(s,idx,color){if(s.type==='explain'){const m=s.content.match(/([^<]{2,100})<\/strong>/);const t=m?m[1]:'Overview';const id='s-'+idx;return`
${s.content}
`;};const types={prompt:{accent:'#f59e0b',bg:'rgba(245,158,11,.05)',label:'PROMPT'},code:{accent:'#10b981',bg:'rgba(16,185,129,.05)',label:'CODE'},config:{accent:'#8b5cf6',bg:'rgba(139,92,246,.05)',label:'CONFIG'},output:{accent:'#06b6d4',bg:'rgba(6,182,212,.05)',label:'OUTPUT'},scenario:{accent:'#ec4899',bg:'rgba(236,72,153,.05)',label:'SCENARIO'}};if(s.type==='quiz')return renderQuiz(s,color);const t=types[s.type]||types.code;const id='s-'+idx;let body='';if(s.type==='code'||s.type==='config'){body=`
${s.lang||'code'}${s.label?`${s.label}`:''}
${esc(s.content)}
`;}else if(s.type==='prompt'){body=`
${s.label?`
${s.label}
`:''}
${esc(s.content)}
`;}else if(s.type==='scenario'){body=`
${s.content}
`;}else{body=`
${esc(s.content)}
`;}const descHtml=s.desc?`
${s.desc}
`:'';return`
${s.type==="config"?body+descHtml:descHtml+body}
`;} function renderQuiz(s,color){const qid='qz'+Math.random().toString(36).slice(2);const qs=s.questions||[];const qsHtml=qs.map(function(q,qi){const optsHtml=q.opts.map(function(o,oi){return '';}).join('');return '
'+q.q+'
'+optsHtml+'
';}).join('');return '
✏️ '+(s.title||'Knowledge Check')+'
'+qsHtml+'
';} function renderPhaseQuiz(p){return '';} function renderFooterNav(p){const isF=state.activePhase===0,isL=state.activePhase===PHASES.length-1;const nx=PHASES[state.activePhase+1];const nl=isL?'\u2713 Course Complete — Back to Home':'Next: '+(nx?nx.title:'')+' \u2192';const nb=isL?'linear-gradient(135deg,#10b981,#06b6d4)':(nx?nx.gradient:p.gradient);return``;} function esc(s){return s.replace(/&/g,'&').replace(//g,'>');} window.startCourse=function(){state.screen='course';state.activePhase=0;render();}; window.goHome=function(){state.screen='landing';render();}; window.jumpToPhase=function(i){state.activePhase=i;state.screen='course';render();document.getElementById('cs')?.scrollTo({top:0,behavior:'smooth'});}; window.goPhase=function(i){state.activePhase=i;render();document.getElementById('cs')?.scrollTo({top:0,behavior:'smooth'});}; window.prevPhase=function(){if(state.activePhase>0){state.activePhase--;render();document.getElementById('cs')?.scrollTo({top:0,behavior:'smooth'});}}; window.nextPhase=function(){if(state.activePhaseb.classList.remove('section-body-open'),300);c.classList.add('open');c.setAttribute('aria-expanded','true');}else{b.style.display='none';c.classList.remove('open');c.setAttribute('aria-expanded','false');}}; window.scrollToSection=function(id){const el=document.getElementById(id);if(el){const b=document.getElementById(id+'-b');const c=document.getElementById(id+'-c');if(b&&b.style.display==='none'){b.style.display='';b.classList.add('section-body-open');setTimeout(()=>b.classList.remove('section-body-open'),300);if(c)c.classList.add('open');}el.scrollIntoView({behavior:'smooth',block:'start'});}}; window.copyCode=function(i){const e=document.getElementById('cd-'+i),b=document.getElementById('cp-'+i);if(e&&b){navigator.clipboard?.writeText(e.textContent);b.textContent='\u2713 Copied';b.classList.add('copied');setTimeout(()=>{b.textContent='Copy';b.classList.remove('copied');},2000);}}; function attachEvents(){document.onkeydown=function(e){if(e.key==='ArrowRight'){e.preventDefault();if(state.screen==='course'&&state.activePhase0){state.activePhase--;render();document.getElementById('cs')?.scrollTo({top:0,behavior:'smooth'});}}else if(e.key==='Escape'){goHome();}const n=parseInt(e.key);if(n>=1&&n<=8)jumpToPhase(n);if(e.key==='0')jumpToPhase(0);};} // ── localStorage phase progress ── const PROG_KEY='gemini-progress'; function loadProgress(){try{return JSON.parse(localStorage.getItem(PROG_KEY)||'{}')}catch{return{}}} function saveProgress(id,done){const p=loadProgress();p[id]=done;localStorage.setItem(PROG_KEY,JSON.stringify(p))} function isDone(id){return!!loadProgress()[id]} function togglePhaseComplete(id){ const now=!isDone(id); saveProgress(id,now); const btn=document.getElementById('pcb-'+id); if(btn){btn.classList.toggle('done',now);const c=btn.querySelector('.chk');if(c)c.textContent=now?'\u2713':'';} const dot=document.querySelector('.sidebar-dot[data-id="'+id+'"]'); if(dot)dot.classList.toggle('done',now); if(now)launchConfetti(); } function initProgress(){ const p=loadProgress(); PHASES.forEach(ph=>{ const done=!!p[ph.id]; const btn=document.getElementById('pcb-'+ph.id); if(btn){btn.classList.toggle('done',done);const c=btn.querySelector('.chk');if(c)c.textContent=done?'\u2713':'';} const dot=document.querySelector('.sidebar-dot[data-id="'+ph.id+'"]'); if(dot)dot.classList.toggle('done',done); }); } function launchConfetti(){ const canvas=document.getElementById('confetti-canvas'); if(!canvas)return; const ctx=canvas.getContext('2d'); canvas.width=window.innerWidth;canvas.height=window.innerHeight; canvas.style.display='block'; const pieces=[]; const colors=['#63b3ed','#4fd1c5','#22c55e','#f59e0b','#ec4899','#a78bfa']; for(let i=0;i<120;i++){pieces.push({x:Math.random()*canvas.width,y:-10,r:Math.random()*6+3,c:colors[Math.floor(Math.random()*colors.length)],s:Math.random()*3+2,a:Math.random()*Math.PI*2,spin:Math.random()*.1-.05});} let frame=0; function draw(){ ctx.clearRect(0,0,canvas.width,canvas.height); pieces.forEach(p=>{ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.a);ctx.fillStyle=p.c;ctx.fillRect(-p.r,-p.r/2,p.r*2,p.r);ctx.restore();p.y+=p.s;p.x+=Math.sin(p.a)*.5;p.a+=p.spin;}); for(let i=pieces.length-1;i>=0;i--){if(pieces[i].y>canvas.height)pieces.splice(i,1);} frame++; if(pieces.length>0&&frame<300)requestAnimationFrame(draw); else{ctx.clearRect(0,0,canvas.width,canvas.height);canvas.style.display='none';} } draw(); } render(); initProgress(); /* ── Phase 2/3 Enhancements: DYK + GWT + Roles + Prism auto-highlight ── */ function getLang(l){var m={python:"python",yaml:"yaml",bash:"bash",shell:"bash",json:"json",sql:"sql",java:"java",markdown:"markdown",md:"markdown",typescript:"typescript",ts:"typescript",tsx:"tsx",jsx:"jsx",javascript:"javascript",js:"javascript",html:"html",css:"css",groovy:"groovy",kotlin:"kotlin",csharp:"csharp",cs:"csharp",dockerfile:"dockerfile",docker:"bash"};return m[(l||"bash").toLowerCase()]||"bash";} var _DYK=['Over 3.5 million UCC-1 filings are processed annually across all 50 US states. Filing perfects in the state where the company was legally formed — not where it operates.','The §9-503 Debtor Name Rule requires the name to exactly match legal formation documents. A misplaced comma or abbreviation can render a lien seriously misleading and unenforceable against other creditors.','A UCC-1 lien lapses automatically after 5 years unless the secured party files a UCC-3 Continuation within the 6-month window before expiration — even for active loans.','The First-to-File Rule (§9-322) gives priority to whoever files first — not who lent first. Two creditors can fund the same entity; only the first to file has senior claim on collateral.','Blanket liens describe collateral as all assets, now owned or hereafter acquired — giving a single lender claim over everything: inventory, receivables, IP, equipment, and future acquisitions.','PMSI super-priority (§9-324): a Purchase Money Security Interest beats even a prior blanket lien if perfected within 20 days of collateral delivery to the debtor.','The Medallion Architecture (Bronze→Silver→Gold) maps perfectly to UCC data: Bronze = raw SOS filings, Silver = standardized records, Gold = entity risk scores ready for decision engines.','AI coding assistants now write roughly 40–55% of new code at teams using Gemini Code Assist or Claude Code — but senior engineers own architecture, review, and the final Accept click.','Entity resolution is the hardest problem in UCC data: multiple name variants for the same legal entity require fuzzy match scoring, EIN lookups, and manual review queues.']; function _dykInject(){try{var blocks=document.querySelectorAll('.explain-block');if(!blocks.length)return;var idx=typeof state!=='undefined'&&state.activePhase!=null?state.activePhase:0;[0,2].forEach(function(bi){var el=blocks[bi];if(el&&!el.querySelector('.dyk-box')){var f=_DYK[(idx+bi*4)%_DYK.length];el.insertAdjacentHTML('beforeend','

'+f+'

');}});}catch(e){}} function _rolesSet(){try{var sb=document.querySelector('.sidebar');if(sb&&!sb.getAttribute('role'))sb.setAttribute('role','navigation');var ct=document.getElementById('cs')||document.querySelector('.content');if(ct&&!ct.getAttribute('role'))ct.setAttribute('role','main');var hd=document.querySelector('.app-header');if(hd&&!hd.getAttribute('role'))hd.setAttribute('role','banner');}catch(e){}} function _p23(){_dykInject();_rolesSet();} window.addEventListener('load',function(){if(window.Prism)Prism.highlightAll();_p23();}); (function(){var el=document.getElementById('app');if(!el)return;new MutationObserver(function(){if(window.Prism)setTimeout(function(){Prism.highlightAll();},0);_p23();}).observe(el,{childList:true});_p23();})();
📖 Glossary
Gemini Code Assist
Google's AI coding assistant integrated in IDEs and Cloud Workbench, providing completions, chat, and autonomous Agent Mode.
Code Completion
AI prediction of the next code tokens as you type, shown as ghost text before you accept the suggestion.
Inline Suggestion
Ghost-text code proposals shown in the editor — press Tab to accept, Escape to dismiss.
Smart Actions
Context-menu AI operations available by right-clicking code: explain, fix, generate tests, add docs, and more.
Chat Panel
Conversational AI interface inside the IDE for Q&A, code generation, and multi-turn context-aware assistance.
Agent Mode
Autonomous multi-step mode where Gemini reads your codebase, proposes a plan, and executes file changes with your approval.
Medallion Architecture
Bronze → Silver → Gold data pipeline pattern: raw ingestion, cleaned/validated, and business-ready aggregated data tiers.
PySpark
Python API for Apache Spark, used for distributed data processing across large datasets in Dataproc clusters.
BigQuery
Google's serverless, highly scalable cloud data warehouse — query petabytes of data using standard SQL.
Dataproc
Google Cloud managed Spark/Hadoop service that provisions clusters, runs jobs, and auto-scales without manual setup.
Cloud Composer
Google's managed Apache Airflow service for orchestrating data workflows using Python DAG definitions.
DAG (Directed Acyclic Graph)
Airflow workflow definition that specifies tasks and their dependencies — no cycles allowed, tasks run in dependency order.
Data Lineage
Tracking the flow and transformation of data from its source through each processing stage to its final destination.
Schema Validation
Automated checks that incoming data matches expected field names, types, and constraints before processing continues.
OpenSpec
AI-agent specification system that defines field-level contracts between teams, consumed by Gemini and Claude as structured context.
CI/CD
Continuous Integration / Continuous Delivery — automated pipeline that builds, tests, and deploys code on every commit.