Skip to content

Data erasure

Whoever has to answer a “delete my data” request, and developers who touch storage or cleanup code.

  • Guest selfie: deleted right after the Telegram pack is created. If the job failed, the selfie stays for an admin retry until the file TTL removes it.
  • File TTL: every file under data/sessions and data/debug_sheets is deleted once it is older than PHOTO_TTL_HOURS (default 72; the config refuses values outside 1–72). The cleanup runs hourly inside the bot process.
  • Guest rows: an admin removes them with Reset guest in the admin panel or with tools/reset_users.py. The bot has no “delete my data” command for guests.
  • Lead data: /stickers_forget <n> in the leads group anonymises a lead at once. A lead marked as a test can be deleted completely.
  • What remains: the Telegram sticker pack, database backups (14 daily copies), reset-time database copies, the audit log, application logs, and any message that was sent to Telegram outside the card.
sequenceDiagram
    autonumber
    participant K as Kiosk
    participant A as API
    participant F as Session folder
    participant W as Worker
    participant D as SQLite
    participant C as Hourly cleanup
    K->>A: Photo upload
    A->>F: selfie file, EXIF removed by re-encoding
    W->>F: face crop, anchor, sheets, stickers
    W->>D: appearance passport cached on the job
    alt pack created
        W->>F: delete selfie file
        W->>D: on link sent, passport set to NULL
    else job failed
        W->>D: passport set to NULL
        Note over F: selfie stays for admin Retry until TTL
    end
    loop every hour while the bot runs
        C->>F: delete files older than TTL minus one hour
        C->>D: clear passports of finished or stuck jobs
    end
Data Removed when Code
Selfie (selfie_<random>.jpg) Immediately after createNewStickerSet succeeds. Also immediately if the upload lost a race or hit the pack limit worker._process_one_job, api.upload_photo
Derived images: face crop, anchor, sheets, single-figure regenerations, final sticker PNGs By file TTL services/storage.py cleanup_expired
Debug copies in data/debug_sheets (sheet copies, anchor copy, JSON diagnostics) By file TTL Same
Appearance passport (jobs.appearance_json) When the link is sent, when the job fails, when the deadline fails it. Hourly safety pass for finished jobs and for jobs older than 15 minutes db.mark_link_sent, db.fail_undelivered_job, db.clear_appearance_cards

Details of the TTL pass (periodic_cleanup in main.py):

  • It runs every 3600 s and deletes files older than PHOTO_TTL_HOURS minus one hour (never less than 0.5 h), so a file is gone no later than the configured TTL.
  • Age is the modification time of each file, not of the folder. A new file in a session folder does not extend the life of the selfie.
  • Empty folders are removed afterwards.
  • The pass runs only while the bot process is running. If the bot is stopped for days, nothing is deleted until it starts again.

There are two tools; both do the same thing to the database.

Admin panel → Reset guest (POST /admin/api/guests/{telegram_user_id}/reset, handler in admin_panel.py, query in db.reset_user):

  1. Makes a consistent copy of the database next to it: app.db.bak-<timestamp>-reset.
  2. In one transaction deletes the guest’s row in users, their rows in jobs, and the sessions rows linked to the guest or to those jobs.
  3. Writes an audit_log entry reset_user with the admin login, the admin’s IP, the guest’s Telegram id, the counts and the links of the guest’s old packs.

Command line (tools/reset_users.py):

Terminal window
python tools/reset_users.py <telegram_user_id> # dry run: shows what would be deleted
python tools/reset_users.py <telegram_user_id> --yes # copy the database, then delete

After a reset the guest can start a new session, and their next pack gets the next pack number.

Still present Why How to remove it
Files in the session folder and in debug_sheets The reset touches only the database Wait for the TTL, or delete the session folder on the server by hand
The Telegram sticker pack The product never deletes packs. The pack is created with the guest as owner The guest can delete their own pack in Telegram (standard platform behaviour, not part of this product)
app.db.bak-<timestamp>-reset (or app.db.bak-<timestamp> from the CLI tool) It is the safety copy made before deletion, so it contains the deleted rows. No code rotates these files Delete the file by hand once it is no longer needed
audit_log entry Kept on purpose: who reset whom, and the old pack links Manual SQL
api_usage rows Cost accounting; they hold a job id, no personal data —
Daily database backups See below They rotate out after 14 days
Application logs Log lines carry the Telegram user id and, for each job, a short appearance summary They rotate out after 14 days

The command works only in the leads group and only for LEADS_ADMIN_IDS (handlers/leads.py).

sequenceDiagram
    autonumber
    participant U as Lead admin
    participant B as Bot
    participant D as SQLite
    participant T as Leads group
    U->>B: /stickers_forget with a lead number
    alt lead not found or already erased
        B-->>U: Text reply with the reason
    else plain form
        B->>D: name, telegram, phone, comment, ip_hash set to NULL, erased_at set
        B->>D: same personal fields cleared in lead_repeats
        B->>T: Card rewritten to data erased
        B-->>U: Confirmation, backups clear in 14 days
    else with the word test and the lead is marked as a test
        B->>T: Card rewritten to test lead deleted
        B->>D: delete history, repeats and the lead row
        B-->>U: Confirmation, lead removed from statistics
    end
Form Effect
/stickers_forget <n> Anonymise. name, telegram, phone, comment, ip_hash become NULL; erased_at is set. The card becomes 🗑 Заявка #stickers_<n> — данные удалены (<date>) (“data erased”) and loses its buttons. The lead still counts in statistics
/stickers_forget <n> тест (or test) Delete the lead, its repeats and its status history. Allowed only if the name or the comment contains тест or test (is_test_lead). Otherwise the bot refuses and suggests the plain form
/stickers_forget with no number Shows the last 5 leads as buttons; pressing one runs the plain form. With тест it lists only test leads

The confirmation text is Данные заявки #<n> удалены (имя, Telegram, телефон, комментарий). Из бэкапов сервера уйдут за 14 дней. В статистике заявка остаётся без контактов. (“Lead data erased (name, Telegram, phone, comment). It leaves server backups within 14 days. The lead stays in statistics without contacts.”) The log gets LEAD_ERASED #<n> по запросу, user=<id> (“on request”).

  • event_date and guests. Both are free-text fields. If a visitor typed personal data there, it stays.
  • Language, UTM values, timestamps, the status and the status history, which includes the Telegram id and display name of each admin who pressed a button.
  • The lead number and its request_id.
Copy Handling
The card in the group Rewritten automatically. If the edit fails (card deleted, edit refused) only a log line is written (LEAD_ERASE); check the group and delete the message by hand
Fallback messages (sent directly by the landing when the leads server did not answer) Not in the database, so /stickers_forget cannot find them. Delete the message in the group by hand
CSV exports (/stickers_export) Sent to the private chat of the admin who asked. Each admin deletes their own copies
Repeat pings and reminders Contain no personal data

Spam leads are anonymised 30 days after the last status change, all other leads after 365 days. See Reminders and digest.

deploy/backup.sh runs daily at 03:30 UTC (sticker-backup.timer). It copies the whole app.db with sqlite3 .backup, verifies it, compresses it and keeps the newest 14 files (KEEP) in /var/backups/sticker-pack, readable by root only.

  • The backup contains every table, including users and leads. It does not contain photos or any other file.
  • Data erased today is still in yesterday’s backup. It disappears when that file rotates out, 14 days later at the latest.
  • A restore from a backup brings erased rows back. After any restore, repeat the erasure requests received since the backup was taken.
  • Provider-level snapshots of the whole server, if enabled, follow the provider’s own retention and are outside this repository.

Last verified: 2026-11-13 against ai-sticker-pack@b715418 and ai-stickers-landing@e350ff5.