ZipGuard data statement
Generated from schema.sql by pnpm data-statement. CI fails when this file is stale, so it cannot drift from what the code stores.
Never stored
IP addresses, browser or device fingerprints, email addresses, phone numbers, account connections, membership of other servers, message content.
Stored
guilds
settings for one server. Holds no member data.
| Column | Type | Purpose | Identifies a member |
|---|---|---|---|
| guild_id | TEXT | Discord server ID | |
| log_channel_id | TEXT | channel that receives verdict logs | |
| verify_channel_id | TEXT | channel that holds the challenge button | |
| quarantine_role_id | TEXT | role applied while a member is held | |
| medium_threshold | INTEGER | score at or above this gets a challenge | |
| high_threshold | INTEGER | score at or above this gets the high action | |
| high_action | TEXT | flag, timeout, kick or ban | |
| shadow_until | INTEGER | unix ms; verdicts are log-only until then | |
| antinuke | INTEGER | 1 = revert mass channel and role deletes and strip the actor, 0 = off | |
| links | INTEGER | 1 = quarantine scam-link patterns from existing members, 0 = off | |
| digest_at | INTEGER | unix ms of the last weekly digest posted to the log channel | |
| pilot_channel_id | TEXT | channel that receives pilot applications (the operator's server only) | |
| created_at | INTEGER | unix ms when /setup first ran |
pilot
servers that applied for the private pilot and whether they were let in. Applicant details stay on the website host.
| Column | Type | Purpose | Identifies a member |
|---|---|---|---|
| guild_id | TEXT | Discord server ID from the application | |
| server_name | TEXT | server name as typed on the form | |
| status | TEXT | pending, approved or rejected | |
| created_at | INTEGER | unix ms the application arrived | |
| decided_at | INTEGER | unix ms of the decision | |
| decided_by | TEXT | Discord user ID of the moderator who decided | yes |
joins
one row per join event, plus one per quarantine of an existing member. Deleted after 90 days.
| Column | Type | Purpose | Identifies a member |
|---|---|---|---|
| id | INTEGER | row id | |
| guild_id | TEXT | server joined | |
| user_id | TEXT | Discord user ID of the joiner | yes |
| joined_at | INTEGER | unix ms of the join event | |
| account_created_at | INTEGER | unix ms, derived from the user ID | |
| invite_code | TEXT | invite used, when the bot could tell | |
| score | INTEGER | risk score 0 to 100 | |
| reasons | TEXT | JSON list of the rules that fired, with their text | |
| band | TEXT | low, medium or high | |
| action | TEXT | none, shadow, challenge, flag, timeout, kick, ban or quarantine | |
| scored_ms | INTEGER | ms from join event to verdict | |
| challenge_sent_at | INTEGER | unix ms the challenge was offered | |
| challenge_answered_at | INTEGER | unix ms the member clicked the button | |
| log_message_id | TEXT | message ID of the log entry, so it can be updated | |
| verdict | TEXT | mod override: approve, kick or ban | |
| verdict_by | TEXT | Discord user ID of the mod who overrode | yes |
| verdict_at | INTEGER | unix ms of the override |
appeals
what a held member wrote to the moderators. Deleted with its join row.
| Column | Type | Purpose | Identifies a member |
|---|---|---|---|
| id | INTEGER | row id | |
| join_id | INTEGER | the join being appealed | |
| user_id | TEXT | Discord user ID of the member appealing | yes |
| text | TEXT | the appeal, 500 characters at most | |
| created_at | INTEGER | unix ms |
Retention and deletion
- Rows in
joinsandappealsare deleted 90 days after the join. /forget-meclears every column marked "yes" above, at once.test/db.test.tsproves it on every CI run./my-datashows the member the same rows, inside Discord.- Pilot applications from zipguard.dev (server ID, server name, the applicant's Discord username, size, note) are kept on the website host for 90 days, then deleted. Email help@myagents.email to withdraw one earlier.