Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

theodi/certificates-node

Repository files navigation

Open Data Certificate - Node.js Implementation

A modern, streamlined Node.js implementation of the Open Data Certificate questionnaire system, migrated from the original Ruby application.

πŸš€ Features

  • Simplified Architecture: MongoDB-based data model with clear separation of concerns
  • Numeric Achievement Levels: Streamlined 0-4 level system (none, basic, pilot, standard, exemplar)
  • RESTful API: Clean, modern API design
  • Real-time Level Calculation: Achievement levels calculated on-demand
  • Migration Support: Complete data migration from Ruby PostgreSQL to MongoDB
  • JSON-based Survey Definition: Flexible questionnaire structure using JSON files

πŸ“Š Architecture Overview

Data Model

Survey (Questionnaire Definition)
β”œβ”€β”€ Sections (Legal, Technical, etc.)
β”‚ └── Elements (Questions & Logic)
Dataset (Data Being Certified)
β”œβ”€β”€ Metadata (title, URL, etc.)
└── Owner Information
Certificate (Questionnaire Attempt + Result)
β”œβ”€β”€ References: surveyId, datasetId, userId
β”œβ”€β”€ Responses (Map of question β†’ answer)
β”œβ”€β”€ Achievement Level (0–4)
└── Publication State (draft, published, archived, superseded)

Achievement Levels

Levels are stored per-survey in Survey.levels as a map keyed by level index (0–4):

levels: {
 "0": { title, description, icon },
 "1": { title, description, icon },
 ...
}

During migration, defaults are set:

  • 0: "No level" β€” No level has yet been achieved (icon: images/badges/no_level_badge.png)
  • 1: "Bronze" β€” A fantastic start... (icon: images/badges/raw_level_badge.png)
  • 2: "Silver" β€” Extra effort went in... (icon: images/badges/pilot_level_badge.png)
  • 3: "Gold" β€” Regularly published open data... (icon: images/badges/standard_level_badge.png)
  • 4: "Platinum" β€” Above and beyond... (icon: images/badges/exemplar_level_badge.png)

The certificate view reads the survey’s levels to display the badge and description. The textual name is also mapped to a friendly string at render time.

πŸ› οΈ Setup Instructions

Prerequisites

  • Node.js 16+
  • MongoDB 4.4+
  • MySQL (for migration from Ruby app)

Installation

  1. Clone the repository

    git clone <repository-url>
    cd open-data-certificate-node
  2. Install dependencies

    npm install
  3. Environment Configuration Create a .env file (see config.env.example):

    # MongoDB
    MONGO_URL=mongodb://localhost:27017/open_data_certificate
    # MySQL (for migration)
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306
    MYSQL_DATABASE=certificates
    MYSQL_USER=root
    MYSQL_PASSWORD=password
    # Server
    PORT=3000
    NODE_ENV=development
    # Session Secret
    SESSION_SECRET=your_session_secret
    # ODI OAuth Credentials
    DJANGO_CLIENT_ID=your_django_client_id
    DJANGO_CLIENT_SECRET=your_django_client_secret
    DJANGO_CALLBACK_URL=/auth/django/callback
    # Google OAuth Credentials
    GOOGLE_CLIENT_ID=your_google_client_id
    GOOGLE_CLIENT_SECRET=your_google_client_secret
    GOOGLE_CALLBACK_URL=/auth/google/callback
  4. Database Setup

    # Start MongoDB
    mongod
    # Start MySQL (if migrating from Ruby app)
    # Ensure your Ruby app database is accessible
  5. Run Migration (Optional) If migrating from the Ruby application:

    Full Migration (recommended):

    npm run migrate:surveys:full
    # or clear existing surveys first
    npm run migrate:surveys:full:clear

    Single Survey Migration (for focused testing):

    # Default single import (falls back to ID 3252)
    npm run migrate:surveys:single
    # Specify a survey ID via CLI arg
    npm run migrate:surveys:single -- --id=4000
    # or
    npm run migrate:surveys:single -- --survey-id=4000
    # Specify via env
    SINGLE_MODE=true SINGLE_SURVEY_ID=4000 node scripts/migrateSurveys.js
    # Clear existing surveys first
    npm run migrate:surveys:single:clear -- --id=4000
  6. Start the Application

    # Development
    npm run dev
    # Production
    npm start

πŸ“ Project Structure

β”œβ”€β”€ models/ # MongoDB schemas
β”‚ β”œβ”€β”€ Survey.js
β”‚ β”œβ”€β”€ User.js
β”‚ β”œβ”€β”€ Dataset.js
β”‚ └── Certificate.js
β”œβ”€β”€ controllers/ # Web controllers
β”‚ β”œβ”€β”€ certificates.js
β”‚ └── surveys.js
β”œβ”€β”€ services/ # Business logic
β”‚ └── levelCalculationService.js
β”œβ”€β”€ routes/ # Routes
β”‚ β”œβ”€β”€ datasets.js # Public + My datasets + certificates (HTML/JSON via content negotiation)
β”‚ β”œβ”€β”€ redirects.js # Legacy redirects (locale-prefixed)
β”‚ └── surveys.js # Surveys index and criteria (HTML) + survey JSON (content negotiation)
β”œβ”€β”€ views/ # EJS templates
β”‚ β”œβ”€β”€ pages/
β”‚ β”‚ β”œβ”€β”€ datasets/
β”‚ β”‚ β”‚ β”œβ”€β”€ index.ejs
β”‚ β”‚ β”‚ └── dataset.ejs
β”‚ β”‚ └── certificates/
β”‚ β”‚ └── show.ejs
β”‚ └── partials/
β”‚ └── header.ejs
β”œβ”€β”€ public/ # Static assets (css, images, lib)
β”œβ”€β”€ scripts/ # Migration scripts
β”‚ β”œβ”€β”€ migrateSurveys.js
β”‚ └── migrateCertificates.js
└── .gitignore

πŸ”„ Migration from Ruby

The migration script extracts data from the original Ruby MySQL database and transforms it for the new MongoDB schema:

Migration Process

  1. Surveys: Converts survey definitions to MongoDB format
  2. Users: Migrates user accounts and preferences
  3. Datasets: Transfers dataset metadata
  4. Certificates: Converts questionnaire responses and achievement records

Test Migration Features

The migration script includes test mode options to validate the migration process:

  • Limited Records: Test with a small subset of data
  • Mixed States: Ensures variety in response set states (draft, published, archived)
  • Non-Blank Data: Filters out empty records to ensure meaningful test data
  • Balanced Sampling: Gets mix of admin/regular users, active/removed datasets, etc.

Running Migration

See scripts and npm commands:

Surveys:

npm run migrate:surveys:single # imports one (default 3252) or pass --id
npm run migrate:surveys:single:clear # clear then import one
npm run migrate:surveys:full # imports all per SQL criteria
npm run migrate:surveys:full:clear # clear then full import

Certificates/Datasets:

npm run migrate:certificates:single # migrate dataset 220763 by default (or --dataset-id)
npm run migrate:certificates:full # migrate all datasets with published certs

🎯 Key Improvements

Simplified Data Model

  • Unified Response Storage: All responses stored as key-value pairs
  • No Complex Joins: MongoDB document structure eliminates complex queries
  • Real-time Calculations: Achievement levels calculated on-demand

Modern Architecture

  • Routes: Consolidated /datasets router and legacy redirects router
  • MVC-ish: Controllers for pages and drill-down tables
  • Survey-driven Certificates: Certificate titles, per-question statement text, and display controls come from the survey
  • Numeric Levels: Simplified 0–4 achievement system, driven by Survey.levels

Performance Benefits

  • Better Scalability: MongoDB handles large datasets efficiently
  • Faster Queries: Document-based queries are more efficient
  • Reduced Complexity: Simplified data relationships

🌐 Route Definitions

Public web routes

  • GET / β†’ Home
  • GET /about β†’ About page
  • GET /datasets β†’ Browse published datasets (HTML) or JSON list via content negotiation
  • GET /datasets/:id β†’ Dataset drill-down (HTML) or JSON via content negotiation
  • GET /datasets/:datasetId/certificates β†’ List or redirect to a certificate for dataset
  • GET /datasets/:datasetId/certificates/:certificateId β†’ Render a certificate

Authenticated web routes

  • GET /datasets/my β†’ "My Datasets" (HTML) or JSON via content negotiation (owner; all for admin)
  • GET /auth/* β†’ Auth routes (login, profile, logout)

Legacy route redirects

  • /:locale/datasets/:datasetId/certificates β†’ 301 β†’ /datasets/:datasetId/certificates
  • /:locale/datasets/:datasetId/certificates/:certificateId β†’ 301 β†’ /datasets/:datasetId/certificates/:certificateId
  • /:locale/datasets/:datasetId/certificate β†’ 301 β†’ /datasets/:datasetId/certificate
  • /:locale/datasets/:datasetId/certificate/embed β†’ 301 β†’ /datasets/:datasetId/certificate/embed
  • /:locale/datasets/:datasetId/certificate/badge.png β†’ 301 β†’ /datasets/:datasetId/certificate/badge.png
  • /:locale/datasets/:datasetId/certificate/badge.js β†’ 301 β†’ /datasets/:datasetId/certificate/badge.js
  • /:locale/datasets/ β†’ 301 β†’ /datasets/

Survey routes (HTML + JSON via content negotiation)

  • GET /surveys β†’ Surveys index page (HTML) or grouped latest-per-locale list (JSON)
  • GET /surveys/:surveyId/criteria β†’ Survey criteria page (HTML)
  • GET /surveys/:surveyId β†’ Survey JSON schema (JSON) or criteria page (HTML)

Note on content negotiation: send Accept: application/json to receive JSON; otherwise HTML is rendered.

πŸ§ͺ Testing

# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run specific test file
npm test -- --testPathPattern=levelCalculationService

πŸš€ Deployment

Docker

# Build image
docker build -t open-data-certificate .
# Run container
docker run -p 3000:3000 open-data-certificate

Environment Variables (production example)

NODE_ENV=production
MONGO_URL=mongodb://your-mongo-host:27017/open_data_certificate
PORT=3000
SESSION_SECRET=your_production_session_secret
# Optional: OAuth in production
DJANGO_CLIENT_ID=...
DJANGO_CLIENT_SECRET=...
DJANGO_CALLBACK_URL=/auth/django/callback
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_CALLBACK_URL=/auth/google/callback

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Submit a pull request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Original Ruby implementation by the Open Data Institute
  • Survey structure based on the Open Data Certificate questionnaire
  • Migration patterns inspired by modern data migration practices

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /