A comprehensive web application for cataloging and exploring agricultural innovations developed by The Alliance of Bioversity International and CIAT. This platform enables users to browse, search, filter, and interact with innovation data through an intuitive interface.
The AICCRA Innovation Catalog serves as a centralized platform for discovering and exploring agricultural innovations. It provides stakeholders with tools to:
- Browse and search innovations with advanced filtering capabilities
- Visualize innovation distribution across African countries
- Explore innovation readiness scales and types
- View detailed innovation information including PDF reports
- Submit comments and reports on innovations
- Subscribe to newsletters for updates
This is a full-stack application consisting of:
- Frontend: A modern, static-first web application built with Astro and Vue.js
- Backend: A RESTful API built with NestJS that provides data access and business logic
- Database: PostgreSQL database managed through TypeORM
The application follows a microservices-ready architecture with clear separation between frontend and backend, enabling independent deployment and scaling.
- Framework: Astro 5.x with Vue 3 integration
- UI Library: PrimeVue 4.x with custom Aura theme
- Styling: TailwindCSS 4.x
- Build Output: Static site generation (SSG) with prerendering
- Deployment: Nginx container serving static files
- Framework: NestJS 11.x
- Database ORM: TypeORM 0.3.x
- Database: PostgreSQL (via
pgdriver) - API Documentation: Swagger/OpenAPI
- Deployment: Supports both traditional Node.js servers and AWS Lambda
- Containerization: Docker with multi-stage builds
- Frontend Server: Nginx Alpine
- Backend Runtime: Node.js 20 Alpine
- Cloud Support: AWS Lambda (serverless) and EC2 (traditional)
User Request
β
Frontend (Astro/Vue) - Static Site
β
API Calls (REST)
β
Backend (NestJS)
β
TypeORM
β
PostgreSQL Database
Key Features:
- Frontend is statically generated at build time for optimal performance
- Backend provides RESTful API endpoints for dynamic data
- API requests are made from Vue components using composables
- Cloudflare Turnstile integration for bot protection
- PDF generation and URL management for innovation reports
| Technology | Version | Purpose |
|---|---|---|
| Astro | ^5.13.7 | Static site generator and framework |
| Vue | ^3.5.21 | Reactive UI components |
| PrimeVue | ^4.3.9 | Component library |
| TailwindCSS | ^4.1.13 | Utility-first CSS framework |
| PrimeIcons | ^7.0.0 | Icon library |
| Technology | Version | Purpose |
|---|---|---|
| NestJS | ^11.0.1 | Node.js framework |
| TypeORM | ^0.3.26 | Object-Relational Mapping |
| PostgreSQL | ^8.16.3 | Relational database |
| Swagger | ^11.0.2 | API documentation |
| Serverless Express | ^4.10.2 | AWS Lambda adapter |
- Docker: Containerization for both frontend and backend
- Nginx: Web server for static frontend assets
- Node.js: Runtime environment (v20)
- TypeScript: Type-safe development
- Jest: Testing framework
- ESLint: Code linting
- Prettier: Code formatting
The project includes GitHub Actions workflows for continuous integration:
- Jenkins trigger workflows for automated builds
- Scheduled builds for regular deployments
MARLO-INNOVATION-CATALOG/
βββ client/ # Frontend application
β βββ src/
β β βββ components/ # Reusable Astro/Vue components
β β βββ composables/ # Vue composables for API calls
β β β βββ cloudflare-api/ # Cloudflare Turnstile integration
β β β βββ database-api/ # Backend API client
β β βββ content/ # Content configuration (vars, texts)
β β βββ entrypoints/ # Application entry points
β β βββ images/ # Image assets
β β βββ interfaces/ # TypeScript type definitions
β β βββ jsons/ # Static JSON data
β β βββ layouts/ # Page layouts
β β βββ pages/ # Route pages (Astro/Vue)
β β β βββ index/ # Home page components
β β β βββ innovation/ # Innovation detail pages
β β βββ providers/ # Vue providers (PrimeVue setup)
β β βββ styles/ # Global styles
β β βββ utils/ # Utility functions
β βββ public/ # Static public assets
β βββ dist/ # Build output (generated)
β βββ astro.config.mjs # Astro configuration
β βββ Dockerfile # Frontend container definition
β βββ package.json # Frontend dependencies
β
βββ server/ # Backend application
β βββ src/
β β βββ api/ # API routes and controllers
β β βββ common/ # Shared utilities
β β β βββ filters/ # Exception filters
β β β βββ logger/ # Logging service
β β β βββ middleware/ # Request middleware
β β βββ app.module.ts # Root application module
β β βββ main.ts # Application entry point (EC2)
β β βββ main-lambda-bootstrap.ts # Lambda bootstrap
β β βββ main.routes.ts # Route configuration
β βββ test/ # E2E tests
β βββ dist/ # Compiled output (generated)
β βββ main-lambda.js # Lambda handler entry point
β βββ Dockerfile # Backend container definition
β βββ package.json # Backend dependencies
β
βββ LICENSE # GNU GPL v3 License
βββ README.md # This file
-
composables/database-api/: Centralized API client for backend communicationuseApi.ts: Main API functions (innovations, comments, reports, etc.)useApiRequest.ts: HTTP request wrapper with retry logic
-
composables/cloudflare-api/: Cloudflare Turnstile integration for bot protection -
pages/index/: Home page with innovation catalogHome.vue: Main catalog view with filters and cardsInnovationFilters.vue: Filter sidebar componentInnovationCards.vue: Innovation card grid with paginationMapFilter.vue: Interactive Africa map visualizationReadinessExplorer.vue: Readiness scale visualization
-
pages/innovation/: Innovation detail pages[id].astro: Dynamic route for individual innovationsCommentCards.vue: User comments display
api/: API endpoints and controllerscommon/filters/: Global exception handlingcommon/logger/: Structured JSON loggingcommon/middleware/: Request logging middleware
Create a .env or .env.local file in the client/ directory:
# Backend API base URL
PUBLIC_API=https://api.example.com
# Cloudflare Turnstile (bot protection)
PUBLIC_TURNSTILE_SITE_KEY=your_site_key
PUBLIC_TURNSTILE_SECRET_KEY=your_secret_keyNote: In Astro, environment variables prefixed with PUBLIC_ are exposed to the client-side code.
Create a .env or .env.local file in the server/ directory:
Option 1: Connection String
DATABASE_URL=postgres://user:password@host:5432/database_nameOption 2: Individual Variables
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=innovation_catalog# Auto-sync schema in development (use with caution)
DB_SYNCHRONIZE=false
# Enable SQL query logging
DB_LOGGING=false
# Enable SSL connections
DB_SSL=false
DB_SSL_REJECT_UNAUTHORIZED=false# Server port (default: 3000)
PORT=3000- Node.js: v20 or higher
- npm: v9 or higher (or compatible package manager)
- PostgreSQL: v12 or higher (for backend)
- Docker (optional): For containerized development
git clone <repository-url>
cd MARLO-INNOVATION-CATALOGcd client
npm installcd ../server
npm installFrontend:
cd ../client
cp .env.example .env.local # If example exists, or create manually
# Edit .env.local with your configurationBackend:
cd ../server
cp .env.example .env.local # If example exists, or create manually
# Edit .env.local with your database configurationEnsure PostgreSQL is running and create a database:
CREATE DATABASE innovation_catalog;Update your .env.local file in the server/ directory with the correct database credentials.
cd client
npm run devThe frontend will be available at http://localhost:4321 (Astro default port).
Available Commands:
npm run dev- Start development server with hot reloadnpm run build- Build for productionnpm run preview- Preview production build locally
cd server
npm run start:devThe backend API will be available at http://localhost:3000 (or the port specified in PORT env variable).
Available Commands:
npm run start- Start production servernpm run start:dev- Start development server with watch modenpm run start:debug- Start with debugger attachednpm run start:prod- Start compiled production buildnpm run build- Compile TypeScript to JavaScript
Once the backend is running, access Swagger documentation at:
http://localhost:3000/api/docs
cd client
npm run buildThe static site will be generated in client/dist/ directory.
cd server
npm run buildThe compiled JavaScript will be in server/dist/ directory.
The frontend uses a multi-stage Docker build:
- Build Stage: Compiles the Astro application
- Test Stage: Runs static analysis (optional)
- Production Stage: Serves static files via Nginx
Build Command:
cd client
docker build -t innovation-catalog-frontend .Run Command:
docker run -p 80:80 innovation-catalog-frontendThe backend Dockerfile supports two deployment targets:
For AWS Lambda:
cd server
docker build --target=lambda -t innovation-catalog-lambda .For EC2/Traditional Server:
cd server
docker build --target=ec2 -t innovation-catalog-backend .
docker run -p 3000:3000 innovation-catalog-backendThe backend is configured for AWS Lambda using @vendia/serverless-express:
- Build the application:
npm run build - Package with
main-lambda.jsas the handler - Deploy to AWS Lambda with the Lambda runtime interface
- Configure API Gateway to route requests to the Lambda function
The Lambda handler is located at server/main-lambda.js and uses the bootstrap function from main-lambda-bootstrap.ts.
The frontend generates a static site that can be deployed to:
- AWS S3 + CloudFront: Static website hosting
- Netlify: Automatic deployments from Git
- Vercel: Zero-config deployments
- GitHub Pages: Free static hosting
- Any static hosting service: Upload the
dist/folder
The project includes GitHub Actions workflows that trigger Jenkins builds:
- Scheduled Builds: Regular automated builds
- Manual Triggers: On-demand builds via workflow dispatch
Configure your Jenkins instance to receive webhook triggers from GitHub Actions.
cd server
npm run testnpm run test:watchnpm run test:covCoverage Thresholds:
- Branches: 70%
- Functions: 70%
- Lines: 50%
- Statements: 50%
npm run test:e2eCurrently, the frontend does not include automated tests. Consider adding:
- Vitest: For unit testing Vue components
- Playwright: For E2E testing
- Astro Check: Already configured via
npm run astro -- check
- Environment Variables: Never commit
.envfiles. They are already in.gitignore - API Keys: Store sensitive keys in environment variables, not in code
- Cloudflare Turnstile: Bot protection is implemented for form submissions
- HTTPS: Always use HTTPS in production
- Database Credentials: Use secure connection strings and avoid hardcoding passwords
Backend:
cd server
npm run lintThe project uses ESLint with strict rules for TypeScript.
Backend:
cd server
npm run formatPrettier is configured for consistent code formatting.
The backend implements structured JSON logging via AppLoggerService:
- All requests are logged with middleware
- Errors are captured by global exception filter
- Logs include timestamps, levels, and context
- Schema Management: Use migrations instead of
DB_SYNCHRONIZEin production - Connection Pooling: TypeORM handles connection pooling automatically
- SSL: Enable SSL for production database connections
- Backups: Implement regular database backups
- Static Generation: Frontend is pre-rendered for optimal load times
- Image Optimization: Use Astro's built-in image optimization
- API Caching: Consider implementing caching strategies for frequently accessed data
- Database Indexing: Ensure proper indexes on frequently queried columns
- Astro Documentation
- NestJS Documentation
- Vue 3 Documentation
- PrimeVue Documentation
- TypeORM Documentation
For technical support, contact: MARLOSupport@cgiar.org
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.
Copyright (C) 2025 The Alliance of Bioversity International and CIAT
When contributing to this project:
- Follow the existing code style and formatting
- Write tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting
This is an active project maintained by The Alliance of Bioversity International and CIAT. For questions, issues, or contributions, please contact the development team.