AS26 : Session 5A

Post-Factory Debrief +
Software Architecture

Processing your Factory 2026 experience, then learning how to architect production-quality AI-powered Earth Observation applications.

📅 Friday, June 12, 2026
🕙 10:00 - 12:00
📍 ISU, Strasbourg
⏱️ 120 min
Factory Debrief

Reflecting on Factory 2026

💡
"What feedback did you receive? What surprised you?"

Take 2 minutes to think quietly. Then share one thing with the person next to you.

Key Questions to Ask Yourself

  • Which parts of your pitch resonated most with the audience?
  • Where did judges or mentors push back hardest?
  • Did anyone compare your project to an existing solution?
  • What was the most unexpected comment you received?
  • How did it feel to pitch under time pressure?
ℹ️ Factory feedback is gold. Even harsh criticism points to real weaknesses in your pitch or concept. The goal is not to defend your idea; it is to strengthen it.
Factory Debrief

Common Patterns from Investor Feedback

Regardless of industry, investors and judges tend to ask the same core questions. Did you hear any of these?

💡 For your AS26 project, answering "Who is the target user?" and "How is this different?" well will be the difference between a good demo and a great one.
Factory Debrief

Pivoting vs. Persisting

After receiving feedback, every team faces a decision: do we change course, or push forward? Both can be correct. The key is knowing which signals warrant a pivot.

🔄 Signs You Should Pivot

  • Multiple reviewers said the problem is not real or not urgent
  • An existing, free solution already does exactly what you propose
  • The data you need does not exist or is inaccessible
  • Your team lacks the technical skills for the core feature, and 5 days is not enough to learn
  • Nobody can clearly explain who benefits

🎯 Signs You Should Persist

  • Feedback focused on presentation, not the idea itself
  • Judges said "interesting" and asked follow-up questions
  • The technical approach is feasible within your team's skills
  • You have a clear, specific user in mind
  • The criticism was about scope: "this is too big" (which means you can narrow it)
⚠️ A pivot does not mean starting over. It often means keeping 80% of your work and changing the framing, the user target, or one key feature. Small pivots save projects.
Activity

5-Minute Reflection

✍️
Write Down 3 Key Takeaways from Factory 2026
Use a notebook, laptop, or sticky notes. Be specific, not generic.

Guiding Prompts

  1. Takeaway 1: What is the single most actionable piece of feedback you received?
  2. Takeaway 2: What assumption about your project was challenged?
  3. Takeaway 3: What will you do differently in your project this week because of Factory?
5:00
Architecture

The Three Layers of an AI-EO Web App

Every AI-powered Earth Observation application can be decomposed into three conceptual layers. This is a simplified form of layered architecture[1], adapted for the specific needs of geospatial AI applications. Research on engineering AI-based systems confirms that separating data, model, and interface concerns is critical for maintainability[7].

🖥️ Presentation Layer
🧠 Intelligence Layer
🛰️ Data Layer
1 Presentation Layer
What the user sees and interacts with: HTML/CSS/JS, LeafletJS map, chat interface, control panels, and data visualizations.
2 Intelligence Layer
The AI "brain": API calls to Gemini or Groq, function calling definitions, prompt templates, response parsing, and tool orchestration.
3 Data Layer
The information backbone: satellite imagery APIs (Sentinel Hub, STAC), GeoJSON storage, user-generated data, and cached responses.
Architecture

Layer Deep-Dive: What Lives Where

🖥️ Presentation Layer

  • LeafletJS map initialization and controls
  • Chat input/output rendering
  • Layer toggles, legends, toolbars
  • CSS themes and responsive layout
  • Loading spinners, skeleton screens

🧠 Intelligence Layer

  • Gemini API or Groq API client
  • System prompt and context management
  • Function calling tool definitions
  • Response parsing (text, JSON, GeoJSON)
  • Conversation history management

🛰️ Data Layer

  • Sentinel Hub / STAC API integration
  • OpenWeatherMap, NASA Earthdata, etc.
  • GeoJSON file loading and caching
  • User-drawn geometry storage
  • localStorage for persistence
ℹ️ Key insight: Each layer should be able to change independently. If you swap Gemini for Groq, the map code should not need to change.
Architecture

MVC Pattern Adapted for AI Apps

The Model-View-Controller (MVC) pattern, first conceived by Trygve Reenskaug at Xerox PARC in 1979[2] and later formalized for Smalltalk-80 by Krasner and Pope[3], maps naturally to AI-EO applications. Here is how the classic triad translates:

📦 Model (State + Data)

  • Conversation history array
  • Map layer states
  • Cached API responses
  • User preferences
  • GeoJSON feature collections

👁️ View (UI Rendering)

  • Chat message bubbles
  • Map tiles and overlays
  • Sidebar panels and controls
  • Charts and data displays

🎮 Controller (Logic + Orchestration)

  • Handles user input events
  • Calls AI API with context
  • Parses AI responses, extracts actions
  • Updates map based on AI output
  • Manages data fetching pipelines
💡 In an AI app, the Controller is where the "magic" happens. It translates natural language into map actions.
Architecture

Component-Based Architecture

Instead of writing one massive script, break your application into small, focused modules. Each component has a single responsibility and communicates through well-defined interfaces[1]. A multivocal literature review identified over 70 design patterns for AI-based systems, many of which emphasize modular decomposition[10].

Why Components?

🧩 Modular

Each file handles one concern. You can work on the chat UI without touching the map code.

♻️ Reusable

Your AI service wrapper works in any project that calls the same API. Write it once, use it everywhere.

🧪 Testable

You can test the AI service by mocking API responses, without needing a running map.

👥 Team-Friendly

Two teammates can work on ai-service.js and map-service.js simultaneously without merge conflicts.

⚠️ Anti-pattern alert: A single 2,000-line app.js file that handles everything is the number one cause of project chaos in student teams. Avoid it.
Architecture

Production-Quality File Structure

Here is a recommended file structure for your AI-EO project. You do not need a build system or framework; plain HTML, CSS, and JS with ES modules works perfectly.

my-eo-app/
├── index.html          ← entry point, loads all scripts
├── css/
│   ├── style.css         ← global layout, themes, typography
│   └── components.css    ← chat bubbles, panels, controls
├── js/
│   ├── app.js            ← main controller, bootstraps everything
│   ├── ai-service.js     ← AI API wrapper (Gemini/Groq)
│   ├── map-service.js    ← Leaflet map init, layers, drawing
│   ├── ui-controller.js  ← DOM updates, chat rendering
│   └── config.js         ← API keys, endpoints, settings
├── assets/
│   └── images/           ← logos, icons, screenshots
└── data/
    └── sample-data.geojson ← test datasets for development
ℹ️ config.js is where you store API keys during development. For production, these would move to environment variables or a backend proxy. Never commit API keys to a public repository.
Architecture

Separation of Concerns

Separation of concerns (SoC) means that each module in your application should address a single, well-defined aspect of the system[1]. For AI-EO apps, this principle is especially important because of the number of moving parts. Sculley et al. warn that ML systems easily accumulate "hidden technical debt" when model code, data pipelines, and UI logic are entangled[8].

Why Should AI Logic Be Separate from Map Logic?

❌ Tightly Coupled (Bad)

// Everything mixed together
async function handleChat(msg) {
  const resp = await fetch('gemini-api...');
  const geojson = parseGeoJSON(resp);
  L.geoJSON(geojson).addTo(map);
  document.getElementById('chat')
    .innerHTML += `<div>...</div>`;
}

✅ Loosely Coupled (Good)

// Each concern in its own module
const resp = await aiService.chat(msg);
const actions = aiService.parse(resp);
if (actions.addLayer)
  mapService.addGeoJSON(actions.data);
uiController.renderReply(resp.text);
ℹ️ In the "good" version, you can swap the AI provider (Gemini to Groq) by changing only ai-service.js. The map and UI code remain untouched.
Quiz

Check Your Understanding

What is the primary benefit of separating AI API calls into a dedicated module (e.g., ai-service.js)?
✅ Correct! Separation of concerns means each module can change independently. Swapping from Gemini to Groq only requires editing the AI service module.
❌ Not quite. The key benefit is independence: changing the AI provider (or its API format) does not ripple through the rest of the codebase. This is the essence of separation of concerns.
State

What is Application State?

State is the complete set of data that describes what your application is "doing" at any given moment. If you could freeze your app, the state would tell you everything needed to resume it exactly as it was.

State in an AI-EO App

ℹ️ Why does it matter? Without managed state, your app becomes unpredictable. The AI forgets context, layers disappear on refresh, and users lose their work. Good state management prevents all of this.
State

Managing Conversation History

The conversation history is the most critical piece of state in an AI-EO app. It provides the context window that allows the AI to give coherent, multi-turn responses[4].

How It Works

  1. User sends a message ("Show me NDVI for Strasbourg")
  2. You append { role: "user", content: "..." } to the history array
  3. You send the entire history to the AI API
  4. AI responds with context from prior messages
  5. You append { role: "model", content: "..." } to the history
JavaScript
// Building context-aware conversation
const history = [
  { role: "user",  content: "What satellite data covers France?" },
  { role: "model", content: "Sentinel-2 provides 10m resolution..." },
  { role: "user",  content: "Show me the latest image for Strasbourg" }
  // The AI now knows "Strasbourg" is in France
  // and "image" refers to satellite imagery
];
⚠️ Token limits: Gemini and Groq have context window limits. For long conversations, implement a sliding window that keeps the system prompt + last N messages.
State & Orchestration

Multi-Action & Dual-Loop Chat Orchestration

When you enable Function Calling (Tools), Gemini does not just respond with text. Sometimes it returns a text explanation, one or more function calls, or both at once. A naive implementation that checks only if (text) ... else if (functionCall) will fail to show the text to the user, or fail to execute the tool.

The Dual-Loop Solution

To support rich, context-aware conversations, your controller needs an orchestration loop that checks and processes each part of the model's response:

💡 Standard Flow: Loop through the response parts. Render text immediately. If you encounter a functionCall, execute it, append the result to the history, and call Gemini again so it can explain what it did.
🔄 This forms a recursive dual-loop: the outer loop handles the user-assistant chat turn, while the inner loop manages the agent-tool execution cycles.
JavaScript
async function sendMessage(userText) {
  // 1. Push user message to history
  history.push({ role: "user", parts: [{ text: userText }] });

  // 2. Call Gemini API
  let response = await callGeminiAPI(history);
  let parts = response.candidates[0].content.parts;
  history.push({ role: "model", parts: parts });

  // 3. Multi-part iteration loop
  for (const part of parts) {
    if (part.text) {
      appendChatBubble("assistant", part.text);
    }
    if (part.functionCall) {
      // Execute local Leaflet JS action
      let res = await runLocalTool(part.functionCall);
      
      // Send tool results back to Gemini
      let toolPart = {
        functionResponse: {
          name: part.functionCall.name,
          response: { result: res }
        }
      };
      
      history.push({ role: "user", parts: [toolPart] });
      let secondRes = await callGeminiAPI(history);
      let secondParts = secondRes.candidates[0].content.parts;
      history.push({ role: "model", parts: secondParts });
      
      // Parse model explanation
      for (const p of secondParts) {
        if (p.text) appendChatBubble("assistant", p.text);
      }
    }
  }
}
State

Map State Management

Your Leaflet map has its own state: center, zoom level, active layers, drawn features, and basemap. This state needs to be synchronized with the AI so the model can reference "the current view."

Map State Includes

  • View: center coordinates, zoom level
  • Layers: which overlays are visible
  • Drawings: user-drawn polygons, markers, or lines
  • Selection: currently clicked feature
  • Basemap: satellite vs. street vs. terrain
💡 Pass the current map bounds to the AI so it can filter data for the visible area: map.getBounds()
JavaScript
// Capturing map state
function getMapState() {
  return {
    center: map.getCenter(),
    zoom: map.getZoom(),
    bounds: map.getBounds(),
    activeLayers: [
      ...this.mapLayers.keys()
    ]
  };
}

// Pass to AI for spatial context
const context =
  `User is viewing: 
  ${state.center}, zoom ${state.zoom}`;
State

AppState Class: Vanilla JS State Management

You do not need React, Vue, or any framework. A simple JavaScript class can manage all your application state cleanly. Here is a complete, production-ready pattern:

JavaScript
class AppState {
  constructor() {
    this.conversationHistory = [];
    this.mapLayers = new Map();
    this.currentView = { center: [48.57, 7.75], zoom: 12 };
    this.userData = {};
  }

  // Add a message to conversation history
  addMessage(role, content) {
    this.conversationHistory.push({
      role, content, timestamp: Date.now()
    });
  }

  // Format history for Gemini API
  getConversationForAPI() {
    return this.conversationHistory.map(m => ({
      role: m.role,
      parts: [{ text: m.content }]
    }));
  }

  // Save to localStorage for persistence
  save() {
    localStorage.setItem('appState', JSON.stringify({
      conversationHistory: this.conversationHistory,
      currentView: this.currentView,
      userData: this.userData
    }));
  }

  // Restore from localStorage
  static load() {
    const saved = localStorage.getItem('appState');
    if (!saved) return new AppState();
    const state = new AppState();
    Object.assign(state, JSON.parse(saved));
    return state;
  }
}
💡 This single class replaces the need for a state management library. Instantiate it globally: const state = AppState.load();
API Patterns

Rate Limiting and Retry Logic

Every API has rate limits. The Gemini free tier typically allows between 5 and 30 requests per minute (RPM), depending on the model, plus daily caps of 100 to 1,500 requests per day (RPD). These limits change frequently, so always check the current quotas in Google AI Studio. If your user sends rapid messages, you will hit a 429 Too Many Requests error. The solution: exponential backoff[5].

How Exponential Backoff Works

  1. First retry: wait 1 second
  2. Second retry: wait 2 seconds
  3. Third retry: wait 4 seconds
  4. Fourth retry: wait 8 seconds (then give up)
JavaScript
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i <= maxRetries; i++) {
    try {
      const resp = await fetch(url, options);
      if (resp.status === 429) {
        const delay = Math.pow(2, i) * 1000;
        console.warn(`Rate limited. Retry in ${delay}ms`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      return await resp.json();
    } catch (err) {
      if (i === maxRetries) throw err;
    }
  }
}
ℹ️ Add a small random jitter (e.g., + Math.random() * 500) to the delay to prevent "thundering herd" issues when multiple clients retry simultaneously.
API Patterns

Caching, Error Handling, and Loading States

🗄️ Caching AI Responses

If a user asks the same question twice, do not waste an API call. Use a simple in-memory cache or localStorage.

const cache = new Map();

async function cachedQuery(prompt) {
  const key = prompt.trim().toLowerCase();
  if (cache.has(key))
    return cache.get(key);
  const result = await queryAI(prompt);
  cache.set(key, result);
  return result;
}

⏳ Loading States

  • Typing indicator: Three bouncing dots in the chat while AI responds
  • Skeleton screens: Placeholder shapes that fill in when data loads
  • Progress bars: For data-heavy operations like imagery fetches

🚨 Error Handling for Users

Never show raw error messages. Instead, display friendly, actionable feedback:

❌ Bad Error UX

Error: 429 Too Many Requests at fetch.js:42

✅ Good Error UX

"I'm thinking extra hard about this one! Please wait a moment and I'll try again." (auto-retry in background)

✅ Graceful Degradation

"The satellite data service is temporarily unavailable. Here's what I know from cached data..." (fallback to localStorage)

API Patterns

Robust AI Service Wrapper

Combine all the patterns into a single, reusable service class. This is the ai-service.js module your team can rely on throughout the project.

ai-service.js
class AIService {
  constructor(apiKey, model = 'gemini-2.5-flash') {
    this.apiKey = apiKey;
    this.model = model;
    this.baseUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}`;
    this.cache = new Map();
  }

  async chat(history, systemPrompt, tools = []) {
    const body = {
      system_instruction: { parts: [{ text: systemPrompt }] },
      contents: history,
      ...(tools.length && { tools: [{ function_declarations: tools }] })
    };

    try {
      const data = await this.fetchWithRetry(
        `${this.baseUrl}:generateContent?key=${this.apiKey}`,
        { method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(body) }
      );
      return this.parseResponse(data);
    } catch (err) {
      return { text: 'Sorry, I had trouble processing that. Please try again.',
               error: true };
    }
  }

  parseResponse(data) {
    const part = data.candidates?.[0]?.content?.parts?.[0];
    if (part?.functionCall) return { type: 'function', ...part.functionCall };
    return { type: 'text', text: part?.text || 'No response' };
  }

  async fetchWithRetry(url, opts, retries = 3) {
    for (let i = 0; i <= retries; i++) {
      const r = await fetch(url, opts);
      if (r.ok) return await r.json();
      if (r.status === 429 && i < retries)
        await new Promise(r => setTimeout(r, 2 ** i * 1000));
      else throw new Error(`API error: ${r.status}`);
    }
  }
}
Real-World Application

Lessons from Terra: API Development in Practice

Developing APIs for production environments involves dealing with complex scenarios. Recent discussions from the Terra project highlight several crucial lessons for deploying and testing your API architectures.

1. CI/CD and Automated Deployment

Moving your code from development to a live server should not be a manual process. The Terra team emphasizes deploying docs on command and utilizing automatic deployments coupled with security constraints.

This includes running code quality scans before any pipeline moves code into the production environment.

2. Component Registries

When working with a component-based architecture, you must maintain a clear registry of where all your components live and ensure endpoints are available to serve them. Splitting components into different folders requires careful path management.

3. Overcoming Security Constraints

When downloading packages or triggering automated workflows, security constraints often block execution. You must be prepared to adjust workflow permissions (e.g. making certain workflows public temporarily) or properly authenticate package downloads to prevent failed pipeline builds.

4. API Testing Pipelines

Your API must pass through rigorous testing pipelines. This involves resolving code quality findings, anticipating expected results from data sampling, and making sure that security scans are resolved.

Sprint Plan

The 5-Day Sprint (Days 5 to 9)

You have 5 working days to go from architecture to a working demo. Here is a realistic, structured plan:

Day Focus Deliverable
Day 5 (Today) Architecture + Setup File structure created, config ready, base HTML/CSS layout
Day 6 Core Feature Map working, AI chat connected, one key feature functional
Day 7 Data Integration Real satellite data flowing, function calling working
Day 8 Polish + Secondary Features Error handling, loading states, UI refinement
Day 9 Demo Prep Rehearsed demo, README, edge cases handled
⚠️ You have 5 working days. Focus on a working demo, not perfection. A simple app that works flawlessly is infinitely better than a complex app that crashes during the presentation.
Sprint Plan

Breaking Your Project into User Stories

A user story is a simple statement that captures a feature from the user's perspective. It follows the format:

"As a [type of user], I want to [action], so that [benefit]."

Example User Stories for an AI-EO App

  1. "As a city planner, I want to ask the AI to show urban heat islands on the map, so that I can identify neighborhoods needing green infrastructure."
  2. "As a farmer, I want to draw my field boundary and get NDVI analysis, so that I can detect areas of crop stress."
  3. "As a disaster responder, I want to type a location and see flood extent, so that I can plan evacuation routes."

Prioritize Ruthlessly

🥇 Must Have (Day 6)

The ONE feature that makes your project compelling. Build this first and make it bulletproof.

🥈 Nice to Have (Day 8)

Additional features that enhance the demo. Only build these if the core feature is solid.

Quiz

Check Your Understanding

In a 5-day sprint with limited time, what should be your FIRST priority?
✅ Correct! Build one compelling feature first and make it work flawlessly. Everything else is polish. A single feature that works is far more impressive than five features that crash.
❌ Not quite. In a time-constrained sprint, you should focus on the one core feature that makes your project unique and compelling. Beautiful UI and documentation matter, but only after the core feature works.
What does "exponential backoff" refer to in API design?
✅ Correct! Exponential backoff doubles the wait time (1s, 2s, 4s, 8s...) between retries. This gives the server time to recover and prevents your app from overwhelming it with requests.
❌ Not quite. Exponential backoff means doubling the wait time between each retry attempt (1s, 2s, 4s, 8s...). This prevents overwhelming a rate-limited or overloaded API.
Summary

Summary of Big Ideas

Reference

Glossary of Key Terms

Architecture
The high-level structural design of a software system, defining how components are organized and interact.
MVC (Model-View-Controller)
A design pattern that separates data (Model), user interface (View), and application logic (Controller) into distinct components.
Component
A self-contained, reusable unit of code that handles a specific piece of functionality (e.g., map service, chat UI).
State Management
The practice of tracking and updating application data (conversation history, map view, user settings) in a predictable, centralized way.
Separation of Concerns
A design principle where each module addresses a single, well-defined aspect of the system, minimizing overlap and dependencies.
Rate Limiting
A restriction imposed by APIs on the number of requests a client can make in a given time window (e.g., 5 to 30 requests/minute for Gemini free tier, varies by model).
Exponential Backoff
A retry strategy where the wait time between attempts doubles with each failure (1s, 2s, 4s, 8s), preventing server overload.
Sprint
A fixed time period (often 1 to 2 weeks) during which a team commits to completing a set of prioritized work items.
User Story
A short, natural-language description of a feature from the user's perspective: "As a [user], I want to [action] so that [benefit]."
MVP (Minimum Viable Product)
The simplest version of your product that delivers the core value proposition and can be demonstrated to users for feedback.

References

  • [1] Martin, R. C. (2017). Clean Architecture: A Craftsman's Guide to Software Structure and Design. Prentice Hall. ISBN: 978-0134494166.
  • [2] Reenskaug, T. (1979). Models-Views-Controllers. Technical note, Xerox PARC. folk.uio.no/trygver
  • [3] Krasner, G. E. & Pope, S. T. (1988). A Cookbook for Using the Model-View-Controller User Interface Paradigm in Smalltalk-80. Journal of Object-Oriented Programming, 1(3), 26-49.
  • [4] Google. (2025). Gemini API: Multi-turn conversations. ai.google.dev/gemini-api/docs
  • [5] Google Cloud. (2025). Retry strategy with exponential backoff. cloud.google.com/docs/quotas/retry-strategy
  • [6] Fowler, M. (2002). Patterns of Enterprise Application Architecture. Addison-Wesley. ISBN: 978-0321127426.
  • [7] Amershi, S. et al. (2019). Software Engineering for Machine Learning: A Case Study. Proc. 41st Int'l Conf. on Software Engineering: Software Engineering in Practice (ICSE-SEIP), 291-300. DOI: 10.1109/ICSE-SEIP.2019.00042
  • [8] Sculley, D. et al. (2015). Hidden Technical Debt in Machine Learning Systems. Advances in Neural Information Processing Systems 28 (NeurIPS 2015), 2503-2511. papers.nips.cc
  • [9] Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN: 978-0201633610.
  • [10] Heiland, L., Hauser, M., & Bogner, J. (2023). Design Patterns for AI-based Systems: A Multivocal Literature Review and Pattern Repository. Proc. IEEE/ACM 2nd Int'l Conf. on AI Engineering (CAIN). DOI: 10.1109/CAIN58948.2023.00035
  • [11] Leaflet. (2025). Leaflet API Reference. leafletjs.com/reference.html

External Resources

🌟 Pioneer Profile
👤

Margaret Hamilton

Software Engineer

She led the MIT team that developed the onboard flight software for the Apollo space program, coining the term 'software engineering'.

🌍 Local to Global

Global Data, Local Impact

Applying EO to Community Challenges

Earth Observation provides a macroscopic view of environmental trends, but its true power lies in downscaling this data to affect local policy and design, such as urban planning and sustainable workplaces.

📍
Texas Connection: In Texas, EO data is used to monitor the Edwards Aquifer depletion and track the expansion of urban heat islands across the Dallas-Fort Worth metroplex.
🗺️
🤔 Geographic Inquiry

Regional Decisions Scenario

Scenario: Designing for Placemaking at Work

As you build your architecture, you must consider the human element. How does your software enable meaningful connection in a remote or hybrid setting?

Your Task:

  • Define the frontend architecture.
  • Explain how the UI promotes a sense of 'Third Place'.
📚 Summary

Big Ideas & Glossary

Summary of Big Ideas

  • Data is only as valuable as its application.
  • Space technology has direct terrestrial benefits.

Glossary of Terms

Earth Observation
Gathering information about Earth via remote sensing.
📝 Knowledge Check

Auto-Graded Quiz

In the context of the IPAT equation (Impact = Population × Affluence × Technology), how does hybrid work technology affect environmental impact?
A
It inherently always reduces the impact to zero.
B
It alters the 'Technology' multiplier, potentially reducing commute emissions but increasing server energy use.
C
It has no effect on environmental impact.
✅ Correct! Technology is a multiplier in IPAT. Hybrid work reduces transit emissions but shifts the energy burden to data centers and home heating/cooling.
❌ Incorrect. The right answer was B. Technology is a multiplier in IPAT. Hybrid work reduces transit emissions but shifts the energy burden to data centers and home heating/cooling.

📝 Daily Reflection

What was your biggest takeaway from this session, and how does it apply to the TERRA project? Write your response below. Your instructor will review this to track your progress.