Project Blueprint: Bill Reminder Bot
Subtitle: Never miss a payment again with AI-powered bill reminders. Difficulty: Beginner Category: Personal Finance
As a Staff AI Engineer at Google, I've outlined a comprehensive blueprint for developing "Bill Reminder Bot." This document details the architectural considerations, implementation strategies, and AI integration necessary to build a robust, user-friendly, and intelligent personal finance assistant. While categorized as 'Beginner' in scope, this blueprint emphasizes principles of good software engineering, responsible AI, and scalability from the outset.
1. The Business Problem (Why build this?)
In the complexities of modern life, managing personal finances often becomes a source of significant stress and costly errors. Individuals juggle multiple bills with varying due dates, amounts, and payment methods across different service providers. This cognitive load frequently leads to forgotten payments, resulting in late fees, credit score degradation, service interruptions, and increased anxiety. Current solutions often provide static reminders lacking personalization or proactive intelligence. They require meticulous manual entry and frequently fail to adapt to a user's evolving financial habits or preferred notification styles.
The core problem Bill Reminder Bot addresses is the mental burden and financial penalty associated with disorganized bill management. Users need a reliable, intelligent system that not only tracks due dates but also understands their unique preferences for reminders and provides a clear, forward-looking view of their financial obligations. The absence of such a personalized, AI-driven assistant in the beginner-friendly personal finance space creates a clear opportunity for a solution that empowers users to regain control over their financial schedules and reduce financial friction.
2. Solution Overview
Bill Reminder Bot will be a progressive web application (PWA) designed to operate locally on the user's device, offering a privacy-first approach to personal finance management. Its primary objective is to simplify bill tracking, provide intelligent, customizable reminders, and offer a clear historical and forecasted view of payments. The AI component, powered by the Gemini API, is central to its value proposition, moving beyond static notifications to truly personalized and adaptive reminders.
Core User Journey:
- Onboarding: User visits the web application. Initial instructions guide them on how to add their first bill.
- Bill Entry: User adds a new bill by providing details such as bill name, amount, due date, frequency (e.g., monthly, quarterly, one-time), and an optional note.
- Custom Reminder Preference: For each bill, the user can express their preferred reminder style using natural language (e.g., "Remind me 3 days before, then on the day itself," or "Just a gentle reminder a week out").
- AI Processing: The Gemini API interprets the user's natural language reminder preference, translating it into a structured set of dates and messages for notifications.
- Notification Scheduling: The application schedules push notifications based on the AI's output, utilizing the Push API and Service Workers for persistent, reliable delivery even when the app is closed.
- Payment Logging: Upon making a payment, the user marks the bill as paid, updating their payment history.
- Dashboard View: Users can see an overview of upcoming bills, payment history, and a forecasted summary of future obligations.
- Data Persistence: All bill data, reminder preferences, and payment history are securely stored client-side using IndexedDB, ensuring privacy and offline access.
Key Benefits:
- Reduced Stress: Automated, personalized reminders eliminate the fear of missing payments.
- Financial Savings: Avoidance of late fees and potential credit score improvements.
- Clarity & Control: Comprehensive view of financial obligations, past and future.
- Privacy-First: All sensitive financial data remains on the user's device.
- Intelligent Personalization: Reminders adapt to individual needs, not just generic defaults.
3. Architecture & Tech Stack Justification
The architecture for Bill Reminder Bot is designed for a client-side-centric application, leveraging modern web technologies for performance, user experience, and privacy.
Overall Architecture Diagram (Conceptual):
+-------------------+ +-------------------+ +--------------------+
| | | | | |
| User Interface |<----->| Application |<----->| Local Data |
| (React.js) | | Logic | | (IndexedDB) |
| | | | | |
+-------------------+ +-------------------+ +--------------------+
^ |
| | API Calls
| v
+-------------------+ +--------------------+
| | | |
| Notification |<----->| AI Service |
| System | | (Gemini API) |
| (Push API/SW) | | |
+-------------------+ +--------------------+
Technology Stack Justification:
-
React.js (Frontend UI Framework):
- Justification: React is an industry-standard for building modern, interactive single-page applications (SPAs). Its component-based architecture promotes modularity, reusability, and maintainability, which is excellent for beginner developers learning structured UI development. For a beginner project,
create-react-app(or Vite for a leaner setup) provides a quick start with minimal configuration. - Role: Handles all UI rendering, user interactions, and state management. It will consume data from IndexedDB and orchestrate calls to the Gemini API.
- Justification: React is an industry-standard for building modern, interactive single-page applications (SPAs). Its component-based architecture promotes modularity, reusability, and maintainability, which is excellent for beginner developers learning structured UI development. For a beginner project,
-
Gemini API (AI Service):
- Justification: Gemini provides powerful multimodal AI capabilities, crucial for the "AI-powered" aspect of this bot. Its natural language understanding (NLU) will be leveraged to interpret user preferences for reminders, moving beyond rigid forms to intuitive, conversational input.
- Role: The core AI engine for
Customizable Reminders. It will parse natural language descriptions of reminder preferences and output structured data (e.g., specific dates, times, and message templates) for notifications. For a beginner project, direct client-side API calls are acceptable with proper API key management (e.g., environment variables, or ideally, a simple serverless function proxy for security in production).
-
IndexedDB (Local Data Storage):
- Justification: IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. It's asynchronous, offers transaction support, and is well-suited for applications that prioritize offline capabilities and user privacy, as data never leaves the user's device. This aligns perfectly with a personal finance application where data sensitivity is paramount.
- Role: Persists all bill details (name, amount, due date, frequency), user-defined reminder preferences, AI-generated reminder schedules, and payment history. It acts as the single source of truth for all application data.
-
Push API & Service Workers (Notification System):
- Justification: The Web Push API, coupled with Service Workers, enables web applications to send push notifications to users even when the browser or application is closed. This is fundamental for a "reminder bot" to ensure timely delivery of critical alerts. Service Workers also provide offline capabilities, background synchronization, and improved performance.
- Role: Service Workers will intercept network requests (for offline support), manage caching, and, most importantly, receive and display push notifications scheduled by the application logic based on the Gemini API's output. The Push API facilitates the subscription process and the actual sending of notifications.
Development Environment Setup:
- Node.js & npm/Yarn: For package management and running the React development server.
- VS Code: Recommended IDE with extensions for React, JavaScript, and linting.
- Git: For version control.
4. Core Feature Implementation Guide
This section details the implementation strategy for the key features, focusing on the interplay between the chosen technologies.
4.1. Bill Due Date Tracker
This feature involves adding, viewing, editing, and deleting bill entries.
Data Model (IndexedDB Schema):
// Database Name: 'BillReminderDB'
// Object Store: 'bills'
{
id: String, // Unique ID (UUID)
name: String, // e.g., "Electricity Bill"
amount: Number, // e.g., 75.50
currency: String, // e.g., "USD"
dueDate: String, // ISO Date String: "YYYY-MM-DD"
frequency: String, // "monthly", "weekly", "quarterly", "annually", "one-time"
lastPaidDate: String | null, // ISO Date String, for recurring bills
isPaid: Boolean, // True if the current occurrence is paid
reminderPreference: String, // User's natural language preference
scheduledReminders: Array, // Array of {date: String, message: String, notificationId: Number}
notes: String, // Optional user notes
createdAt: String, // ISO Date String
updatedAt: String // ISO Date String
}
Implementation Steps:
-
IndexedDB Wrapper: Create a utility class or functions to abstract IndexedDB operations (open DB, add, get, update, delete). Libraries like
idb(Google Chrome Labs) can simplify this.// src/services/idbService.js import { openDB } from 'idb'; const DB_NAME = 'BillReminderDB'; const DB_VERSION = 1; const STORE_NAME = 'bills'; async function getDb() { return openDB(DB_NAME, DB_VERSION, { upgrade(db) { if (!db.objectStoreNames.contains(STORE_NAME)) { db.createObjectStore(STORE_NAME, { keyPath: 'id' }); } }, }); } export async function addBill(bill) { const db = await getDb(); return db.add(STORE_NAME, bill); } // ... implement getBill, updateBill, deleteBill, getAllBills -
React Components:
AddEditBillForm.js: A form for entering/editing bill details.BillItem.js: Displays a single bill with options to mark as paid, edit, or delete.BillList.js: Renders a list ofBillItemcomponents.
-
Bill Creation/Update Flow:
- User submits
AddEditBillForm. - React component validates input.
- Calls
idbService.addBill(newBill)oridbService.updateBill(updatedBill). - After successful DB operation, trigger the reminder scheduling logic (see 4.2).
- Update React state to re-render the bill list.
- User submits
4.2. Customizable Reminders (AI-powered)
This is the core AI feature.
Implementation Steps:
-
User Input for Reminder Preference: In the
AddEditBillForm, include a text area for "How would you like to be reminded?" -
Gemini API Integration (Client-Side):
- When a bill is added or updated with a
reminderPreference, make an API call to Gemini. - Prompt Design: Craft a precise prompt to guide Gemini to output structured reminder data.
// src/services/geminiService.js const API_KEY = process.env.REACT_APP_GEMINI_API_KEY; // Use environment variables const MODEL_NAME = 'gemini-pro'; // Or gemini-1.5-pro export async function getReminderSchedule(billName, dueDate, amount, preference) { const prompt = `You are a helpful assistant for scheduling bill reminders. The user has a bill: '${billName}' for ${amount} due on ${dueDate}. Their reminder preference is: '${preference}'. Generate a JSON array of optimal reminder events. Each event should have a 'date' (YYYY-MM-DD), 'time' (HH:MM, e.g., '09:00'), and 'message'. Focus on critical reminders. Avoid more than 3 reminders per bill for standard preferences. If no specific time is mentioned, default to '09:00'. Ensure the dates are valid and on or before the due date. Example output format: [ { "date": "YYYY-MM-DD", "time": "HH:MM", "message": "Your {billName} of {amount} is due in {X} days." }, { "date": "YYYY-MM-DD", "time": "HH:MM", "message": "Your {billName} of {amount} is due TODAY!" } ] Output ONLY the JSON array.`; try { const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${MODEL_NAME}:generateContent?key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }], // Add safety settings if needed }), }); if (!response.ok) { throw new Error(`Gemini API error: ${response.statusText}`); } const data = await response.json(); const jsonContent = data.candidates[0].content.parts[0].text; return JSON.parse(jsonContent); // Parse the JSON string from Gemini } catch (error) { console.error("Error calling Gemini API:", error); // Fallback: Return a default reminder if AI fails return [{ date: dueDate, time: '09:00', message: `${billName} of ${amount} is due TODAY!` }]; } } - When a bill is added or updated with a
-
Notification Scheduling (Push API & Service Worker):
- After receiving structured reminder data from Gemini, schedule these as local notifications or push notifications. For cross-browser reliability and persistence, Push API is preferred.
- Service Worker Registration: Ensure your
src/index.jsor equivalent registers a Service Worker.
// public/service-worker.js (or src/service-worker.js if using workbox) self.addEventListener('push', function(event) { const data = event.data.json(); const title = data.title || 'Bill Reminder'; const options = { body: data.body, icon: '/icons/icon-192x192.png', // Path to your app icon badge: '/icons/badge.png', data: { billId: data.billId, url: '/' // URL to open when notification is clicked } }; event.waitUntil(self.registration.showNotification(title, options)); }); self.addEventListener('notificationclick', function(event) { event.notification.close(); const billId = event.notification.data.billId; event.waitUntil( clients.openWindow(event.notification.data.url + `?bill=${billId}`) // Open app to specific bill ); });- Scheduling Function (Client-side):
// src/services/notificationService.js export async function scheduleLocalNotification(billId, date, time, message) { if (!('Notification' in window) || !('serviceWorker' in navigator)) { console.warn('Notifications not supported.'); return; } const permission = await Notification.requestPermission(); if (permission !== 'granted') { console.warn('Notification permission denied.'); return; } // Calculate target timestamp const [year, month, day] = date.split('-').map(Number); const [hours, minutes] = time.split(':').map(Number); const targetDate = new Date(year, month - 1, day, hours, minutes); const now = new Date(); if (targetDate <= now) { console.log(`Skipping past reminder for bill ${billId} on ${date} at ${time}`); return; } const delay = targetDate.getTime() - now.getTime(); // For a beginner project, scheduling push notifications from client-side *without* a server // is challenging for arbitrary future dates. A simpler approach is local notifications // or to rely on the service worker to manage persistent local notifications. // For truly persistent, background push notifications, a server component is typically required // to send the actual push message to the browser's push service. // *Alternative for Beginner:* Use setTimeout for local notifications if app is open, // or rely on a "pseudo-push" by having the Service Worker regularly check IndexedDB for upcoming reminders // and display them as local notifications. This is less robust than true push but easier to implement client-side. // Let's assume a simplified approach for beginner, leveraging Service Worker to *display* // notifications that it "wakes up" to schedule, or for app-open notifications. // For *true* push notifications, a backend (e.g., serverless function) would hit the Push API endpoint. // For this blueprint, we'll demonstrate the *display* part via SW and acknowledge the server needed for *sending* pushes. // Simplified approach: store reminders in IndexedDB and let SW handle. // This part requires a more advanced SW setup for background tasks. // For beginner, let's keep it to immediate local notifications or a simple "poll" by SW on startup. // A more robust client-side approach for "scheduled" local notifications: // The Service Worker can manage a list of upcoming notifications in IndexedDB. // When the SW is activated/periodically (if the browser allows), it checks for due notifications // and uses `self.registration.showNotification`. This is complex for "Beginner." // **Revised Beginner Approach:** // For a true "Beginner" project without a backend, the most realistic Push API usage // is limited. We can use the Notification API for immediate reminders if the app is open, // and store scheduled reminders in IndexedDB. A more advanced version would use a server // to send Web Push. For this project, let's focus on the local scheduling. // A simple *local* notification scheduler: setTimeout(async () => { await navigator.serviceWorker.ready; const swReg = await navigator.serviceWorker.getRegistration(); if (swReg) { swReg.showNotification(`Bill Due: ${message}`, { body: `Don't forget to pay ${message}!`, icon: '/icons/icon-192x192.png', data: { billId: billId, url: '/' } }); // Update bill in IndexedDB to mark this specific reminder as "sent" } }, delay); console.log(`Scheduled local notification for ${billId} on ${date} at ${time}`); } // This `scheduleLocalNotification` needs to be called after Gemini returns the `scheduledReminders` array. // Store `scheduledReminders` in the `bills` IndexedDB object. // On app load, you'd iterate through active bills and re-schedule or check for missed notifications.
4.3. Payment History Log
This feature tracks when bills were paid and updates their status.
Implementation Steps:
-
Mark as Paid UI: Add a "Mark as Paid" button or checkbox to
BillItem.js. -
Logic:
- When a bill is marked as paid:
- Update the
isPaidproperty of the current bill occurrence totruein IndexedDB. - Update
lastPaidDateto the current date. - If the bill is recurring, calculate the
nextDueDatebased on itsfrequencyand store it as a new bill entry or update the existing one for the next cycle, resettingisPaidtofalse. This requires careful date logic. - Clear any pending scheduled notifications for the just-paid bill occurrence.
- Update React state to refresh the UI.
- Update the
// src/services/billService.js (combines IDB and notification logic) import { updateBill, addBill } from './idbService'; import { cancelNotifications } from './notificationService'; // Needs implementation export async function markBillAsPaid(billId) { const bill = await getBill(billId); // Assume getBill is implemented in idbService if (!bill) return; // Update current occurrence bill.isPaid = true; bill.lastPaidDate = new Date().toISOString().split('T')[0]; bill.updatedAt = new Date().toISOString(); await updateBill(bill); await cancelNotifications(bill.scheduledReminders); // Cancel pending notifications for this specific bill instance // Handle recurring bills: create next instance if (bill.frequency !== 'one-time') { const nextDueDate = calculateNextDueDate(bill.dueDate, bill.frequency); // Helper function needed const newBill = { ...bill, id: crypto.randomUUID(), // New unique ID dueDate: nextDueDate, isPaid: false, lastPaidDate: null, scheduledReminders: [], // Will be re-generated by AI createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; await addBill(newBill); // Trigger Gemini and notification scheduling for newBill (async) // This is where `getReminderSchedule` and `scheduleLocalNotification` would be called. } return bill; // Return updated bill } - When a bill is marked as paid:
4.4. Upcoming Bill Forecast
This feature displays bills due in the near future.
Implementation Steps:
-
Query IndexedDB: Retrieve all active bills from IndexedDB.
-
Filtering & Sorting: Filter bills that are not
isPaidand havedueDatein the future. Sort them bydueDate. -
React Component: Create a
UpcomingBillsList.jscomponent to render these filtered and sorted bills. -
Date Logic: Implement helper functions for date comparisons and calculations (e.g.,
isTomorrow,isNext7Days).// src/components/UpcomingBillsList.js import React, { useState, useEffect } from 'react'; import { getAllBills } from '../services/idbService'; // Assume getAllBills is implemented function UpcomingBillsList() { const [upcomingBills, setUpcomingBills] = useState([]); useEffect(() => { async function fetchUpcomingBills() { const allBills = await getAllBills(); const today = new Date(); today.setHours(0, 0, 0, 0); const filtered = allBills.filter(bill => { const billDueDate = new Date(bill.dueDate); billDueDate.setHours(0, 0, 0, 0); return !bill.isPaid && billDueDate >= today; }).sort((a, b) => new Date(a.dueDate) - new Date(b.dueDate)); setUpcomingBills(filtered); } fetchUpcomingBills(); // Set up an interval or listen to IndexedDB changes for real-time updates }, []); return ( <div> <h2>Upcoming Bills</h2> {upcomingBills.length === 0 ? ( <p>No upcoming bills!</p> ) : ( <ul> {upcomingBills.map(bill => ( <li key={bill.id}> {bill.name}: ${bill.amount} due on {bill.dueDate} </li> ))} </ul> )} </div> ); } export default UpcomingBillsList;
5. Gemini Prompting Strategy
The effectiveness of the AI-powered customizable reminders hinges critically on the prompt engineering for the Gemini API. The goal is to consistently extract structured data (reminder dates, times, messages) from natural language user input.
General Principles for Prompt Design:
- Clear Role Assignment: Explicitly define Gemini's role (e.g., "You are a helpful assistant for scheduling bill reminders.").
- Specific Task: Clearly state what information needs to be extracted or generated.
- Contextual Information: Provide all necessary context (bill name, amount, due date) to allow for accurate and personalized responses.
- Target Output Format: Mandate a strict, machine-readable output format (JSON is ideal) with example schema. This is crucial for programmatic parsing.
- Constraints & Guidelines: Define limits (e.g., "avoid more than 3 reminders," "default to 09:00 if no time is mentioned").
- Edge Case Handling (Implicit): The prompt should be robust enough to handle slightly ambiguous or incomplete user requests gracefully, or explicitly instruct on default behaviors.
Refined Prompt Example for getReminderSchedule:
System Message:
You are an expert financial assistant designed to schedule bill reminders. Your task is to interpret a user's natural language reminder preference for a specific bill and output a structured JSON array of reminder events. Each event must include a 'date' (YYYY-MM-DD), 'time' (HH:MM), and a 'message'. Prioritize clarity and usefulness for financial reminders.
User Input:
Bill Details:
Name: "Rent"
Amount: "$1200"
Due Date: "2024-03-01"
User Preference: "Remind me a week before, then 2 days before, and definitely on the day itself. Make the messages clear about the amount."
Output Format (JSON Array):
[
{ "date": "YYYY-MM-DD", "time": "HH:MM", "message": "String" }
]
Constraints:
- All reminder dates must be on or before the bill's due date.
- Default time for reminders should be '09:00' if not specified by the user.
- Generate no more than 3 distinct reminder events per request unless the user explicitly asks for more.
- Messages should be concise, professional, and include the bill name and amount.
- Ensure all generated dates are valid calendar dates.
Desired Output based on example input:
```json
[
{ "date": "2024-02-23", "time": "09:00", "message": "Your Rent bill of $1200 is due in 7 days." },
{ "date": "2024-02-28", "time": "09:00", "message": "Your Rent bill of $1200 is due in 2 days." },
{ "date": "2024-03-01", "time": "09:00", "message": "Your Rent bill of $1200 is due TODAY!" }
]
**Testing and Iteration:**
* **Diverse User Inputs:** Test with various natural language phrases: "just remind me on the day," "a few days before," "the Friday before if it's a Monday bill," "a subtle reminder," "multiple reminders please."
* **Edge Cases:** Test with short due dates (e.g., due tomorrow), or preferences that might conflict with the due date.
* **Output Validation:** Always validate Gemini's JSON output in your application code before scheduling notifications to handle malformed responses or unexpected structures.
* **Safety & Bias:** While personal finance data (especially client-side) is less prone to certain biases, ensure that the language model doesn't generate inappropriate or unhelpful messages. Leverage Gemini's safety settings.
---
## 6. Deployment & Scaling
For a "Beginner" project focused on client-side functionality and local data storage, deployment and scaling considerations are primarily about efficient static asset delivery and managing API usage.
### 6.1. Deployment
1. **Static Site Hosting:**
* Since Bill Reminder Bot is a client-side React application, it can be deployed as a static site.
* **Recommended Platforms:** Netlify, Vercel, Firebase Hosting (Google Cloud), GitHub Pages. These platforms offer seamless integration with Git repositories, automated builds, and global Content Delivery Networks (CDNs).
* **Process:**
1. Build the React application (`npm run build`). This generates an optimized `build/` folder.
2. Connect your Git repository (e.g., GitHub) to the hosting service.
3. Configure the build command (e.g., `npm run build`) and the publish directory (e.g., `build/`).
4. Every push to the main branch triggers an automatic redeployment.
2. **Service Worker Hosting:** Ensure your `service-worker.js` file is served from the root of your domain for maximum scope. Static site hosts handle this automatically if it's placed correctly in the `public/` directory or generated by a tool like Workbox.
3. **HTTPS:** Always deploy with HTTPS. All recommended platforms provide this automatically. HTTPS is mandatory for Service Workers and Push API functionality.
### 6.2. Scaling (for a client-side PWA)
Scaling for this architecture is largely distributed by design:
1. **Frontend (React App):**
* **CDN:** Leveraging a CDN (provided by Netlify, Vercel, Firebase Hosting) ensures global availability and fast loading times for your static assets, even under high user traffic.
* **Caching:** Browser caching of static assets (JS, CSS, images) minimizes subsequent load times. Service Workers can further enhance caching for offline access and improved performance.
2. **Local Data (IndexedDB):**
* IndexedDB scales with the user's device storage and CPU. Each user's data is isolated and stored locally. There are no server-side database scaling concerns for this architecture.
3. **AI Service (Gemini API):**
* The Gemini API is a managed service by Google and is designed for high scalability.
* **Concerns:**
* **Rate Limits:** Be mindful of API rate limits. For a beginner project with direct client-side calls, individual users will hit their own personal device's API limits. If a proxy server were introduced, the server itself would need to manage its aggregate rate limit.
* **Cost:** API usage incurs cost. Monitor usage and understand pricing tiers. For a public "beginner" app, consider limiting the number of AI calls per user or prompting strategy to minimize costs.
* **API Key Security:** For a production application, directly exposing the Gemini API key in client-side code is generally discouraged. A simple serverless function (e.g., Cloud Functions, Firebase Functions) acting as a proxy would be a more robust solution, abstracting the API key and potentially adding rate limiting or logging. For a "beginner" project, using environment variables and client-side calls is often tolerated for simplicity, but the security implication should be noted.
4. **Notification System (Push API / Service Workers):**
* The Push API and Service Workers offload much of the "scaling" to the user's browser and operating system, which manage notification delivery.
* **Service Worker Reliability:** Ensure your Service Worker is robust, handles updates gracefully, and is not prone to errors that could prevent notifications.
**Future Scaling Considerations (Beyond Beginner Scope):**
* **Multi-Device Sync:** To enable users to access their bills across multiple devices, a centralized backend with a user authentication system and a server-side database (e.g., Firestore, PostgreSQL) would be required.
* **Shared Bills:** A backend would be essential to manage shared financial obligations between users.
* **Advanced Analytics:** Server-side data (anonymized and permissioned) could enable more sophisticated insights and predictive analytics (e.g., "Your average monthly bill spending is X, consider setting aside Y for upcoming bills").
* **Offline Data Sync:** A robust synchronization strategy between IndexedDB and a backend would be needed for a truly resilient offline-first multi-device experience.
This blueprint provides a strong foundation for building Bill Reminder Bot, addressing both the immediate functional requirements and setting the stage for future growth, all while leveraging modern web and AI technologies.
