Skip to content
This repository was archived by the owner on Nov 29, 2025. It is now read-only.

Latest commit

 

History

History
778 lines (594 loc) · 21.7 KB

File metadata and controls

778 lines (594 loc) · 21.7 KB

LaunchPad UI - AI Assistant Guide

Last Updated: 2025-11-28

Project Overview

LaunchPad is a project planning tool for educators to design high-quality, personalized project-based learning experiences. This is an Ember.js web application that provides a visual storyboard interface for creating and managing educational projects with various learning activities (tiles).

Status: This repository has been moved into a monorepo at https://github.com/savilabs/launchpad, but is still maintained as a standalone repository.

Key Information

  • Framework: Ember.js 3.3 (Classic syntax, pre-Octane)
  • Data Layer: Ember Data 3.3 with ActiveModelAdapter
  • Authentication: OAuth2 via ember-simple-auth
  • UI Framework: Bootstrap 3
  • Styling: LESS preprocessor
  • Testing: QUnit with ember-cli-qunit
  • Node Version: 10.x (managed via nvm)
  • Deployment: Firebase Hosting (staging and production)

Live Environments

Directory Structure

launchpad-ui/
├── app/                          # Main application code
│   ├── adapters/                # Ember Data API adapters
│   ├── authenticators/          # OAuth2 authentication
│   ├── authorizers/             # Request authorization
│   ├── components/              # UI components (51 total)
│   ├── controllers/             # Route-bound state
│   ├── helpers/                 # Handlebars template helpers
│   ├── initializers/            # App startup hooks
│   ├── mixins/                  # Shared behavior (9 mixins)
│   ├── models/                  # Ember Data models (15 models)
│   ├── routes/                  # Route handlers (33 routes)
│   ├── serializers/             # Data serialization
│   ├── services/                # Singleton services
│   ├── styles/                  # LESS stylesheets
│   ├── templates/               # Handlebars templates (105 files)
│   ├── transforms/              # Custom data transforms
│   ├── app.js                   # Application entry point
│   └── router.js                # Route definitions
├── config/                      # Configuration files
│   ├── environment.js           # Environment-specific config
│   ├── optional-features.json   # Feature flags
│   └── targets.js               # Browser targets
├── tests/                       # Test suite
│   ├── integration/             # Integration tests
│   ├── unit/                    # Unit tests
│   └── helpers/                 # Test utilities
├── public/                      # Static assets
├── vendor/                      # Third-party code
├── ember-cli-build.js           # Build configuration
└── package.json                 # Dependencies and scripts

Core Architecture

Ember.js Patterns (Classic Syntax)

This application uses Ember.js 3.3 with Classic syntax (not Octane):

  • Components: Component.extend() with lifecycle hooks
  • Properties: Use set() and get() for updates
  • Computed Properties: computed() with dependent keys
  • Actions: Defined in actions hash
  • Lifecycle: init(), didInsertElement(), willDestroyElement()

Key Architectural Layers

1. Data Layer (Ember Data + ActiveModelAdapter)

Location: app/adapters/application.js, app/models/, app/serializers/

The application uses Ember Data with the ActiveModelAdapter for Rails-compatible API communication:

// API Configuration
API_NAMESPACE: 'v1'
API_HOST: varies by environment
API_ENDPOINT: {API_HOST}/v1

Core Models:

  • project.js - Learning projects with tiles and designers
  • tile.js - Individual learning activities (polymorphic: Launch, Experience, Artifact, Checkpoint, Exhibition)
  • user.js / current-user.js - User accounts
  • project-member.js - Team members on projects
  • project-invite.js - Pending invitations (custom primaryKey: invite_token)
  • performance-indicator.js - Learning standards/proficiencies
  • applied-performance-indicator.js - Indicators applied to tiles

Model Relationships:

ProjecthasMany: tiles, appliedPerformanceIndicators, designers, sourceDesigners

TilebelongsTo: project (sync)hasMany: appliedPerformanceIndicators (async)

UserhasMany: projects (async, inverse: null)

2. Authentication & Authorization

Location: app/authenticators/oauth2.js, app/authorizers/oauth2.js, app/services/current-user.js

  • OAuth2 password grant flow
  • Bearer token in Authorization header
  • Session management via ember-simple-auth
  • Route protection via RequireCurrentUser mixin
  • Automatic redirect to signin on auth failure

Key Service: current-user

  • Methods: load(), login(), logout()
  • Injected into most routes and components
  • Tracks authenticated user state

3. Routing

Location: app/router.js, app/routes/

The application uses deeply nested routes with 33 total route handlers:

/ (home)
├── auth/{signin,signup}
├── invite-accept (/invites/:token)
├── forgot-password/:reset_token
├── gallery (public project browsing)
└── main (authenticated area)
    ├── dashboard (user's projects)
    ├── user-profile (/profile)
    ├── projects
    │   ├── new
    │   └── show (:id)
    │       ├── overview/edit
    │       ├── storyboard
    │       │   ├── launches/:tile_id/{edit,move}
    │       │   ├── experiences/:tile_id/{edit,move}
    │       │   ├── artifacts/:tile_id/{edit,move}
    │       │   ├── checkpoints/:tile_id/{edit,move}
    │       │   └── exhibitions/:tile_id/{edit,move}
    │       ├── proficiencies
    │       └── team
    └── users/:id

Route Mixins:

  • ApplicationRoute - Base auth handling + redirects
  • RequireCurrentUser - Protected route enforcement
  • EditTileRoute - Permission checking for tile editing
  • ResetScroll - Reset scroll on transition

4. Component System

Location: app/components/, app/templates/components/

51 reusable components organized by feature area:

Authentication & User:

  • user-profile, user-profile-form, user-card
  • password-reset-form, password-reset-request-form
  • invite-accept

Project Management:

  • project-card, project-form, project-view, project-gallery
  • project-copy, new-project-member-form
  • app-dashboard

Tile/Storyboard (Core Feature):

  • tile-card - Individual tile display
  • tile-form - Generic tile form with validation
  • tile-form-{launch,experience,artifact,checkpoint,exhibition} - Type-specific forms
  • tile-modal - Modal wrapper
  • tile-nav, tile-nav-item - Navigation between tiles
  • tile-move - Move tile to different project
  • grouped-tiles - Group tiles by week

Performance Indicators:

  • indicator-input, indicator-with-scale
  • applied-performance-indicator
  • tile-indicator-select

UI Utilities:

  • file-upload - Cloudinary image uploads
  • file-editable - Inline file editing
  • flash-messages - Toast notifications
  • form-group, form-item-errors - Form helpers
  • wysiwyg-editor - Rich text (Trix editor)
  • main-navigation - Top nav bar
  • Icon components for each tile type

Component Mixins:

  • TileForm - Form validation and submission
  • TileModal - Modal behavior
  • TileModalEdit - Edit modal behavior
  • RichText - Format rich text with target="_blank"

5. Services

Location: app/services/

Core Services:

  • current-user - Authenticated user management
  • session - OAuth2 session (ember-simple-auth)
  • flash-messages - Notifications (3s auto-dismiss)
  • store - Ember Data persistence
  • ajax / authorized-ajax - HTTP requests
  • metrics - Google Analytics tracking

6. Styling

Location: app/styles/

  • LESS preprocessor with Bootstrap 3
  • Component-scoped LESS files in styles/components/
  • Shared variables in styles/variables/
  • BEM-like naming: .ClassName-element--modifier
  • Custom Bootstrap theme with brand colors

The Tile System (Core Domain Concept)

The application centers around a tile-based storyboard for organizing learning activities in a project.

Five Tile Types:

  1. Launch - Project kickoff activities
  2. Experience - Learning experiences
  3. Artifact - Student work products
  4. Checkpoint - Assessment points
  5. Exhibition - Final presentations

Tile Properties (from app/models/tile.js):

  • type - Tile type (polymorphic)
  • position - Order within week
  • week - Week number in project
  • title, description - Content
  • learningSteps - Rich text instructions
  • isMilestone - Flag for important tiles
  • startDate - Scheduled date
  • imageId - Cloudinary image reference
  • appliedPerformanceIndicators - Tagged learning standards

Polymorphic Routing:

  • Each tile type has its own nested route
  • Routes follow pattern: /projects/:id/storyboard/{type}s/:tile_id
  • Type-specific edit forms via components

Computed Properties (key pattern):

typeForRoute: computed('type', function() { ... })
routeForType: computed('type', function() { ... })
editRouteForType: computed('type', function() { ... })

Development Workflows

Environment Setup

# Install and use Node 10.x
nvm install 10.24.1
nvm use 10.24.1

# Install dependencies
npm install

# Install Ember CLI globally (optional)
npm install -g ember-cli@3.3.0

Running the Application

# Start development server (runs at localhost:4200)
ember serve
# or
npm start

# The app expects the API to be running at localhost:3090
# ember-cli-build.js configures a proxy for development

Testing

# Run all tests once
ember test
# or
npm test

# Run tests in watch mode
ember test --server

# Linting
npm run lint:js
npm run lint:js -- --fix

Test Structure:

  • Unit tests: tests/unit/ (models, transforms, mixins)
  • Integration tests: tests/integration/components/
  • Uses QUnit with ember-qunit helpers
  • Test runner: Testem with Chrome headless

Building

# Development build
ember build

# Production build
ember build --environment production

# Production build with asset fingerprinting
FINGERPRINT_ASSETS=true ember build --environment production

Code Generation

Ember CLI provides generators:

ember generate component my-component
ember generate route my-route
ember generate model my-model
ember generate service my-service
ember generate helper my-helper
ember generate mixin my-mixin

Important Conventions & Patterns

1. File Naming

  • Components: Kebab-case files → camelCase in code

    • File: app/components/project-card.js
    • Template: app/templates/components/project-card.hbs
    • Usage: {{project-card}}
  • Routes: Directory structure mirrors route nesting

    • Route: main.projects.show.storyboard.launches.launch.edit
    • File: app/routes/main/projects/show/storyboard/launches/launch/edit.js
  • Models: Singular names

    • File: app/models/project.js
    • Usage: store.findRecord('project', id)

2. Component Data Flow

  • Props passed from parent via template
  • Actions passed as strings, triggered via send()
  • Two-way binding via set()
  • Avoid direct model mutation in components

Example:

{{!-- Parent template --}}
{{project-card project=model onEdit=(action "editProject")}}
// Component actions
actions: {
  handleEdit() {
    this.sendAction('onEdit', this.get('project'));
  }
}

3. Route Loading Pattern

Standard Route:

export default Route.extend({
  currentUser: service(),

  beforeModel() {
    // Auth checks, redirects
  },

  model(params) {
    return this.store.findRecord('project', params.id);
  },

  afterModel(model) {
    // Additional setup
  }
});

4. Service Injection

Always inject services needed in routes/components:

import { inject as service } from '@ember/service';

export default Component.extend({
  currentUser: service(),
  flashMessages: service(),

  actions: {
    doSomething() {
      const user = this.get('currentUser.user');
      this.get('flashMessages').success('Done!');
    }
  }
});

5. Error Handling

  • Route-level error actions catch failures
  • 404 responses redirect to not-found route
  • User feedback via flash-messages service
  • Validation errors displayed via errors-for helper

Example:

{{form-item-errors errors=(errors-for model "title")}}

6. Image Uploads (Cloudinary)

  • Configured in app/initializers/cloudinary.js
  • Upload preset: launchpad
  • Cloudinary name: agilion
  • Integration via file-upload component
  • Image URLs generated with transformations

7. Modal Pattern

  • Uses ember-modal-dialog addon
  • Tile editing uses modal overlays
  • Modals rendered via outlets
  • Close actions bubble up to parent routes

8. Form Validation

  • Model validations in app/models/
  • TileForm mixin provides validation helpers
  • Errors displayed per-field via form-item-errors
  • Flash messages for success/failure

Configuration & Environment Variables

Environment Files

Location: config/environment.js

Environments:

  • development - Local development, API at localhost:3090
  • test - Testing mode with disabled analytics
  • staging - Staging deployment with debug GA
  • production - Production deployment

Key Config Values:

modulePrefix: 'launch-pad'
API_NAMESPACE: 'v1'
API_HOST: varies by environment
CLOUDINARY_NAME: 'agilion'
CLOUDINARY_UPLOAD_PRESET: 'launchpad'
GA_ID: varies by environment

Content Security Policy

CSP headers allow:

  • Fonts: Google Fonts, data URIs
  • Scripts: Google Analytics, inline scripts
  • Images: Cloudinary, Gravatar, S3
  • Connections: API hosts, Cloudinary, GA

Build Configuration

Location: ember-cli-build.js

  • Asset fingerprinting via FINGERPRINT_ASSETS env var
  • Bootstrap 3 integration with fonts
  • Cloudinary upload library imports
  • Development proxy to API server

CI/CD

GitHub Actions

Location: .github/workflows/ember.yml

Workflow:

  1. Checkout code
  2. Setup Node 10.x with npm cache
  3. Install dependencies: npm ci
  4. Run tests: npm test
  5. Run linting: npm run lint:js

Triggers:

  • Push to master branch
  • Pull requests to master

Deployment

Deployment to Firebase Hosting (TBD - see README)

  • Staging: launchpad-ui-staging.firebaseapp.com
  • Production: launchpad-ui-production.firebaseapp.com

Key Dependencies

Framework

  • ember-source ~3.3.0
  • ember-cli ~3.3.0
  • ember-data ~3.3.0

Data & API

  • active-model-adapter 2.2.0 - Rails-compatible adapter
  • ember-ajax ^3.0.0 - AJAX requests
  • ember-inflector ^2.3.0 - String pluralization

Authentication

  • ember-simple-auth ^1.7.0

UI Components

  • ember-bootstrap ^2.0.0 + bootstrap ^3.3.7
  • ember-modal-dialog 2.4.3
  • ember-trix-editor - Rich text editing
  • emberx-select ^3.1.1
  • ember-pikaday ^2.2.4 - Date picker
  • ember-drag-drop ^0.5.1
  • ember-sortable ^1.11.2

Utilities

  • ember-moment 7.7.0 - Date/time
  • ember-cli-flash 1.7.0 - Notifications
  • ember-metrics ^0.13.0 - Analytics
  • ember-keyboard ^3.0.2
  • cloudinary-jquery-file-upload ^2.5.0

Development

  • eslint + eslint-plugin-ember - Linting
  • ember-cli-less 1.5.5
  • ember-cli-qunit ^4.3.2
  • qunit-dom ^0.6.2

Common Tasks for AI Assistants

Adding a New Component

  1. Generate component: ember generate component my-component
  2. Implement component logic in app/components/my-component.js
  3. Create template in app/templates/components/my-component.hbs
  4. Add component styles to app/styles/components/my-component.less
  5. Import LESS in app/styles/app.less
  6. Write tests in tests/integration/components/my-component-test.js

Adding a New Route

  1. Add route to app/router.js
  2. Generate handler: ember generate route my-route
  3. Implement model hook and actions
  4. Create template in app/templates/my-route.hbs
  5. Add navigation link in appropriate template
  6. Consider authentication requirements (mixins)

Adding a New Model

  1. Generate model: ember generate model my-model
  2. Define attributes and relationships
  3. Create serializer if needed: ember generate serializer my-model
  4. Write unit tests in tests/unit/models/my-model-test.js
  5. Update related models for relationships

Modifying API Integration

  1. Check adapter: app/adapters/application.js (or model-specific)
  2. Check serializer for data transformation
  3. Update model attributes/relationships
  4. Test with API endpoints
  5. Handle errors appropriately

Updating Styles

  1. Locate relevant LESS file in app/styles/components/
  2. Use Bootstrap 3 classes and variables
  3. Follow BEM-like naming conventions
  4. Import new LESS files in app/styles/app.less
  5. Test across different screen sizes

Testing Guidelines

Unit Tests

Test pure functions, computed properties, model logic:

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

module('Unit | Model | project', function(hooks) {
  setupTest(hooks);

  test('it has correct attributes', function(assert) {
    let model = this.owner.lookup('service:store').createRecord('project');
    assert.ok(model);
  });
});

Integration Tests

Test component rendering and user interaction:

import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';

module('Integration | Component | project-card', function(hooks) {
  setupRenderingTest(hooks);

  test('it renders', async function(assert) {
    await render(hbs`{{project-card}}`);
    assert.dom(this.element).exists();
  });
});

Test Helpers

  • @ember/test-helpers - Modern Ember test helpers
  • qunit-dom - DOM assertion helpers
  • Custom helpers in tests/helpers/

Troubleshooting

Common Issues

Node Version Mismatch:

nvm use 10.24.1

Dependency Issues:

rm -rf node_modules package-lock.json
npm install

API Connection Errors:

  • Ensure API is running at localhost:3090
  • Check config/environment.js for correct API_HOST
  • Verify OAuth2 credentials

Build Failures:

  • Check for LESS syntax errors
  • Verify all imports are correct
  • Clear tmp/ and dist/ directories

Test Failures:

  • Check for missing test setup
  • Verify test helpers are imported
  • Ensure test environment is configured correctly

Code Style & Best Practices

ESLint Configuration

Location: .eslintrc.js

  • Extends eslint:recommended and plugin:ember/recommended
  • ECMAScript 2017 support
  • Browser environment
  • Node environment for config files

Ember Patterns

  • Use set() and get() for property access
  • Computed properties for derived state
  • Actions for event handling
  • Services for shared state
  • Mixins for shared behavior
  • Avoid direct DOM manipulation

Naming Conventions

  • Components: kebab-case
  • Services: kebab-case
  • Models: singular, kebab-case
  • Routes: dot-separated paths
  • Variables: camelCase
  • Classes: PascalCase

Comments

  • Add comments for complex logic
  • Document public APIs
  • Explain "why" not "what"
  • Keep comments up-to-date

Project-Specific Domain Knowledge

Educational Concepts

  • Project: A learning expedition with multiple activities
  • Tile: Individual learning activity or milestone
  • Storyboard: Visual timeline of project activities
  • Week: Organizational unit (projects span multiple weeks)
  • Performance Indicator: Learning standard or proficiency
  • Designer: Educator who created the project
  • Team Member: Collaborator on a project

User Roles

  • Designer: Can create and edit projects
  • Team Member: Can collaborate on projects
  • Guest: Can view public gallery

Project Visibility

Projects can be:

  • Private (only team members)
  • Public (visible in gallery)

Performance Indicators

  • Can be applied to any tile
  • Track learning standards alignment
  • Multiple indicators per tile
  • System-wide catalog of indicators

Additional Resources

Notes for AI Assistants

  1. Always use Classic Ember syntax - This is a pre-Octane application
  2. Read before editing - Always read files before making changes
  3. Respect Ember conventions - Follow the framework's patterns
  4. Test your changes - Run tests after modifications
  5. Use mixins for shared behavior - Don't duplicate code
  6. Inject services - Don't access global state
  7. Handle errors gracefully - Use flash messages for user feedback
  8. Follow the data flow - Props down, actions up
  9. Check authentication - Many routes require login
  10. Use Ember CLI generators - They ensure correct structure

When Making Changes

  • Read relevant files first using Read tool
  • Use Edit tool for modifications (preserve formatting)
  • Run tests to verify changes
  • Check linting with npm run lint:js
  • Update tests if adding new functionality
  • Consider backward compatibility
  • Document significant changes

File References

When referencing code locations, use the pattern:

  • file_path:line_number (e.g., app/models/project.js:42)

This allows users to navigate directly to the source code.