Skip to content

Repository files navigation

Ask-OFF WebApp

Intelligent Food Discovery & Conversational UI for Open Food Facts Canada

A high-performance, accessible web application for natural language food search, structured nutritional comparison, and grounded food inquiry across 124,145 Canadian Open Food Facts products.


React TypeScript Vite TailwindCSS TanStack Query Vitest Open Food Facts


Overview

Ask-OFF WebApp is the official open-source frontend application for the Ask-OFF Canada ecosystem. It provides an intuitive, high-speed, and responsive interface designed to explore, analyze, and compare 124,145 Canadian grocery and packaged food products.

While traditional food catalogs present rigid, unstructured text fields, Ask-OFF delivers an interactive web experience powered by deterministic natural language search, official French/English bilingual product records, and evidence-grounded conversational inquiry.

Primary Objectives

  • Conversational & Keyword Food Discovery: Instant natural language exploration coupled with debounced, race-condition-free autocomplete and query match highlighting.
  • Deterministic Nutritional Transparency: Render official vector Nutri-Score gauges (A to E), NOVA industrial food processing groups (1 to 4), Eco-Scores, allergens, and per-100g nutritional facts tables.
  • Side-by-Side Nutritional Comparison: Multi-product matrix evaluating 2 to 4 food items simultaneously with macro-nutrient deltas and persistent browser storage.
  • Ask-OFF Assistant: Grounded conversational assistant (available via full page or floating action button) that queries the backend retrieval engine and provides verifiable citations to official Open Food Facts records.
  • Zero-Latency Route Navigation: Route-level code splitting using React.lazy and Suspense to deliver minimal initial JavaScript payloads and lightning-fast transitions.
  • Universal Accessibility (a11y): Built from the ground up with keyboard navigation, visible focus indicators, screen-reader semantics, and full prefers-reduced-motion accommodation.

System Architecture

Ask-OFF WebApp operates as a decoupled single-page application (SPA) communicating over HTTPS REST APIs with the FastAPI retrieval backend.

flowchart TD
    subgraph Browser_Client [Client Browser — AskOFF WebApp]
        A[User Interaction] --> B[React Router 7 Declarative Routes]
        B --> C[Pages & Lazy-Loaded Chunks]
        C --> D[Shared Reusable UI Components]
        D --> E[TanStack Query Cache]
        D --> F[Local State: CompareContext & ListsContext]
    end

    subgraph API_Layer [Frontend API Boundary]
        E --> G[Typed REST Client: src/api/client.ts]
        G --> H[Vite Development Proxy /api or Production HTTPS]
    end

    subgraph Backend_Infrastructure [Ask-OFF Backend — offCanada]
        H --> I[FastAPI REST Gateway]
        I --> J[Query Understanding & Intent Pipeline]
        J --> K[(OpenSearch 2.x BM25 Cluster<br/>124,145 Canadian Records)]
    end
Loading

Technology Stack

Layer Technologies Purpose
Frontend Core React 19.2+, TypeScript 6.0+, Vite 8.1+ Ultra-fast modern web application with strict type safety and sub-second HMR
State & Data Fetching @tanstack/react-query 5.101+, Context API Server-state caching, stale-while-revalidate, request deduplication, and local storage
Routing & Code Splitting React Router 7.18+, React.lazy, Suspense Declarative route matching with discrete asynchronous chunks per route
Styling & Design System TailwindCSS 3.4+, PostCSS 8, Autoprefixer Utility-first responsive styling with custom typography, focus styling, and scrollbars
Icons & Media Lucide React 1.24+, SVG Vector Graphics Clean, accessible vector icons and dynamic Nutri-Score/NOVA badges
Testing Suite Vitest 4.1+, @testing-library/react, JSDOM Comprehensive unit and component behavior test suites (24/24 tests passing)
Static Code Analysis Oxlint, TypeScript Compiler (tsc -b) Sub-second linter execution and zero-error strict type verification

Application Pages & Key Features

Route Page Component Key Functionality
/ or /discover LandingPage Hero search, dynamic typewriter placeholders, brand chips, category highlights, and catalog showcase
/search SearchPage Search results grid, 9 dietary & health filter toggles, sort dropdown, responsive drawer, and pagination
/product/:id ProductDetailsPage Full product specifications, 4-tier CDN images, nutrition facts per 100g, ingredients, allergens, and labels
/compare ComparePage Side-by-side comparison table for 2–4 products with nutrient difference calculations and quick product picker
/offbot OffBotPage Dedicated conversational food assistant with verifiable ODbL citations, grounded evidence cards, and follow-ups
/lists ListsPage Saved grocery lists, favorites, and dietary bookmarks with print and JSON export capabilities
/recipes RecipesPage Curated recipe directory with ingredients linked directly to live search queries and barcode tokens
/extensions ExtensionsPage Ecosystem showcase for community plugins, allergy advisors, barcode scanners, and grocery integrations
/status DashboardPage Live backend service health check, OpenSearch connection status, record count, and autocomplete testing sandbox
/about AboutPage Project mission, architecture pillars, Open Food Facts partnership, and Open Database License (ODbL) attribution

Reusable Component Architecture

The frontend is structured around reusable, accessible presentation components:

src/components/
├── ErrorBoundary.tsx             # Catches unhandled render errors with user-friendly recovery UI
├── OffBotChat.tsx                # Core conversational chat engine, message list & ODbL citations
├── OffBotWidget.tsx              # Spherical Floating Action Button (FAB) launcher and popup chat modal
├── ProductCard.tsx               # Food product card with image, brand, Nutri-Score & macro stats
├── ProductImage.tsx              # Resilient image loader with 4-tier Open Food Facts CDN normalization
├── ProductImagePlaceholder.tsx   # Category-aware SVG fallback placeholder for items without images
├── NutritionTable.tsx            # Structured nutrition table per 100g with European & Canadian standards
├── NutriScoreLogo.tsx            # Official vector SVG Nutri-Score spectrum graphic (A to E)
├── NutriScoreBadge.tsx           # Compact Nutri-Score pills, NOVA Group cards (1 to 4) & Eco-Score badges
├── SearchBar.tsx                 # Search input with debounced autocomplete, typewriter & AbortSignal
├── FilterSidebar.tsx             # Desktop sidebar and mobile slide-over drawer for dietary filters
├── Pagination.tsx                # Accessible page navigator with previous/next controls
├── LoadingSkeleton.tsx           # Animated skeleton loaders for cards, detail sheets, and grids
├── EmptyState.tsx                # Friendly empty states with recommended actions
├── ErrorState.tsx                # Connection error displays with retry callbacks
└── ScrollToTop.tsx               # Window scroll reset upon route navigation

Project Structure

AskOFF-WebApp/
├── public/                       # Static public assets
│   ├── favicon.svg               # Web application favicon
│   ├── icons.svg                 # SVG sprite sheet
│   └── logo.png                  # Project logo asset
├── docs/
│   └── design-references/        # Design artifacts, reference screenshots & visual mockups
│       ├── A.jpg
│       ├── B.jpg
│       ├── C.jpg
│       ├── image (1).png
│       ├── image.png
│       ├── Nutri-score-A.webp
│       └── Screenshot 2026-08-26 180122.png
├── src/
│   ├── api/
│   │   ├── client.ts             # Typed REST API client, timeout handling & CDN normalization
│   │   └── assistantService.ts   # Conversational query synthesis & citation models
│   ├── assets/                   # Optimized vector icons and project logo
│   │   ├── app_qr.svg
│   │   ├── hero.png
│   │   ├── logo.png
│   │   └── phone_app.png
│   ├── components/               # 16 reusable UI and utility components
│   ├── constants/
│   │   └── queries.ts            # Default sample queries and animated typewriter phrases
│   ├── context/
│   │   ├── AssistantContext.tsx  # Chat state, conversation history, and active product focus
│   │   ├── CompareContext.tsx    # Multi-product comparison state (stored in localStorage)
│   │   └── ListsContext.tsx      # Favorites, shopping list & saved items (stored in localStorage)
│   ├── pages/                    # 10 route page components
│   ├── tests/                    # Vitest unit and React Testing Library component tests
│   │   ├── assistantService.test.ts
│   │   ├── badges.test.ts
│   │   ├── client.test.ts
│   │   ├── components.test.tsx
│   │   └── productCard.test.ts
│   ├── App.tsx                   # Main router, ErrorBoundary, QueryClient, and Providers
│   ├── index.css                 # Tailwind directives, focus-visible styles, and custom scrollbars
│   └── main.tsx                  # Application entry point (React StrictMode)
├── .env.example                  # Template for frontend environment variables
├── .gitignore                    # Git exclusion rules
├── .oxlintrc.json                # Oxlint linter configuration
├── package.json                  # Project manifest, scripts, and dependencies
├── package-lock.json             # Locked dependency tree
├── postcss.config.js             # PostCSS plugin configuration
├── tailwind.config.js            # TailwindCSS theme and font configurations
├── tsconfig.json                 # TypeScript project configuration root
├── tsconfig.app.json             # TypeScript browser configuration
├── tsconfig.node.json            # TypeScript Node/Vite configuration
├── vite.config.ts                # Vite configuration with proxy and Vitest settings
├── CONTRIBUTORS.md               # Contributor guidelines and workflow
└── README.md                     # Project documentation

Quick Start

Prerequisites

  • Node.js: v18.0.0 or higher (v20 LTS recommended)
  • npm: v9.0.0 or higher
  • Ask-OFF Backend API: Running locally on http://127.0.0.1:8000 or hosted remotely

Installation & Local Setup

1. Clone Repository

git clone https://github.com/SaitejaKommi/AskOFF-WebApp.git
cd AskOFF-WebApp

2. Install Dependencies

npm install

3. Configure Environment Variables

Copy the example environment configuration:

cp .env.example .env
Variable Default Description
VITE_API_BASE_URL /api Base URL or proxy prefix for the Ask-OFF FastAPI backend. In development, Vite automatically proxies /api to http://127.0.0.1:8000.

Security Note: All VITE_* variables are bundled directly into client-side code and visible to anyone inspecting network requests. Never expose private passwords, tokens, or backend credentials in frontend environment variables.

4. Run Development Server

npm run dev

The application will launch with hot module replacement (HMR) at http://localhost:5173.


Running Tests & Quality Checks

The repository enforces strict code quality, type safety, and automated test coverage:

# 1. Run all 24 automated unit & component tests
npm run test

# 2. Run Oxlint static analysis (0 errors)
npm run lint

# 3. Verify TypeScript compilation
npx tsc -b

# 4. Compile production build
npm run build

# 5. Preview production bundle locally
npm run preview

Test Coverage Highlights

  • Component Behavior: User-facing tests for ProductCard, NutritionTable, EmptyState, ErrorState, and ErrorBoundary via @testing-library/react.
  • API Client Utilities: Validation of per-100g nutrient extraction, 4-tier CDN URL normalization, and product image resolution.
  • Assistant Service: Context-aware nutritional reasoning, allergen extraction, and structured citation verification.
  • Nutritional Standards: Enforcement of Nutri-Score calculation bounds (A to E) and NOVA food processing classifications (1 to 4).

Performance & Production Readiness

  • Asynchronous Route Splitting: Route components are dynamically imported using React.lazy(), cutting the initial main bundle size down to 266 kB (81.5 kB gzip) and serving per-page JavaScript chunks on demand.
  • Race-Condition-Free Autocomplete: Search inputs use AbortController to automatically cancel in-flight HTTP requests when the user continues typing, preventing stale network responses from overwriting newer suggestions.
  • Open Food Facts CDN Tiering: Barcode images with 9+ digits are normalized into 4-tier subdirectories (e.g. 0060383860479 $\to$ 006/038/386/0479/1.jpg), preventing image delivery 404s.
  • Global Error Boundary: Client-side rendering exceptions are intercepted gracefully by ErrorBoundary, offering immediate recovery actions without blank screens.
  • Production Deployment: The project compiles to standard static assets in dist/ that can be hosted on any static platform (Cloudflare Pages, Vercel, Netlify, AWS S3 / CloudFront, or NGINX) with client-side routing fallback to /index.html.

Documentation & Guidelines

  • CONTRIBUTORS.md — Comprehensive contributing workflow, component conventions, testing practices, and accessibility rules.
  • docs/design-references/ — Design system assets, reference screenshots, and visual specifications.

Open Food Facts Attribution

This application interfaces with open product records provided by Open Food Facts, published under the Open Database License (ODbL). Individual product images and brand assets remain the property of their respective copyright holders under Open Food Facts contributor terms.

Ask-OFF is an independent community discovery project and is not operated by the Open Food Facts organization.


License

This project is licensed under the Apache 2.0 License.


🌱 Building intelligent, transparent food discovery for Open Food Facts Canada.

About

AskOFF WebApp - An open-source web application for discovering, searching, comparing, and exploring Open Food Facts products with a clean, user-friendly experience.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages