| # 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. |