Skip to content

wri/gri-restoration-diagnostic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

192 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Restoration Diagnostic Web Application

A production-ready Next.js 15 application for landscape restoration assessments featuring multi-language support (EN/ES/FR/PT), interactive maps, rich text editing, and XLSX export โ€” backed by TypeORM + PostgreSQL and deployed to AWS ECS Fargate via Terraform and GitHub Actions.

๐Ÿ—๏ธ Architecture

graph TB
    subgraph AWS Cloud
        subgraph VPC
            subgraph Public Subnets
                ALB[Application Load Balancer]
                ECS[ECS Fargate Tasks<br/>Ephemeral Public IPs]
            end
        end
        ECR[ECR Repository]
        CW[CloudWatch Logs]
        RDS[(RDS PostgreSQL)]
        S3[S3 - TF State]
    end

    Client([Browser]) -->|HTTPS| ALB
    ALB --> ECS
    ECS --> RDS
    GH([GitHub Actions]) -->|Deploy| ECR
    ECR --> ECS
    ECS -->|Logs| CW
Loading

๐Ÿงฐ Tech Stack

Layer Technology
Framework Next.js 15 (App Router), React 19
UI WRI Design System, Chakra UI v3, Tailwind CSS, TipTap Rich Text Editor
Forms React Hook Form
Database PostgreSQL 17, TypeORM 0.3
Auth Bcrypt password hashing, session tokens (Web Crypto API)
i18n 4 languages (EN, ES, FR, PT) with JSON translation files
Maps Interactive map components with layer/legend controls
Export XLSX assessment export
Analytics Google Tag Manager, Hotjar
Deployment AWS ECS Fargate, ALB, ECR, Terraform
CI/CD GitHub Actions (QA, Production, PR checks)
Testing Jest, React Testing Library

๐Ÿ“ Project Structure

.
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/
โ”‚       โ”œโ”€โ”€ deploy-qa.yml              # QA deployment workflow
โ”‚       โ”œโ”€โ”€ deploy-production.yml      # Production deployment workflow
โ”‚       โ”œโ”€โ”€ pr-check.yml               # Pull request validation
โ”‚       โ””โ”€โ”€ destroy.yml                # Infrastructure teardown
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ app/                           # Next.js App Router
โ”‚   โ”‚   โ”œโ”€โ”€ api/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ health/               # Health check endpoint
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ assessments/           # Assessment REST API
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ route.ts           #   POST create assessment
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ [id]/
โ”‚   โ”‚   โ”‚           โ”œโ”€โ”€ answers/       #   GET/POST answers
โ”‚   โ”‚   โ”‚           โ”œโ”€โ”€ contributors/  #   GET/POST/DELETE contributors
โ”‚   โ”‚   โ”‚           โ”œโ”€โ”€ export-responses/ # XLSX export
โ”‚   โ”‚   โ”‚           โ”œโ”€โ”€ login/         #   Password authentication
โ”‚   โ”‚   โ”‚           โ”œโ”€โ”€ preparation/   #   Preparation workflow
โ”‚   โ”‚   โ”‚           โ””โ”€โ”€ questions/     #   GET questions by language
โ”‚   โ”‚   โ”œโ”€โ”€ assessment/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ setup/                 # Assessment setup form
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ [id]/
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ page.tsx           # Overview & password prompt
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ created/           # Success page
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ preparation/       # Multi-step preparation
โ”‚   โ”‚   โ”‚       โ”‚   โ””โ”€โ”€ [step]/
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ [theme]/           # Theme pages (Motivate/Enable/Implement)
โ”‚   โ”‚   โ”œโ”€โ”€ auth/                      # Sign-in & sign-up pages
โ”‚   โ”‚   โ””โ”€โ”€ welcome/                   # Welcome page
โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ”œโ”€โ”€ assessment/                # Assessment UI components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DiagnosticPreparation/ #   Multi-step preparation form
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Overview/              #   Assessment overview & export
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AnswerOptions.tsx      #   Yes/Partly/No/NA selection
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ChakraRichTextEditor.tsx # Rich text editor
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ContributorsCombobox.tsx # Team member selection
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ FollowUpQuestions.tsx   #   Dynamic follow-ups
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ PasswordPrompt.tsx     #   Access control
โ”‚   โ”‚   โ”œโ”€โ”€ Map/                       # Interactive map with layers & legends
โ”‚   โ”‚   โ”œโ”€โ”€ static/landing/            # Landing page sections
โ”‚   โ”‚   โ”œโ”€โ”€ icons/                     # 50+ custom SVG icons
โ”‚   โ”‚   โ”œโ”€โ”€ Footer/
โ”‚   โ”‚   โ”œโ”€โ”€ Providers/                 # Chakra UI & language context
โ”‚   โ”‚   โ””โ”€โ”€ ui/                        # Shared UI (DatePicker, RichText, Loader)
โ”‚   โ”œโ”€โ”€ db/                            # Database layer
โ”‚   โ”‚   โ”œโ”€โ”€ schema.dbml                # Database schema (source of truth)
โ”‚   โ”‚   โ”œโ”€โ”€ data-source.ts             # TypeORM configuration
โ”‚   โ”‚   โ”œโ”€โ”€ entities/                  # 8 TypeORM entities
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Assessment.entity.ts   #   Assessment instance
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Answer.entity.ts       #   Answer (yes/partly/no/na)
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AnswerContributor.entity.ts # Junction table
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Contributor.entity.ts  #   Team members
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Diagnostic.entity.ts   #   Assessment template
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Lead.entity.ts         #   Assessment lead (demographics)
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Question.entity.ts     #   Questions (3 themes)
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ Region.entity.ts       #   Geography & GIS
โ”‚   โ”‚   โ”œโ”€โ”€ migrations/                # 15+ database migrations
โ”‚   โ”‚   โ”œโ”€โ”€ seeds/                     # Diagnostic & question seeds
โ”‚   โ”‚   โ”œโ”€โ”€ queries/                   # Complex assessment queries
โ”‚   โ”‚   โ””โ”€โ”€ scripts/                   # DB utility scripts
โ”‚   โ”œโ”€โ”€ i18n/                          # Internationalization
โ”‚   โ”‚   โ”œโ”€โ”€ translations/              # EN, ES, FR, PT JSON files
โ”‚   โ”‚   โ””โ”€โ”€ scripts/                   # Import/export/validate scripts
โ”‚   โ”œโ”€โ”€ hooks/                         # Custom React hooks
โ”‚   โ”‚   โ”œโ”€โ”€ useAutoSave.ts             #   Auto-save answers
โ”‚   โ”‚   โ”œโ”€โ”€ useAssessmentSetupForm.ts  #   Setup form logic
โ”‚   โ”‚   โ”œโ”€โ”€ useRichTextEditor.ts       #   Editor state
โ”‚   โ”‚   โ””โ”€โ”€ useResponsiveFlags.ts      #   Responsive helpers
โ”‚   โ”œโ”€โ”€ contexts/                      # React contexts
โ”‚   โ”‚   โ””โ”€โ”€ LanguageContext.tsx         #   Global language state
โ”‚   โ”œโ”€โ”€ constants/                     # App constants & options
โ”‚   โ”œโ”€โ”€ types/                         # TypeScript type definitions
โ”‚   โ”œโ”€โ”€ utils/                         # Utilities (session, rate-limiter, xlsx)
โ”‚   โ””โ”€โ”€ middleware.ts                  # Auth middleware for protected routes
โ”œโ”€โ”€ terraform/
โ”‚   โ”œโ”€โ”€ backend-setup/                 # Terraform state backend (S3 + DynamoDB)
โ”‚   โ”œโ”€โ”€ infrastructure/                # VPC, ALB, ECS, ECR, Security Groups
โ”‚   โ””โ”€โ”€ environments/                  # QA & production tfvars
โ”œโ”€โ”€ docs/resources/                    # CSV question sources & schema reference
โ”œโ”€โ”€ Dockerfile                         # Multi-stage build (standalone Next.js)
โ”œโ”€โ”€ docker-compose.yml                 # Local PostgreSQL for development
โ””โ”€โ”€ package.json

๐Ÿ—„๏ธ Database Schema

erDiagram
    Diagnostic ||--o{ Question : contains
    Diagnostic ||--o{ Assessment : "template for"
    Assessment }o--|| Lead : "led by"
    Assessment }o--|| Region : "scoped to"
    Assessment ||--o{ Answer : has
    Assessment ||--o{ Contributor : has
    Answer }o--|| Question : "responds to"
    Answer ||--o{ AnswerContributor : "attributed to"
    Contributor ||--o{ AnswerContributor : participates

    Diagnostic {
        uuid id PK
        string title
        string version
        string language
    }
    Question {
        uuid id PK
        string questionCode
        string theme "Motivate-Enable-Implement"
        string enablingCondition
        string keySuccessFactor
        string questionText
        int sortOrder
        string locale
    }
    Assessment {
        uuid id PK
        string passwordHash
        string projectType "GEF_8-WRI-other"
        string status "draft-inprogress-completed-archived"
        int diagnosticYear
        timestamp submittedAt
    }
    Lead {
        uuid id PK
        string name
        string email
        string jobTitle
        string organization
        string gender
        string ageRange
    }
    Region {
        uuid id PK
        string regionName
        string geographyType
        string countries
        string ecosystems
        string gisUrl
    }
    Answer {
        uuid id PK
        string value "yes-partly-no-na"
        text rationale
        text notes
        string status "not_started-in_progress-complete"
    }
    Contributor {
        uuid id PK
        string name
    }
    AnswerContributor {
        uuid contributorId PK
        uuid answerId PK
    }
Loading

๐Ÿ”Œ API Endpoints

Method Endpoint Description
GET /api/health Health check
POST /api/assessments Create assessment (returns ID + password)
GET /api/assessments/[id]/questions Get questions by language
GET /api/assessments/[id]/answers List all answers
POST /api/assessments/[id]/answers Create answers
GET /api/assessments/[id]/contributors List contributors
POST /api/assessments/[id]/contributors Add contributor
DELETE /api/assessments/[id]/contributors Remove contributor
POST /api/assessments/[id]/login Verify password & create session
GET /api/assessments/[id]/preparation Get preparation status
POST /api/assessments/[id]/preparation Save preparation data
GET /api/assessments/[id]/export-responses Export assessment to XLSX

๐ŸŒ Internationalization (i18n)

Four languages are supported with both UI and question translations:

Language Code UI File Questions File
English en en.json questions-en.json
Spanish es es.json questions-es.json
French fr fr.json questions-fr.json
Portuguese pt pt.json questions-pt.json

Translation files are in src/i18n/translations/. Management scripts:

npm run i18n:import-csv          # Import questions from CSV
npm run i18n:export-questions     # Export questions to JSON
npm run i18n:import-questions     # Import questions from JSON
npm run i18n:validate            # Validate translation completeness
npm run i18n:cleanup             # Remove duplicate questions

๐Ÿš€ Getting Started

Prerequisites

1. Clone and Install Dependencies

git clone <repository-url>
cd gri-restoration-diagnostic

# Use correct Node.js version
nvm use

# Install dependencies
npm install

2. Database Setup (AWS RDS)

The application uses a shared AWS RDS PostgreSQL instance (rd-app-db2) across all environments. Each environment (dev, qa, production) has its own database within the same RDS instance. Access to the DB instance is controlled by an AWS security group (rd-app-db1-sg), and each environment has access to it. Folks trying to connect to the DB directly need to add their external IP address to the AWS security group.

Security Group Configuration

The RDS instance is publicly accessible to support local development. You must add your external IP to the AWS security group.

  1. Add inbound rule:
    • Type: PostgreSQL
    • Port: 5432
    • Source: <your-ip-address>/32
    • Description: "[Your Name]"

Configure Environment Variables

# Copy example environment file
cp .env.example .env

Update .env with RDS credentials:

# Database Configuration (AWS RDS)
DB_HOST=rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com
DB_PORT=5432
DB_USER=rduser
DB_PASSWORD=<get-from-aws-parameter-store>
DB_NAME=dev  # or 'qa', 'production'

# TypeORM Configuration
TYPEORM_SYNCHRONIZE=false
TYPEORM_LOGGING=true

# Application
NODE_ENV=development

# SSL Configuration (enable for production)
DATABASE_SSL_REJECT_UNAUTHORIZED=false

Getting Database Credentials:

Get your external IP:

curl ifconfig.me

Run Database Migrations

# Run migrations to create tables
npm run migration:run

# Seed initial diagnostic questions (24 questions)
npm run seed:run

Generate migrations when schema changes:

npm run migration:generate

Verify Database Setup

# Connect to dev database
psql -h rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com -U postgres -d dev

# List tables
\dt

# View diagnostic seed data
SELECT id, version, language FROM diagnostic;

# Exit
\q

Note: If connection times out, verify your IP is in the rd-app-db1-sg security group.

3. Set Up Terraform State Backend

Before deploying infrastructure, you need to create the S3 bucket and DynamoDB table for Terraform state:

cd terraform/backend-setup

# Make the script executable
chmod +x setup.sh

# Run setup (uses default values)
./setup.sh

# Or customize with environment variables
AWS_REGION=us-east-1 PROJECT_NAME=rd-app ./setup.sh

4. Configure GitHub Repository

  1. Create a new GitHub repository

  2. Push this code to the repository

  3. Create the following branches:

    • main or production - Production deployments
    • qa - QA deployments
  4. Add GitHub variables for AWS permissions (Settings โ†’ Secrets and variables โ†’ Actions -> Variables):

    • OIDC_ROLE - ARN from AWS console for role GitHubActionsOIDC

5. Required AWS IAM Permissions

The AWS credentials need permissions for:

  • ECR (create/push images)
  • ECS (manage clusters, services, tasks)
  • EC2 (VPC, subnets, security groups)
  • ELB (Application Load Balancers)
  • IAM (create roles and policies)
  • CloudWatch (logs)
  • S3 (Terraform state)
  • DynamoDB (Terraform locks)

6. Deploy

Push to the appropriate branch to trigger deployment:

# Deploy to QA
git checkout -b qa
git push origin qa

# Deploy to Production
git checkout main
git push origin main

๐Ÿ”ง Local Development

# Run development server
npm run dev

# Run tests
npm test

# Run tests with coverage (CI mode)
npm run test:ci

# Lint
npm run lint

# Build for production
npm run build

# Start production server
npm start

Database Management Commands

Migrations:

# Generate new migration (after entity changes)
npm run migration:generate

# Run pending migrations
npm run migration:run

# Revert last migration
npm run migration:revert

Seeding:

# Run seed data
npm run seed:run

Direct Database Access:

# Connect to dev database
psql -h rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com -U postgres -d dev

# Connect to QA database
psql -h rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com -U postgres -d qa

# Connect to production database
psql -h rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com -U postgres -d production

โš ๏ธ Legacy Docker Commands (Deprecated):

# These commands are no longer used (RDS replaced local Docker)
# npm run db:start
# npm run db:stop
# npm run db:reset

Docker Build

# Build image
docker build -t rd-app .

# Run container
docker run -p 3000:3000 rd-app

๐Ÿ“‹ Environment Configuration

Database (Shared RDS Instance)

  • RDS Endpoint: rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com
  • Engine: PostgreSQL 17
  • Databases:
    • dev - Development database
    • qa - QA database
    • production - Production database
  • Access: Publicly accessible with security group IP allowlist
  • Credentials: Stored in AWS Systems Manager Parameter Store

QA Environment

  • VPC CIDR: 10.0.0.0/16
  • Database: qa
  • Resources: 256 CPU / 512 MB Memory
  • Desired count: 1 task
  • Auto-scaling: 1-2 tasks

Production Environment

  • VPC CIDR: 10.1.0.0/16
  • Database: production
  • Resources: 512 CPU / 1024 MB Memory
  • Desired count: 2 tasks
  • Auto-scaling: 2-10 tasks

๐Ÿ”„ CI/CD Workflows

Workflow Trigger Description
deploy-qa.yml Push to qa branch Deploy to QA environment
deploy-production.yml Push to main/production Deploy to Production
pr-check.yml Pull requests Run tests and validate
destroy.yml Manual Tear down infrastructure

๐Ÿ—‘๏ธ Teardown

Destroy Infrastructure (via GitHub Actions)

  1. Go to Actions โ†’ Destroy Infrastructure
  2. Select the environment (qa or production)
  3. Type DESTROY to confirm
  4. Run workflow

Destroy Terraform State Backend

cd terraform/backend-setup
chmod +x teardown.sh
./teardown.sh

โš ๏ธ Warning: This will permanently delete all Terraform state files!

๐Ÿ“Š Monitoring

  • CloudWatch Logs: /ecs/rd-app-{environment}
  • Container Insights: Enabled on ECS cluster
  • Health Check: GET /api/health

๐Ÿ” Security Features

  • VPC with public subnets; exposure limited via security groups and ALB
  • ECS Fargate tasks with ephemeral public IPs (no NAT Gateway)
  • Security groups limiting traffic
  • S3 bucket versioning and encryption for Terraform state
  • ECR image scanning on push
  • Non-root container user
  • HTTPS headers configured in Next.js
  • Bcrypt password hashing for assessment access
  • Session token authentication (Web Crypto API, Edge Runtime)
  • Rate limiting on API endpoints
  • Auth middleware protecting assessment routes
  • AWS RDS SSL connections (CA bundle in Docker image)

๐Ÿ’ฐ Cost Optimization

  • Use FARGATE_SPOT for non-production workloads
  • Auto-scaling based on CPU/Memory utilization
  • ECR lifecycle policies to clean old images
  • No NAT Gateway โ€” ECS tasks use ephemeral public IPs

๐Ÿ“ Customization

Adding Environment Variables

  1. Update terraform/environments/{env}.tfvars:
app_environment_variables = {
  "MY_VAR" = "my-value"
}
  1. Redeploy

Changing Resources

Edit terraform/environments/{env}.tfvars:

container_cpu    = 512   # 0.5 vCPU
container_memory = 1024  # 1 GB
desired_count    = 3

๐Ÿ†˜ Troubleshooting

Common Issues

  1. Database connection fails

    • Verify your IP is in the rd-app-db1-sg security group allowlist
    • Check .env has correct RDS credentials from Parameter Store
    • Test connection: psql -h rd-app-db2.c9o0i0gg61en.us-east-1.rds.amazonaws.com -U postgres -d dev
    • Verify RDS instance is running in AWS Console
  2. Connection timeout to RDS

    • Add your external IP to security group: curl ifconfig.me
    • Check VPN/firewall settings aren't blocking port 5432
    • Verify you're using the correct database name (dev/qa/production)
  3. Migration generation fails

    • Ensure entities are properly imported in data-source.ts
    • Verify TypeORM can connect to RDS (check credentials)
    • Check entity decorators and column types
    • Review tsconfig.typeorm.json for CommonJS compatibility
  4. Deployment fails at ECS service stability

    • Check CloudWatch logs
    • Verify health check endpoint returns 200
    • Check security group rules
    • Ensure ECS tasks can connect to RDS
  5. Terraform state lock error

    • Wait for other deployments to complete
    • If stuck, manually release lock in DynamoDB
  6. Docker build fails

    • Ensure all dependencies are in package.json
    • Check for missing files in .dockerignore

๐Ÿ“„ License

MIT

About

No description, website, or topics provided.

Resources

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

โšก