Skip to content

ClassPulse Developer Guide

This guide is intended for developers who want to understand, modify, or extend the ClassPulse application. It provides detailed information about the codebase, key components, and how to implement common changes.

Table of Contents

  1. Getting Started
  2. Project Structure
  3. Key Components
  4. Database Schema
  5. Authentication Flow
  6. Session Management
  7. WebSocket Implementation
  8. Adding a New Question Type
  9. Customizing Visualizations
  10. Common Development Tasks
  11. Troubleshooting

Getting Started

Development Environment Setup

  1. Clone the repository

    git clone <repository-url>
    cd classpulse
    

  2. Create and activate a virtual environment

    python3 -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    

  3. Install dependencies

    pip install python-fasthtml
    

  4. Run the development server

    python app.py
    

  5. Access the application Open your browser and navigate to http://localhost:5002

Development Workflow

  1. Create a feature branch for your changes
  2. Make your code changes
  3. Test your changes locally
  4. Create a pull request for review

Project Structure

ClassPulse follows a modular structure:

~/projects/classpulse/
├── app.py                  # Main application entry point
├── models/
│   └── schema.py           # Database schema definitions
├── controllers/
│   ├── auth_routes.py      # Authentication routes
│   ├── audience_routes.py  # Audience participation routes
│   ├── presenter_routes.py # Presenter dashboard routes 
│   ├── question_routes.py  # Question management routes
│   └── websocket_routes.py # Real-time WebSocket routes
├── utils/
│   ├── auth.py             # Authentication utilities
│   ├── components.py       # Reusable UI components
│   ├── qrcode.py           # QR code generation
│   └── session_manager.py  # Session management utilities
├── static/
│   ├── css/
│   │   └── styles.css      # Custom styling
│   ├── js/
│   │   └── main.js         # JavaScript functionality
│   └── img/                # Image assets
└── templates/
    ├── audience/           # Audience view templates 
    └── presenter/          # Presenter view templates

Key Components

FastHTML Framework

ClassPulse uses the FastHTML framework, which is built on top of Starlette. FastHTML provides a convenient way to generate HTML using Python syntax.

Key concepts: - HTML tags are represented as Python functions (e.g., Div(), P()) - Route handlers are defined with the @rt decorator - Components can be created as Python functions that return HTML elements

Example of a FastHTML component:

def layout(*content, title="ClassPulse"):
    """Main layout component"""
    return Titled(
        title,
        Header(
            # Header content...
        ),
        Main(
            Div(*content, cls="container"),
            cls="content"
        ),
        Footer(
            # Footer content...
        )
    )

Route Controllers

Route controllers are organized by feature area:

  1. auth_routes.py: Handles login/logout functionality
  2. audience_routes.py: Manages audience-facing views and responses
  3. presenter_routes.py: Provides presenter dashboard and management
  4. question_routes.py: Handles question creation and results
  5. websocket_routes.py: Manages real-time updates

Each controller module follows a similar pattern: - A main setup function that takes the route decorator (rt) - Route handler functions for GET/POST requests - Returns HTML content or redirects as appropriate

Example:

def setup_auth_routes(rt):
    """Set up authentication related routes"""

    @rt("/login")
    def get():
        # Route implementation...

    @rt("/login")
    def post(username: str, password: str, session):
        # Route implementation...

    return rt

Utility Modules

  1. auth.py: Handles password hashing, user authentication
  2. components.py: Provides reusable UI components
  3. qrcode.py: Generates QR codes for session joining
  4. session_manager.py: Manages sessions, questions, and responses

Database Schema

ClassPulse uses SQLite with the FastLite ORM. Tables are defined in models/schema.py:

  1. users: Stores presenter accounts
  2. sessions: Stores presentation sessions
  3. questions: Stores questions of different types
  4. responses: Stores audience responses

Example query patterns:

# Get a specific record by ID
user = users[user_id]

# Query with conditions
session_list = sessions(where="code = ?", where_args=[code])

# Insert a record
user = User(username="example", password_hash="hash", email="email")
users.insert(user)

# Update a record
user.display_name = "New Name"
users.update(user)

Authentication Flow

  1. Login Process:
  2. User submits username/password to /login (POST)
  3. authenticate_user() verifies credentials
  4. On success, user ID is stored in session
  5. User is redirected to dashboard

  6. Authentication Middleware:

  7. Checks for user_id in session
  8. Allows public routes (/login, /join, /audience/*)
  9. Redirects to login for protected routes if not authenticated

  10. Password Security:

  11. Passwords are hashed using PBKDF2 with salt
  12. Verification compares hashed passwords

Session Management

Sessions in ClassPulse refer to presentation sessions, not web sessions:

  1. Creation:
  2. Presenter creates a session with a name
  3. System generates a unique 6-digit code
  4. Session is associated with the creator

  5. Question Management:

  6. Presenter can add questions of different types
  7. Questions can be activated/deactivated
  8. Questions are ordered within the session

  9. Audience Joining:

  10. Audience members join using the session code
  11. They receive a unique respondent ID (UUID)
  12. They can view and answer active questions

WebSocket Implementation

Real-time updates use WebSockets:

  1. Connection Setup:
  2. Presenter connects to /ws/results/{question_id}
  3. Connection is stored in a dictionary by question ID

  4. Update Process:

  5. When responses arrive, stats are calculated
  6. Updates are sent to all connections for that question
  7. Updates include formatted HTML with result information

  8. Client-Side Handling:

  9. HTMX handles WebSocket connections and updates
  10. Charts are re-rendered when data changes

Adding a New Question Type

To add a new question type (e.g., "Ranking"):

  1. Update Schema:
  2. No schema change needed, as the type field is a string
  3. Add a new creation function in session_manager.py:
def create_ranking_question(session_id: int, title: str, items: List[str]) -> Question:
    """Create a ranking question"""
    question = Question(
        session_id=session_id,
        type='ranking',
        title=title,
        options=json.dumps(items),
        active=True,
        created_at=datetime.now().isoformat(),
        order=0
    )

    return questions.insert(question)
  1. Add Result Processing:
  2. Add a function to process results in session_manager.py:
def get_ranking_results(question_id: int) -> Dict[str, Dict[str, int]]:
    """Get results for a ranking question"""
    # Implementation...
  1. Update Controllers:
  2. Add a new route in question_routes.py for creation
  3. Extend audience_routes.py to handle the new question type
  4. Update visualization in questions/{id}/results

  5. Add UI Components:

  6. Create audience interface for ranking questions
  7. Add visualization code for ranking results

Customizing Visualizations

Visualizations are handled through Chart.js:

  1. Chart Configuration:
  2. Chart options are in question_routes.py in the results route
  3. Different configurations are used based on question type

  4. Customizing Charts:

  5. Modify the chart configuration in question_routes.py
  6. Update the initialization code in static/js/main.js

Example for changing chart colors:

new Chart(ctx, {
    type: chartType,
    data: chartData,
    options: {
        // ...existing options
        plugins: {
            legend: {
                labels: {
                    color: '#333'
                }
            }
        }
    }
});

Common Development Tasks

Adding a New Route

  1. Choose the appropriate controller file
  2. Add a route handler function:
@rt("/my-new-route")
def get():
    return layout(
        H2("My New Page"),
        P("Page content here")
    )
  1. If needed, add a POST handler:
@rt("/my-new-route")
def post(param1: str, param2: int):
    # Process the submission
    return RedirectResponse("/some-page", status_code=303)

Creating a New UI Component

Create a function that returns HTML elements:

def my_component(title, content):
    return Div(
        H3(title),
        P(content),
        cls="my-component"
    )

Then use it in your routes:

@rt("/some-route")
def get():
    return layout(
        my_component("Title 1", "Content 1"),
        my_component("Title 2", "Content 2")
    )

Extending the Database Schema

To add a new table or field:

  1. Update models/schema.py:
# Add a new table
settings = db.t.settings
if settings not in db.t:
    settings.create(
        id=int,
        user_id=int,
        theme=str,
        notifications=bool,
        pk='id'
    )
Setting = settings.dataclass()
  1. Add helper functions as needed in utility modules
  2. Update controllers to use the new schema elements

Troubleshooting

Common Issues

  1. Database Errors:
  2. Check table creation in schema.py
  3. Verify query parameters in function calls

  4. Route Errors:

  5. Ensure route decorators don't conflict
  6. Check parameter types match between routes and inputs

  7. WebSocket Issues:

  8. Verify WebSocket connection setup
  9. Check browser console for connection errors

Development Tips

  1. Debug Mode:
  2. The application runs in debug mode by default
  3. Error details are displayed in the console and browser

  4. Interactive Debugging:

  5. Add print statements for debugging
  6. Use browser developer tools for frontend issues

  7. Database Inspection:

  8. Use SQLite tools to inspect the database directly:

    sqlite3 classpulse.db
    .tables
    SELECT * FROM users;
    

  9. Testing WebSockets:

  10. Test WebSocket connections with browser developer tools
  11. Monitor the network tab for WebSocket frames