Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .dev.vars.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ TELEGRAM_WEBHOOK_SECRET=replace_with_a_random_development_secret

# Your numeric Telegram user ID; blank disables the admin panel.
SUPER_ADMIN_ID=

# Development access restriction. An empty whitelist permits everyone.
# Production always ignores this feature. IDs remain private Worker secrets.
APP_ENV=development
TEST_WHITELIST_ENABLED=false
WHITELIST_USER_IDS=
4 changes: 4 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ Keep real IDs in private Worker secrets or bot commands. `WHITELIST_USER_IDS` su

Removing the final tester also opens access to everyone; every change confirms whether access is restricted or open. Invalid configuration restricts access until the superadmin resets it. Payment and refund confirmations already issued by Telegram are still recorded after a tester is removed. Existing queued notifications are preserved.

In the development Mini App, open **Profile → Super admin → Dev access** to turn the whitelist on or off and add or remove numeric Telegram user IDs. The panel warns before enabling restrictions or removing the last allowed user. The superadmin always retains access. Turning it off keeps the saved IDs and permits everyone; turning it on restricts access when the list contains IDs. An empty ordinary whitelist still permits everyone. These changes apply immediately to the development bot and Mini App and survive redeployment. The `TEST_WHITELIST_ENABLED` variable is the initial default; the saved panel setting takes precedence. Production does not expose these controls or honor the development setting.

When development contains a production snapshot, its protection takes priority: the panel cannot turn access off, and removing the last tester leaves admin-only access. Database refresh retains the saved switch and whitelist together with the other development settings.

This restriction applies to the Cloudflare Worker, including its webhook and Mini App APIs. Use `wrangler dev` for local access-control testing; the standalone `npm start` polling process does not enforce this hosted feature. The whitelist command is advertised only in the configured superadmin's private chat.

## Copy production data to dev
Expand Down
4 changes: 2 additions & 2 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ The owner's edit page has a red event-actions section with Cancel event and Dele

## Tickets and check-in

Confirmed guests receive a unique ticket code. Confirmation requires an accepted response plus any required approval and verified payment. Private locations and ticket instructions stay locked until those requirements are satisfied.
Confirmed guests can request a six-digit check-in code from their ticket page. It expires at the next minute; **Refresh code** requests a new one. Codes are generated on demand, without background polling or scheduled generation. Confirmation requires an accepted response plus any required approval and verified payment. Private locations and ticket instructions stay locked until those requirements are satisfied.

Hosts can enter a code to check its validity, then check in the entire group. The result shows the guest name and participant count. A repeat check reports the existing check-in; a newly recorded check-in notifies the guest in Telegram.
Owners and co-hosts can use the event editor's check-in keypad to enter a code and check in the entire group. The result shows the guest name and participant count. A repeat check reports the existing check-in; a newly recorded check-in notifies the guest in Telegram. Existing QR tickets and check-in records remain valid.

Ticket validation checks the current event, acceptance, approval, and payment state. Cancelled or no-longer-confirmed tickets fail validation. An event with a saved finish time also rejects tickets after that time; an event without a finish time has no automatic end-time ticket expiry.

Expand Down
16 changes: 11 additions & 5 deletions docs/invitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,19 @@ A guest's selected count survives reopening the invitation. Editable counts can

In the bot, open **Manage → Invitation links** to see guest-name buttons, with ten guests per page and two buttons per row. When the complete invitation and link fit Telegram's 256-character copy-button limit, tapping the name copies them immediately. Longer invitations open that guest in **App**; tap their name there to copy the full message and personal link. Invitation details offer **Share invite**, **Copy invite** (or **Copy invite in App** for longer text), and **Copy link only**. Without App, the bot displays the full invitation so you can select and copy it. Messages are not truncated to fit the button.

The Mini App's **Guest invitations** view shows each invitation's responses, comments and attendee counts, plus totals for responses and accepted people. Filter by **Accepted**, **Declined**, **Maybe**, **Later** or **Unanswered**, and combine the filter with a guest-name search. Unanswered includes invitations with no response and guests who chose Later. A reusable invitation can show several responses and appear in more than one filter.
The Mini App's **Guest invitations** view shows each invitation's current response, comments and attendee counts, plus totals for responses and accepted people. Recorded response times appear in your timezone. Opening an invite without responding is shown as awaiting a response; it does not count as choosing Respond later. Filter by **Accepted**, **Declined**, **Maybe**, **Later**, **Unanswered** or **Revoked**, and combine the filter with a guest-name search. Unanswered includes invitations with no response and guests who chose Later. A reusable invitation can show several responses and appear in more than one filter. Older responses may have no recorded timestamp.

Each guest has **Share invite**, **Copy invite**, and **Copy link** actions. **Copy invite** includes the personal message and link; **Copy link** copies only that guest's URL. Guest-name buttons also copy the full invitation, and previews are expandable. If clipboard access fails, the requested text or URL is selected for manual copying. Guest names and unused links are private to the event hosts. Send personal links privately: possession of a link does not prove someone's real-world identity.
Each guest card keeps **Copy invite** and **Copy link** visible. **Copy invite** includes the personal message and link; **Copy link** copies only that guest's URL. Guest-name buttons also copy the full invitation, and previews are expandable. The three-dot menu contains **Share invite**, **Edit invite**, **Change response**, **Revoke invite** and **See history**. If clipboard access fails, the requested text or URL is selected for manual copying. Guest names and unused links are private to the event hosts. Send personal links privately: possession of a link does not prove someone's real-world identity.

Owners and co-hosts can expand **Add guests** and choose **Add one guest** or **Add a list**, without replacing existing links or responses. The individual form provides a name, a count from 1 to 10, and plain-language choices for one person, asking for a count, an editable preset, count confirmation or a fixed count. The same individual controls are available beside the text list when creating or editing an event. Adding a guest to an unsaved event appends a line to that draft; it does not send an invitation. Duplicate names need a distinguishing label.

The **Guest list** also has **Add guest** and **Invitations** shortcuts. Each named guest has **Invitation** and **Revoke invitation** actions; revocation opens the matching personal invitation's removal choices. **Remove invite** asks whether to **Notify guest** or **Remove silently**, with **Keep invite** to cancel. Notification is available only after a Telegram account has opened the invitation. Removing an invitation revokes its link and ticket, removes its responses from attendance totals, and clears related reminders and unfinished response steps. For reusable invitations, this affects every response associated with that link. Payment records remain available for separate refund handling; removal does not issue a refund. These named-invitation controls are not shown for shared ticket-booking links.
The **Guest list** also has **Add guest** and **Invitations** shortcuts. Each named guest has **Invitation** and **Revoke invitation** actions. **Revoke invite** offers an optional notification, off by default. Revocation disables the link and ticket, removes its responses from attendance totals, and clears related reminders and unfinished response steps. For reusable invitations, this affects every response associated with that link. Revoked cards remain available through the **Revoked** filter, with their history and a separate **Delete invite** confirmation. Deleting removes the card from the invitation list while retaining private audit, check-in and payment records. Neither action issues a refund. These named-invitation controls are not shown for shared ticket-booking links.

Links stay stable when you save the same guest names and count settings. The general event editor can remove unopened names, revoking their links. Once an invitation has been opened, that editor cannot remove or rename it, or change its count or selection mode. Use the dedicated **Remove invite** action above to revoke an opened or answered invitation. Changes are checked against the current guest list and responses; if another host or guest changes them first, refresh and review before retrying. This edit protection is separate from the one-time-use lock described below.
**Edit invite** changes the name, attendee count or attendee setting without replacing its personal link. Linked guest responses use the updated name and count rules. Attendance changes are blocked for checked-in guests and while protected payment or refund states apply; a name-only correction remains possible. The general event editor still protects opened invitations from bulk removal or attendee changes: use the dedicated per-invitation actions instead. Changes are checked against the current guest list and responses; if another host or guest changes them first, refresh and review before retrying. This edit protection is separate from the one-time-use lock described below.

**Change response** records Accept, Reject, Maybe or Respond later for a guest who has already opened the invitation in Telegram. For reusable links, select the actual guest response to change. Choose whether to notify that guest; silent saving is the default. Unopened invitations cannot create a response or ticket for an unknown Telegram account. Acceptance still follows payment requirements and attendee rules. Checked-in guests and protected payments cannot have their attendance changed here.

**See history** shows recorded creation, first opening by each guest, responses, response changes, edits and revocation with timestamps in your saved timezone. Organiser changes include whether notification was requested. History starts when activity is recorded by this version; older invitations may have incomplete history, and missing past timestamps are not invented. History is visible only to event hosts.

Editing loads the latest event details, including the invitation message, guest list, payment settings and existing banner preview. Saving without selecting a replacement image preserves the current banner.

Expand Down Expand Up @@ -139,7 +143,9 @@ For contributions without an RSVP, enable uploads and the separate public media

Hosts can review accepted responses and people totals separately, distinguish confirmed attendance from approval requests and unpaid bookings, and filter the roster by response state. Named lists also show unopened guest placeholders. An unopened name can appear in the roster, but the bot cannot contact a Telegram account that has not interacted with it.

Confirmed guests receive a unique ticket code. With QR codes enabled, the Mini App also provides a scannable ticket. Owners and co-hosts can verify a code or scan the QR and check in the entire group. A new check-in notifies the guest; repeat checks show that the ticket was already checked in.
Confirmed guests open **Check-in code** to request a six-digit code. It expires at the next minute; a countdown and **Refresh code** button help them request another. Codes are generated only when requested, with no background polling or scheduled generation. Owners and co-hosts open **Check in guests** from the event editor and enter the code using the numeric keypad to check in the entire group. A new check-in notifies the guest; repeat checks show that the ticket was already checked in.

With QR codes enabled, the ticket page also provides a scannable ticket. Existing ticket QR codes and saved check-in records continue to work.

QR codes start off for new events. Turning them off hides guest QR options and upload QR generation, while manual ticket codes, check-in by code and media upload links still work. Existing events without a saved QR setting retain QR functionality until it is disabled. Ticket QR payloads contain an event ID and ticket code, not the hosting URL.

Expand Down
Loading
Loading