blob: 2cff9c657fe72bb7f76189f292810a1ac99e9abb [file] [view]
# Apache STeVe v3 Server Architecture
## Overview
Apache STeVe (Secure Team Voting Engine) v3 is a web-based voting system built for the Apache Software Foundation. It provides a secure, anonymous voting platform for elections, supporting multiple vote types (e.g., Yes/No/Abstain motions and Single Transferable Vote elections). The server is implemented in Python using the Quart asynchronous web framework, with a SQLite database backend for persistence.
The architecture emphasizes security, modularity, and ease of maintenance. It follows a layered design with clear separation of concerns: web handling, business logic, data access, and utilities.
## Directory Structure
```
v3/
├── server/ # Main server application
│ ├── api.py # API endpoints (currently minimal)
│ ├── bin/ # Command-line utilities
│ │ ├── load-fakedata.py # Script to populate test data
│ │ └── tally.py # Election tallying and reporting
│ ├── certs/ # TLS certificates for HTTPS
│ ├── config.yaml # Server configuration (YAML)
│ ├── docs/ # Per-issue documentation storage
│ ├── main.py # Application entry point
│ ├── pages.py # Web page handlers (routes)
│ ├── static/ # Static assets (CSS, JS, images)
│ │ ├── css/
│ │ ├── js/
│ │ └── favicon.ico
│ └── templates/ # EZT templates for HTML rendering
├── steve/ # Core business logic and data models
│ ├── crypto.py # Cryptographic utilities (salts, keys, tokens)
│ ├── election.py # Election model and database operations
│ ├── persondb.py # Person/PersonDB model for voter management
│ └── vtypes/ # Vote type implementations
│ └── __init__.py # Registry of supported vote types
└── tests/ # (Removed in some contexts) Unit tests
```
## Key Components
### Web Layer (Quart Framework)
- **Framework**: Uses Quart, an asynchronous version of Flask, for handling HTTP requests. This allows non-blocking I/O for better performance in I/O-bound operations like database queries.
- **Routing**: Handled in `pages.py` with decorators like `@APP.get('/')`. Routes are organized by functionality (e.g., voter pages, admin pages).
- **Authentication**: Relies on external ASF authentication via `asfquart.auth`. Requires committer-level access for most operations.
- **Templates**: Uses EZT (Easy Template) for server-side rendering. Templates are stored in `templates/` and use `[variable]` syntax for substitution. Includes includes for headers/footers.
- **Static Assets**: Served from `static/` directory, including Bootstrap CSS/JS, custom CSS, and JavaScript utilities.
- **Middleware**: Includes session management, CSRF protection (placeholder), and flash messages for user feedback.
### Business Logic Layer (`steve/`)
- **Election Model** (`election.py`): Core class `Election` manages election lifecycle (creation, opening, closing). Handles issues, votes, and voter eligibility. Uses prepared SQL queries for database interactions.
- **Person Database** (`persondb.py`): Manages voter information (PID, name, email). Provides lookup and addition methods.
- **Cryptography** (`crypto.py`): Handles secure token generation, salts, and vote encryption. Uses Argon2 for key derivation.
- **Vote Types** (`vtypes/`): Modular system for different voting methods (e.g., 'yna' for Yes/No/Abstain, 'stv' for Single Transferable Vote). Registry in `__init__.py`.
### Data Layer
- **Database**: SQLite for simplicity and portability. Schema includes tables for elections, issues, votes, persons, and voter eligibility (mayvote).
- **Queries**: SQL queries are defined in a separate YAML file (referenced but not shown in provided files). Accessed via prepared statements in the `Election` class.
- **Connections**: Database connections are opened per operation or cached in the app context. Uses `sqlite3` with row factories for dict-like access.
### Utilities and Scripts (`bin/`)
- **Tallying** (`tally.py`): Command-line tool for processing election results. Uses the `Election` class to compute tallies and generate reports.
- **Data Loading** (`load-fakedata.py`): Populates the database with test data for development.
## Code Conventions
### Python Style
- **Imports**: Standard library first, then third-party (e.g., `import pathlib`, `import quart`), then local modules. Uses absolute imports within the package.
- **Constants**: All uppercase with underscores (e.g., `FMT_DATE = '%b %d'`). No abbreviations unless standard.
- **Variables**: Snake_case for locals/functions, PascalCase for classes.
- **Error Handling**: Exceptions are raised for errors (e.g., `ElectionNotFound`). No broad try/except blocks; scripts exit on failure.
- **Logging**: Uses Python's `logging` module. Root logger set to INFO to suppress third-party noise. Local loggers (e.g., `_LOGGER`) can be DEBUG. F-strings for log messages (e.g., `logger.debug(f"Processing {item}")`).
- **Async/Await**: Used throughout Quart handlers for non-blocking operations.
- **Type Hints**: Not used (per project style; avoid unless requested).
- **Docstrings**: Minimal; not enforced.
### File and Directory Layout
- **Modularity**: Each major component in its own file (e.g., `pages.py` for routes, `election.py` for model).
- **Separation**: Web logic in `server/`, business logic in `steve/`, scripts in `bin/`.
- **Configuration**: YAML for config (`config.yaml`), with defaults in code.
- **Assets**: Organized by type (CSS, JS) in `static/`.
- **Templates**: Flat structure in `templates/`, with includes for reuse.
### Database Patterns
- **Prepared Statements**: All SQL uses parameterized queries to prevent injection.
- **Transactions**: Implicit in SQLite; explicit commits for multi-step operations.
- **Schema Evolution**: Not shown; assumes schema is static or handled externally.
- **Joins and Counts**: Queries use JOINs for related data (e.g., voter counts via `mayvote` table).
### Security
- **Authentication**: External (ASF OAuth); no local auth.
- **Authorization**: Role-based (committer, PMC member) via decorators.
- **Encryption**: Votes are encrypted; keys derived securely.
- **CSRF**: Placeholder token in forms; not fully implemented.
- **HTTPS**: Enforced via TLS certificates in `certs/`.
### Development and Deployment
- **Entry Point**: `main.py` with `if __name__ == '__main__'` for standalone, ASGI for production.
- **Configuration**: Loaded from `config.yaml` relative to app directory.
- **Testing**: Unit tests in `tests/` (removed in some contexts).
- **Dependencies**: Managed via `uv` (Python package manager); includes Quart, asfpy, etc.
## Patterns and Idioms
- **Decorator-Based Loading**: `@load_election` and `@load_election_issue` decorators fetch and pass database objects to handlers.
- **EasyDict Usage**: `edict` from `easydict` for dict-like objects with attribute access (e.g., `result.election = election.get_metadata()`).
- **Template Rendering**: `asfquart.utils.render()` for EZT templates.
- **Flash Messages**: Session-based user feedback using Quart's flash system.
- **Stopwatch**: `asfpy.stopwatch.Stopwatch()` for performance monitoring in debug mode.
- **EZT Boolean Flags**: `ezt.boolean()` for conditional rendering in templates.
- **Randomization**: Shuffles candidate lists to avoid bias in STV elections.
This architecture supports scalable, secure voting while remaining maintainable and extensible.