Skip to main content
Jira progress: loading…

EcoWorld Academy Platform — Deployment Guide

Viroway Ltd | Phase 1


Prerequisites

  • AWS CLI installed and configured: aws configure
  • Node.js 20+ installed: node --version
  • AWS CDK installed: npm install -g aws-cdk
  • Active HubSpot account with Private Apps access

Step 1 — HubSpot setup (15 minutes)

JiraTaskUnlinkedZYZ-874EWA-DEP#step-1-hubspot-setup-15-minutes#1

1.1 Create Private App

  1. In HubSpot: Settings → Integrations → Private Apps → Create Private App
  2. Name: EcoWorld Academy Sync
  3. Description: Syncs Academy learner registrations as HubSpot contacts
  4. Required scopes:
    • crm.objects.contacts.read
    • crm.objects.contacts.write
    • crm.objects.companies.read
    • crm.objects.companies.write
    • crm.schemas.contacts.read
  5. Click Create app → copy the access token

1.2 Add custom Company properties

In HubSpot: Settings → Properties → Company properties → Create property

Property name (internal)LabelType
ecoworld_company_codeEcoWorld company codeSingle-line text
ecoworld_seats_purchasedAcademy seats purchasedNumber
ecoworld_course_assignedCourse assignedSingle-line text
ecoworld_cohort_startCohort start dateDate
ecoworld_enrolment_statusAcademy enrolment statusDropdown: Pending / Active / Completed
ecoworld_completion_pctTraining completion %Number
ecoworld_certificates_issuedCertificates issuedNumber
ecoworld_last_dashboard_syncLast dashboard syncDate

1.3 Add custom Contact properties

Property name (internal)LabelType
ecoworld_user_idEcoWorld user ID (Cognito)Single-line text
ecoworld_completion_pctTraining completion %Number
ecoworld_certificate_issuedCertificate issued dateDate
ecoworld_last_activeLast active in AcademyDate

1.4 Populate company records

For each client company:

  1. Find their Company record in HubSpot
  2. Set ecoworld_company_code to a unique code (e.g., NORSK-HYDRO-2026)
  3. Set ecoworld_seats_purchased, ecoworld_course_assigned, ecoworld_cohort_start
  4. This code is what you include in the learner invite link: https://academy.ecoworld.ai/register?company=NORSK-HYDRO-2026

Step 2 — Store secrets in AWS (5 minutes)

# HubSpot Private App token
aws secretsmanager create-secret \
--name ecoworld/hubspot-token \
--secret-string '{"token":"YOUR_HUBSPOT_TOKEN_HERE"}' \
--region eu-west-1

# HubSpot Portal ID (find in HubSpot Settings → Account Setup)
aws secretsmanager create-secret \
--name ecoworld/hubspot-portal-id \
--secret-string '{"portalId":"YOUR_PORTAL_ID"}' \
--region eu-west-1

Step 3 — Deploy AWS infrastructure (10 minutes)

cd infra

# Install CDK dependencies
npm init -y
npm install aws-cdk-lib constructs

# Bootstrap CDK (first time only, per account/region)
npx cdk bootstrap aws://YOUR_ACCOUNT_ID/eu-west-1

# Preview what will be created
npx cdk diff

# Deploy everything
WEBFLOW_ORIGIN=https://academy.ecoworld.ai npx cdk deploy EcoWorldAcademy

Save the outputs — you'll need them for Step 4:

EcoWorldAcademy.UserPoolId        = eu-west-1_XXXXXXXXX
EcoWorldAcademy.UserPoolClientId = XXXXXXXXXXXXXXXXXXXXXXXXXX
EcoWorldAcademy.ApiEndpoint = https://XXXXXXXXXX.execute-api.eu-west-1.amazonaws.com/v1
EcoWorldAcademy.CognitoHostedUI = https://ecoworld-prod.auth.eu-west-1.amazoncognito.com

Step 4 — Configure Webflow (10 minutes)

4.1 Update the JS config

Open frontend/ecoworld-academy.js and update the CONFIG section:

const CONFIG = {
userPoolId: "eu-west-1_XXXXXXXXX", // From CDK output
clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXX", // From CDK output
cognitoDomain: "ecoworld-prod.auth.eu-west-1.amazoncognito.com",
apiBase: "https://XXXXXXXXXX.execute-api.eu-west-1.amazonaws.com/v1",
siteUrl: "https://academy.ecoworld.ai",
postLoginPath: "/academy",
};

4.2 Add to Webflow

  1. In Webflow: Site Settings → Custom Code → Footer Code
  2. Paste the entire frontend/ecoworld-academy.js content inside <script> tags
  3. Publish the site

4.3 Add Webflow page attributes

On each page body element, add:

  • Workbook page: data-eco-page="workbook"
  • Dashboard page: data-eco-page="dashboard"
  • Risk tool page: data-eco-page="risk-tool"

On buttons:

  • Login button: data-eco-action="login"
  • Logout button: data-eco-action="logout"

On nav elements:

  • User name: data-eco-user="name"
  • Company name: data-eco-user="company"

Show/hide by login state:

  • Logged-in elements: data-eco-auth="logged-in"
  • Logged-out elements: data-eco-auth="logged-out"

Step 5 — Test the full flow (30 minutes)

5.1 Create a test company in HubSpot

  • Add company: Test Company Ltd
  • Set ecoworld_company_code = TEST-2025
  • Set ecoworld_seats_purchased = 5

5.2 Test learner registration

  1. Open: https://academy.ecoworld.ai/register?company=TEST-2025
  2. Should redirect to Cognito hosted login
  3. Register a new user with a real email
  4. Confirm email
  5. Check:
    • ✓ DynamoDB ecoworld-progress has a new LEARNER_PROFILE row
    • ✓ HubSpot has a new Contact linked to Test Company Ltd
    • ✓ Cognito user has custom:hubspot_company_id attribute set

5.3 Test the workbook

  1. Log in and navigate to /academy
  2. Type in a workbook exercise textarea (must have data-eco-exercise="1.1:exercise-name")
  3. After 2 seconds, should auto-save
  4. Refresh the page — answer should be restored
  5. Progress bar should show updated %

5.4 Test the admin dashboard

  1. In Cognito console, set a user's custom:role attribute to admin
  2. Log in as that user
  3. Navigate to the dashboard page
  4. Should see all learners and their progress

Monitoring and troubleshooting

CloudWatch Logs

Each Lambda writes to its own log group:

/aws/lambda/ecoworld-prod-post-confirmation
/aws/lambda/ecoworld-prod-hubspot-sync
/aws/lambda/ecoworld-prod-save-answer
/aws/lambda/ecoworld-prod-get-progress
/aws/lambda/ecoworld-prod-risk-score
/aws/lambda/ecoworld-prod-dashboard

Common issues

IssueLikely causeFix
HubSpot sync not firingCognito trigger not attachedRe-deploy CDK stack
Company not found in HubSpotecoworld_company_code not setAdd the custom property in HubSpot and set it on the company record
Token exchange failsRedirect URI mismatchAdd your Webflow URL to the Cognito app client callback URLs
CORS errors in browserWrong WEBFLOW_ORIGINUpdate the env var and re-deploy
Progress not loadingUser not logged inCheck Cognito token expiry (1hr default)

Cost estimate (monthly)

At 200 active learners across 10 client companies:

ServiceEstimated cost
AWS CognitoFree (first 50k MAU)
DynamoDB (on-demand)~€2
Lambda (200 users × 50 calls/day)Free (1M calls/month included)
API Gateway~€1
CloudWatch Logs~€1
Secrets Manager~€0.40
Total~€4–5/month

Next phases

  • Phase 2: Supplier questionnaire portal (suppliers get a link, fill form, responses stored)
  • Phase 3: Full supplier monitoring dashboard with CAP tracking
  • Phase 4: LearnWorlds → AWS completion sync (so quiz scores flow into the unified dashboard)



GitHub RepoRequest for Change (RFC)