Vue 3 + TypeScript frontend for the STAC-Atlas project. This is a modern single-page application (SPA) that provides a user-friendly interface for searching, browsing, and exploring STAC (SpatioTemporal Asset Catalog) collections.
- Overview
- Getting Started
- Environment Variables
- Testing
- How It Works
- Design Decisions
- Libraries & Dependencies
- Project Structure
- Documentation
STAC-Atlas UI is a responsive web application that connects to the STAC-Atlas API to provide:
- Collection Search: Full-text search across STAC collection titles, descriptions, and keywords
- Advanced Filtering: Filter by bounding box, temporal range, provider, license, and more
- Interactive Maps: Visualize collection spatial extents using MapLibre GL
- Pagination: Efficiently browse through large numbers of collections
- Internationalization: Support for English and German languages
- CQL2 Filtering: Advanced query support using OGC CQL2 filter expressions
- Node.js >= 18.x
- npm >= 9.x (or pnpm)
- Docker and Docker Compose (for containerized deployment)
# Navigate to the UI directory
cd ui
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Update queryables data (providers/licenses)
npm run update-queryablesThe development server runs at http://localhost:5173/ with hot module replacement (HMR) enabled.
The UI can be deployed as a standalone Docker container serving static files via Nginx.
# From the ui directory
cd ui
# Build and start the container
docker-compose up -d
# Stop the container
docker-compose downThe UI will be available at http://localhost:8080.
# Build the Docker image
docker build -t stac-atlas-ui .
# Run the container
docker run -d -p 8080:80 --name stac-atlas-ui stac-atlas-ui
# Stop and remove
docker stop stac-atlas-ui && docker rm stac-atlas-uiTo run the complete STAC-Atlas stack (UI, API, Database), use the root docker-compose.yml:
# From the project root
docker-compose up -dThe UI uses Vite's environment variable system. Variables must be prefixed with VITE_ to be exposed to the client.
| Variable | Default | Description |
|---|---|---|
VITE_API_BASE_URL |
http://localhost:3000 |
Base URL of the STAC-Atlas API. Change this to point to your API server in production. |
Copy example.env to .env and adjust values as needed:
cp example.env .envExample .env file:
# API Configuration
VITE_API_BASE_URL=http://localhost:3000
# Production example
# VITE_API_BASE_URL=https://api.stac-atlas.example.comNote: Environment variables are embedded at build time. For Docker deployments, you need to rebuild the image after changing .env values, or use runtime configuration injection.
The UI includes end-to-end (E2E) tests using Playwright to verify core functionality as specified in the project requirements (bid.md).
# Run all tests (starts dev server automatically)
npm run test:e2e
# Run tests with interactive UI
npm run test:e2e:ui
# Run tests with visible browser
npm run test:e2e:headed
# View HTML test report
npm run test:e2e:reportThe E2E tests cover the following areas (referencing bid.md requirements):
| Test File | Coverage | bid.md Reference |
|---|---|---|
search.spec.ts |
Search interface, filter availability | 6.1.3.1, 6.1.3.4 |
map.spec.ts |
Map display, bounding box selection | 6.1.3.3, 6.1.3.5 |
collection-detail.spec.ts |
Collection details, source links, items | 6.1.3.6, 6.1.3.7, 6.1.3.8 |
accessibility.spec.ts |
Responsive design, i18n, accessibility | 6.2.2.1 - 6.2.2.4 |
- Chromium browser is installed automatically via Playwright
- Dev server runs on
http://localhost:5173(started automatically) - No external API required for basic UI tests
┌─────────────────────────────────────────────────────────────┐
│ STAC-Atlas UI │
├─────────────────────────────────────────────────────────────┤
│ Views (Home, CollectionDetail) │
│ └── Components (FilterSection, SearchResults, ...) │
│ └── Composables (useI18n, useQueryables) │
│ └── Services (API calls) │
│ └── Stores (Pinia state management) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ STAC-Atlas API │
│ (REST API) │
└─────────────────┘
-
Collection Search & Filtering
- The
FilterSectioncomponent provides UI controls for all filter parameters - Filters are managed centrally in the
filterStore(Pinia store) - Changes trigger API requests with debounced search queries
- The
-
API Communication
- The
api.tsservice handles all HTTP requests to the STAC-Atlas API - Supports collection search parameters:
q,bbox,datetime,provider,license,filter(CQL2) - Implements RFC 7807 error response parsing
- The
-
State Management
- Pinia store (
filterStore) maintains filter state, pagination, and loading states - Reactive computed properties automatically format API request parameters
- Pinia store (
-
Internationalization
- Custom
useI18ncomposable provides English/German translations - Language preference is persisted in localStorage
- Browser language is auto-detected on first visit
- Custom
-
Queryables
- Available providers and licenses are loaded from a static JSON file
- The file is generated by the
update-queryablesscript which fetches from the API - Auto-refreshes every 24 hours
Decision: Use Vue 3 with the Composition API exclusively (no Options API).
Rationale:
- Better TypeScript integration with improved type inference
- More flexible code organization through composables
- Improved code reusability across components
- Better tree-shaking for smaller bundle sizes
Decision: Use Vite instead of Vue CLI or Webpack.
Rationale:
- Significantly faster development server startup (native ES modules)
- Faster hot module replacement (HMR)
- Simpler configuration
- Better TypeScript support out of the box
- Modern build output with Rollup
Decision: Use Pinia instead of Vuex.
Rationale:
- Official Vue 3 state management library
- Better TypeScript support with full type inference
- Simpler API without mutations (just actions)
- Modular by design - each store is independent
- DevTools support built-in
Decision: Implement a lightweight custom i18n solution instead of using vue-i18n.
Rationale:
- Simpler implementation for a two-language application
- Smaller bundle size (no external dependency)
- Reactive language switching with Vue's reactivity system
- Full type safety for translation keys
Decision: Use MapLibre GL instead of Leaflet or other mapping libraries.
Rationale:
- Open-source and free (forked from Mapbox GL before license change)
- WebGL-based rendering for smooth performance
- Better handling of vector tiles
- Modern API with good TypeScript support
Decision: Fetch filter options (providers, licenses) from a static JSON file instead of the API.
Rationale:
- Reduces API load - no need to query for filter options on every page load
- Faster initial page load
- Can be cached aggressively
- Updated via a script that runs periodically
Decision: Use CSS custom properties for theming instead of a CSS-in-JS solution.
Rationale:
- Native browser support - no runtime overhead
- Easy theme switching (future dark mode support)
- Works well with scoped component styles
- No additional library needed
Decision: Use a multi-stage Dockerfile with Node for building and Nginx for serving.
Rationale:
- Smaller final image size (Nginx Alpine is ~20MB)
- No Node.js runtime needed in production
- Efficient static file serving with Nginx
- Built-in gzip compression and caching headers
| Library | Version | Purpose |
|---|---|---|
| Vue | 3.5.x | Progressive JavaScript framework for building user interfaces |
| TypeScript | 5.9.x | Typed superset of JavaScript for better developer experience and code quality |
| Library | Version | Purpose |
|---|---|---|
| Vue Router | 4.6.x | Official client-side router for Vue.js with history mode support |
| Pinia | 3.0.x | State management library for Vue with TypeScript support |
| Library | Version | Purpose |
|---|---|---|
| MapLibre GL | 5.13.x | Open-source WebGL-based library for interactive maps and spatial extent visualization |
| Lucide Vue Next | 0.556.x | Icon library providing consistent, customizable SVG icons throughout the UI |
| Library | Version | Purpose |
|---|---|---|
| VueUse | 14.1.x | Collection of Vue composition utilities for common tasks (debounce, localStorage, etc.) |
| Library | Purpose |
|---|---|
| Vite | Fast build tool with native ES modules support and HMR |
| vue-tsc | TypeScript type-checking for Vue single-file components |
| @vitejs/plugin-vue | Official Vue plugin for Vite |
ui/
├── public/ # Static assets (served as-is)
│ └── data/ # Generated queryables JSON
├── scripts/ # Build and utility scripts
│ └── update-queryables.js # Fetches providers/licenses from API
├── src/
│ ├── assets/ # Static assets (bundled)
│ │ └── styles/ # Global CSS architecture
│ ├── components/ # Reusable UI components
│ │ ├── BoundingBoxModal.vue # Map-based bbox selection
│ │ ├── CustomSelect.vue # Styled select dropdown
│ │ ├── FilterSection.vue # Main filter controls
│ │ ├── InfoCard.vue # Collection info display
│ │ ├── ItemCard.vue # Collection card in grid
│ │ ├── Navbar.vue # Navigation header
│ │ ├── SearchResultCard.vue # Search result item
│ │ ├── SearchResults.vue # Results grid layout
│ │ └── SearchSection.vue # Search input area
│ ├── composables/ # Shared composition functions
│ │ ├── useI18n.ts # Internationalization logic
│ │ └── useQueryables.ts # Filter options management
│ ├── i18n/ # Translation files
│ │ ├── en.ts # English translations
│ │ ├── de.ts # German translations
│ │ └── index.ts # i18n exports
│ ├── router/ # Vue Router configuration
│ │ └── index.ts # Route definitions
│ ├── services/ # API communication layer
│ │ └── api.ts # STAC-Atlas API client
│ ├── stores/ # Pinia state stores
│ │ └── filterStore.ts # Filter and pagination state
│ ├── types/ # TypeScript type definitions
│ │ └── collection.ts # STAC collection types
│ ├── views/ # Page-level components
│ │ ├── Home.vue # Main search page
│ │ └── CollectionDetail.vue # Single collection view
│ ├── App.vue # Root component
│ └── main.ts # Application entry point
├── docs/ # Internal documentation
│ ├── STRUCTURE.md # Folder structure guide
│ ├── STYLING.md # CSS architecture guide
│ └── i18n.md # Internationalization guide
├── docker-compose.yml # Docker Compose configuration
├── Dockerfile # Multi-stage Docker build
├── nginx.conf # Nginx server configuration
├── package.json # npm dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
└── .env # Environment variables (not in git)
- Folder Structure Guide - Detailed breakdown of project organization
- Styling Guide - CSS architecture and component styling patterns
- Internationalization - How to add and manage translations
The UI requires the STAC-Atlas API to be running. The API should support:
GET /collections- Search and list collectionsGET /collections/:id- Get single collection details- Query parameters:
q,bbox,datetime,limit,token,provider,license,filter,filter-lang
See the API documentation for full details.
This project is part of the STAC-Atlas project. See the LICENSE file in the project root for details.