This is an automated email from the ASF dual-hosted git repository.

gstein pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/steve.git

commit 855a8c7909b178b51e830b617909e4a6bdecb676
Author: Greg Stein <[email protected]>
AuthorDate: Fri Sep 26 12:15:29 2025 -0500

    add schema docco, h/t to Grok
---
 v3/docs/schema.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/v3/docs/schema.md b/v3/docs/schema.md
new file mode 100644
index 0000000..0de9ec0
--- /dev/null
+++ b/v3/docs/schema.md
@@ -0,0 +1,113 @@
+# Database Schema Documentation
+
+This document describes the SQLite database schema for an election management 
system. The schema supports creating and managing elections, defining issues to 
vote on, tracking eligible voters, and securely recording votes. It emphasizes 
security through cryptographic fields (e.g., salts, hashed tokens, encrypted 
votes) and enforces data integrity with constraints like foreign keys and 
strict typing.
+
+## Overview
+The database consists of five tables:
+- `election`: Stores election metadata, including ownership and cryptographic 
data.
+- `issue`: Defines specific issues within an election, with voting mechanisms 
and metadata.
+- `person`: Tracks individuals involved in elections (e.g., voters, owners).
+- `mayvote`: Specifies which persons are eligible to vote on specific issues.
+- `vote`: Records encrypted votes, supporting re-voting by tracking insertion 
order.
+
+All tables use SQLite’s `STRICT` mode to enforce type constraints. The schema 
avoids `AUTOINCREMENT` for IDs (except in `vote`) to prevent predictable URLs, 
using 10-character hexadecimal IDs instead.
+
+## Table Details
+
+### `election`
+Stores metadata for each election.
+
+- **Columns**:
+  - `eid` (TEXT, PRIMARY KEY): A 10-character hexadecimal election ID (e.g., 
"1a2b3c4d5e"). Not auto-incremented to prevent URL deduction. Must match the 
pattern `[0-9a-f]{10}`.
+  - `title` (TEXT, NOT NULL): The election’s title.
+  - `owner_pid` (TEXT, NOT NULL): The ID of the person who created/owns the 
election. References `person(pid)`.
+  - `authz` (TEXT): Specifies an LDAP group (e.g., group name or identifier) 
allowed to edit the election. If `NULL`, only `owner_pid` can edit. The exact 
format is TBD but will likely map to LDAP-based persons.
+  - `salt` (BLOB): A 16-byte salt generated using `secrets.token_bytes()` in 
Python, set when the election is opened. `NULL` if not opened.
+  - `opened_key` (BLOB): A 32-byte hash (using Argon2) derived from election 
data to detect tampering, set when the election is opened. `NULL` if not opened.
+  - `closed` (INTEGER): Indicates election status: `NULL` or `0` for not 
closed, `1` for closed (implies opened). Must be `NULL`, `0`, or `1`.
+
+- **Constraints**:
+  - Foreign key: `owner_pid` references `person(pid)` with `RESTRICT` on 
delete and `NO ACTION` on update.
+  - Check constraints ensure `eid` format, `salt` (16 bytes or `NULL`), 
`opened_key` (32 bytes or `NULL`), and `closed` values.
+
+### `issue`
+Represents issues (questions or proposals) within an election.
+
+- **Columns**:
+  - `iid` (TEXT, PRIMARY KEY): A 10-character hexadecimal issue ID (e.g., 
"a1b2c3d4e5"). Must match `[0-9a-f]{10}`.
+  - `eid` (TEXT, NOT NULL): The election ID this issue belongs to. References 
`election(eid)`.
+  - `title` (TEXT, NOT NULL): A one-line title for the issue.
+  - `description` (TEXT): An optional detailed description of the issue.
+  - `type` (TEXT, NOT NULL): The voting mechanism. Currently supports:
+    - `yna`: Yes/No/Abstain voting.
+    - `stv`: Single Transferable Vote.
+    Additional types may be added in the future.
+  - `kv` (TEXT): JSON-formatted key-value pairs for issue-specific data, 
varying by `type`. For example, `stv` issues may include a `"candidates"` key 
listing candidate names or IDs.
+
+- **Constraints**:
+  - Foreign key: `eid` references `election(eid)` with `RESTRICT` on delete 
and `NO ACTION` on update.
+  - Check constraint ensures `iid` format.
+
+- **Indexes**:
+  - `idx_issue_eid`: Index on `eid` for efficient lookups of issues by 
election.
+
+### `person`
+Stores information about individuals (voters, owners).
+
+- **Columns**:
+  - `pid` (TEXT, PRIMARY KEY): A unique person ID (e.g., LDAP username).
+  - `name` (TEXT): An optional human-readable name.
+  - `email` (TEXT, NOT NULL): Contact email for sending ballot links.
+
+- **Constraints**:
+  - No foreign keys or additional constraints.
+
+### `mayvote`
+Defines which persons are eligible to vote on specific issues.
+
+- **Columns**:
+  - `pid` (TEXT, NOT NULL): The person ID. References `person(pid)`.
+  - `iid` (TEXT, NOT NULL): The issue ID. References `issue(iid)`.
+  - `salt` (BLOB): A 16-byte salt generated using `secrets.token_bytes()`, 
used for generating a vote token and encryption key. `NULL` until the election 
is opened.
+
+- **Constraints**:
+  - Primary key: `(pid, iid)` ensures a person can be eligible for an issue 
only once.
+  - Foreign keys: `pid` references `person(pid)`, `iid` references 
`issue(iid)`, both with `RESTRICT` on delete and `NO ACTION` on update.
+  - Check constraint ensures `salt` is 16 bytes or `NULL`.
+
+### `vote`
+Records votes cast for issues, supporting re-voting.
+
+- **Columns**:
+  - `vid` (INTEGER, PRIMARY KEY, AUTOINCREMENT): Auto-incrementing ID to track 
insertion order (aliases `_ROWID_`).
+  - `vote_token` (BLOB, NOT NULL): A 32-byte hash (using Argon2) of a 
person-issue pair (from `mayvote`), used for encryption key derivation.
+  - `ciphertext` (BLOB, NOT NULL): The encrypted vote data, currently using 
Fernet encryption, with plans to transition to XChaCha20-Poly1305.
+
+- **Constraints**:
+  - Check constraint ensures `vote_token` is 32 bytes.
+  - No foreign keys, but `vote_token` is derived from `mayvote` data.
+
+- **Indexes**:
+  - `idx_by_vote_token`: Index on `vote_token` for efficient vote lookups.
+
+## Key Features
+- **Security**:
+  - Cryptographic fields ensure vote and election integrity:
+    - `salt` (16 bytes) in `election` and `mayvote` uses 
`secrets.token_bytes()`.
+    - `opened_key` (32 bytes) in `election` uses Argon2 to hash election data 
for tamper detection.
+    - `vote_token` (32 bytes) in `vote` uses Argon2 to hash person-issue pairs.
+    - `ciphertext` in `vote` uses Fernet encryption (to be replaced with 
XChaCha20-Poly1305).
+  - Non-predictable IDs (`eid`, `iid`) use 10-character hex strings to prevent 
URL guessing.
+- **Re-voting**: The `vote` table allows multiple votes per person-issue pair. 
The latest vote is identified using `MAX(vid)`, leveraging the 
auto-incrementing `vid`. Older votes are retained for auditing.
+- **Flexible Issues**: The `issue` table supports multiple voting mechanisms 
(`yna`, `stv`) with extensible JSON metadata (`kv`). For example, `stv` issues 
may specify candidates in `kv`.
+- **Data Integrity**: Foreign keys with `RESTRICT` prevent deletion of 
referenced records, and `STRICT` mode enforces type safety.
+- **Election Lifecycle**:
+  - **Editable**: The election is created and can be modified (e.g., adding 
issues, voters).
+  - **Open**: A Python method call opens the election, setting `salt` and 
`opened_key`. Eligible voters (in `mayvote`) can vote on issues.
+  - **Closed**: A Python method call closes the election (sets `closed = 1`), 
enabling tallying.
+  - The owner (`owner_pid`) can monitor and edit the election at all stages, 
including viewing voter eligibility and vote counts.
+
+## Notes
+- **Authorization**: The `authz` field’s format is TBD but will likely use 
LDAP group identifiers to define editing permissions. Validation occurs outside 
the schema (e.g., via LDAP integration).
+- **Query Optimization**: The schema references a `queries.yaml` file, which 
maps query names to SQL statements for all database interactions. This file 
provides insight into common operations (e.g., vote tallying, eligibility 
checks). Specific queries are not included here but can be analyzed for index 
optimization.
+- **Future Changes**: The `ciphertext` encryption will transition from Fernet 
to XChaCha20-Poly1305. Additional `issue` types may be added beyond `yna` and 
`stv`.

Reply via email to