Native iOS app built with Swift and SwiftUI. Public discovery connects to huddlz.com without signing in. No third-party dependencies.
- Xcode 26.6 for native behavior tests; CI also checks stable Xcode 27.1, build 27A9275
- Swift 6 language mode for the app and both test targets
- An iOS 26.5 simulator runtime for the default local test command
- Minimum supported OS: iOS 26.0; iPhone and iPad supported by the template. Use iOS 26 as the baseline; guard APIs introduced in later releases with availability checks.
- Open
Huddlz/Huddlz.xcodeprojin Xcode. - Select the
Huddlzscheme and an iPhone simulator. - Press Command-R to build and run.
- Press Command-U to run tests.
Add your Apple account in Xcode Settings, then select your development team under the app target's Signing & Capabilities tab. Automatic signing is enabled. Use the same team for test targets when testing on a physical device.
The initial bundle identifier is com.huddlz.Huddlz. Confirm the organization's identifier before registering the app for distribution.
Huddlz/Huddlz/: SwiftUI app entry point, discovery feature, shared UI, and assets.Huddlz/HuddlzTests/: Swift Testing unit test target.Huddlz/HuddlzUITests/: XCTest UI and launch tests.
Keep new code grouped by feature as features are added. Add shared UI and networking code when needed. Store private server credentials on the backend, never in the app or repository.
The app opens on Discover, the search tab, which keeps the discovery journey below unchanged. While Discover is selected its search field is expanded in the tab bar and the other tabs fold into one pill; tapping the pill opens Agenda and shows Agenda and Groups with the Discover search button beside them. Tapping that button returns to Discover with the field open. Scrolling down shrinks the bar and minimizes the field; scrolling up brings them back. Switching tabs and back keeps the search text, filters, and results in place. Signed-out visitors see what each tab will hold and a wide “Sign in” button that opens the account sheet in place; the tab checks the saved session before offering sign-in. The selected tab survives rotation and backgrounding through scene storage; the app does not promise it across a relaunch.
The Agenda tab opens under the huddlz wordmark and a glass Account button, with “Your agenda” and a count of the huddlz coming up once they load. It lists the upcoming huddlz the signed-in member is going to or waitlisted for, soonest first, with adjacent huddlz grouped by day in each huddl’s own time zone; each day’s huddlz share one card under a small heading. A day heading can repeat when time zones cross date boundaries, keeping the list chronological. Each row leaves the date to its day heading and shows the title, the start time with the event’s zone, the venue name (the address up to its first comma), and a Going pill in the accent or a Waitlisted pill in the warm hybrid tone. Tap a row to open the same huddl page discovery uses; native back returns to the agenda. Members with no upcoming RSVPs read that RSVPing to a huddl in Discover adds it here. A failed request offers retry. RSVP changes made in the app reload the agenda, so a cancelled RSVP disappears on return; changes made on the website appear on the next load or retry. Signing out returns the tab to the sign-in prompt and clears the list.
The tab uses the authenticated GET /api/json/huddlz/upcoming?filter[attendance_state][in][]=confirmed&filter[attendance_state][in][]=waitlisted route with the account client’s cookie-free, redirect-free session. The route returns every match with no pagination (verified September 12, 2026: the filter is accepted and page[limit] is ignored), sorted by start time, and the app sorts again before grouping. Responses for a previous account are discarded, and rows without an RSVP are dropped.
The Groups tab opens under the huddlz wordmark and a glass Account button, with “Your groups” above one card that lists the groups the signed-in member owns or has joined, alphabetically as the API returns them. Each row shows a tile with the group’s initial, tinted from the brand palette by the group’s name, then the name and the location. Tap a group to open the same group page discovery uses: the tile and name, the location, the description under “About this group”, and its upcoming huddlz in the same cards Discover shows; native back returns to the list. Members of no groups read how to join one from a huddl’s group page. A failed request offers retry. Twenty groups load at a time; “Load more groups” appends the next batch and a failed batch keeps the list with retry. Signing out returns the tab to the sign-in prompt and clears the list; signing in again loads that account’s groups. The list loads once per signed-in account and after retry; it does not yet refresh on its own when the app returns to the foreground.
The tab uses the authenticated GET /api/json/groups/mine?page[limit]=20 route with the account client’s cookie-free, redirect-free session. Pagination follows only the API’s own same-origin links.next for that route. Responses for a previous account are discarded. Member counts and next-huddl summaries are not in the API response and are not invented.
Browse real huddlz in cards that share the web app’s anatomy: a 16:9 cover with a solid date stamp (month over day) that stays readable over busy art and a glass tag, then the hosting group when known, the title, and a meta line with the weekday, start time, event zone, and location. The tag names the event type (in person, online, hybrid) in that type’s color; when signed in it shows “Going” in the accent or “Waitlisted” in the warm hybrid tone instead and the event type moves into the meta line. Cards without an RSVP keep the type tag. Location, date, and type filters are glass chips in one row that scrolls sideways; each takes the accent color only while it is set. While a search is active, “Results for” names it above the cards with a Clear search action. The status bar fades the cards scrolling under it. Badges refresh on app return, pull-to-refresh, and as cards enter view, and disappear after sign-out. Submit text with the keyboard’s Search action, and filter by event type (all, in person, online, hybrid) and date (all upcoming, this week, this month). Clear the search field to reset the text query. Pull to refresh while keeping the current cards visible. A failed refresh keeps the cards and filters and offers retry. Search uses the search tab’s native field. Native pull-to-refresh keeps working alongside it in the tab layout (verified September 12, 2026); the earlier UIKit search bar existed because a top-placed SwiftUI search field detached the refresh control. Scroll near the last card to load the next batch. A bottom spinner shows progress; a failed batch keeps the cards and offers retry. Loading stops after the final batch. Opening a card fetches current details separately. The huddl page opens on a full-width cover that fades into the page, then the event-type pill and title, a card with the hosting group and the day and time range in the event’s zone (an end on a later day is spelled out, and the zone’s everyday name, such as “Central Time”, sits beneath when it differs from the phone’s), the venue map or online label, the description, and online joining. The RSVP row with its one action floats at the bottom so it stays in reach while reading. Once the title scrolls under the navigation bar, the bar shows the huddl’s name; the group page does the same with the group’s name. The bar also offers Add to Calendar, which opens Apple’s new-event sheet filled in with the huddl (no calendar permission needed), and Share, which shares the huddl’s page on huddlz.com once its group’s slug loads. Details show the hosting group in that card. Tap it to read the group’s description and location and browse its upcoming huddlz in the same cards Discover shows. Native back navigation returns through the group to the original huddl. Empty lists explain that no upcoming huddlz are scheduled; failed requests offer retry. Load more adds the next batch without removing existing cards. Missing or withheld host information leaves the rest of the details available without a host row. Signed-in details show whether you are going, waitlisted, or have not RSVP’d. The status refreshes when details open or the app becomes active, including changes made on the website. Anonymous browsing shows no personal-status claim. Failed or unreadable status requests keep the event visible with retry.
Online and hybrid details offer “Join online” when the API grants access to a joining link. The server limits access to confirmed attendees and group organizers. Signed-out visitors see an explanation; a missing link leaves the section without an action. Returning to the app checks access again, and signing out removes the link. Failed requests keep the huddl visible and offer retry.
In-person and hybrid details show a native map when Apple Maps resolves the venue to one result. Tap the address row to open that place in Maps and choose directions. The API currently supplies location text without coordinates; failed, empty, or ambiguous lookups keep the address available as a Maps search. Online events and unannounced locations have no map action. A separate live check on September 7, 2026 resolved both the DOS Coffee address in St. Augustine and the Jacksonville Beach venue to one place in Apple Maps.
Choose Anywhere to search for a city or postal code with Apple Maps; the keyboard’s Search key runs the search, and the sheet’s close button leaves without choosing. Select a place, then choose a distance of 5, 10, 25, 50, or 100 miles. Clear location returns to browsing anywhere and keeps the event search and filters. Place searches run when submitted. Use current location requests location access only after you choose that action, then uses a single fix to find nearby huddlz. Denied access or an unavailable location leaves manual place search available. Leaving the picker cancels a pending lookup.
The client uses anonymous, cookie-free requests to the public JSON API:
GET /api/json/huddlzwithdate_filter,query,event_type,search_time_zone, andpage[limit].GET /api/json/huddlz/{id}?include=group&fields[group]=namefor details and the hosting group.GET /api/json/groups/{id}for the public group profile.GET /api/json/huddlz/by_group?group_id={id}&page[limit]=20for upcoming published group huddlz, ordered by start time.- Pagination follows same-origin links returned by the API, restricted to the discovery route or the same group.
- Location searches add
search_latitude,search_longitude, anddistance_miles. Relative date filters use the selected place’s time zone when available, otherwise the device’s time zone.
Schema: https://huddlz.com/api/json/open_api; browser docs: https://huddlz.com/api/json/swaggerui. Verified September 8, 2026: the deployed schema exposes field sorting without the former duplicate sort parameter, and sort=starts_at returns HTTP 200. The app uses default ordering. Group discovery remains separate work. Missing thumbnails use an event-type illustration; unavailable host/attendance data is not invented.
Design reference: prototype/issue-1-core-journey, variant A (cards). The prototype and simulated account/RSVP flow remain on that branch. The palette follows the huddlz web app (assets/css/app.css in the huddlz repo): teal accent, pink for online huddlz, and a warm tone for hybrid ones, each with light and dark values in the asset catalog. Artwork tests recognize the fallback illustration by its teal accent pixels and measure the cover below the date stamp and tag.
Open Account from discovery to sign in with an existing Huddlz account. Successful sign-in uses the profile city unless a location or Anywhere has already been chosen for this search; text and other filters stay in place. Account sheets sit on a material over the page, with a rounded title and subtitle beside a glass close button, labeled fields in hairline wells, a show-password control, a glass prominent sign-in button, and text links for password reset and registration; the signed-in sheet shows initials, name, and email on a surface card above a glass sign-out button. They expand for the keyboard and accessibility text sizes. The signed-in sheet groups initials, name, and email above sign-out. “Forgot password?” submits the email to the existing reset API, shows confirmation or a retryable error, and preserves the email on return to sign-in. The emailed link opens huddlz.com to choose a new password. “Create an account” submits a display name, email, password, password confirmation, and explicit acceptance of the linked legal documents. Registration saves the session, then offers an optional home-city step. Rejected forms keep entries available for correction. Upcoming plans and profile editing remain follow-up work under #4–#5.
After signup, choose a city, use current location, or select “Not now.” Location access is requested only after tapping that action. A detected location is resolved to a city center and shown for confirmation; the GPS fix is not saved as home. Confirming saves the city, coordinates, and time zone through the authenticated GraphQL updateHomeLocation mutation at POST /gql, then applies that city to the current search without clearing other filters. Failed saves keep the selection with retry and skip available. Later sign-ins and app launches read the current profile defaults again.
Authentication uses the dedicated JSON endpoints POST /api/auth/register, POST /api/auth/sign_in, GET /api/auth/me, and DELETE /api/auth/sign_out. Requests are cookie-free and do not follow redirects. Only the bearer token is saved, using device-only Keychain storage accessible while unlocked. Sign-in passwords are cleared after submission. Registration keeps passwords in memory for correction after a rejected request and clears them when the form is left or registration succeeds. The app checks a saved session on launch and when it returns to the foreground; expired sessions are removed, while temporary failures offer retry. Sign-out removes the local token before attempting server revocation, with clear feedback if the server cannot be reached. Public discovery remains available without an account.
Search badges use authenticated sparse requests to GET /api/json/huddlz, with date_filter=all, fields[huddl]=attendance_state, and repeated filter[id][in][] parameters for visible cards. Requests contain at most 20 IDs, combine brief visibility changes during scrolling, and use the account client’s redirect policy. Public search and pagination stay anonymous. Failed badge requests clear stale badges while keeping cards available; refresh or scrolling retries the lookup.
Personal RSVP status uses a separate authenticated GET /api/json/huddlz/{id}?fields[huddl]=attendance_state request. It sends the saved bearer token through the account client’s cookie-free session and rejects redirects. Public event requests stay anonymous. Status remains in memory; account changes and cancelled requests cannot apply a previous account’s response. Event details support RSVP, cancellation, and leaving an existing waitlist. Signing in returns to the same event to finish the RSVP. Pending requests disable the action; failures keep the current status and allow retry. Cancelled, completed, draft, and past events explain that RSVPs are closed. Full-event and other readable API rejections appear beside the action. Successful changes refresh joining access and search badges. The upcoming-plans screen and waitlist enrollment remain separate work under #4.
The authenticated GET /api/json/profile endpoint supplies the current home city, coordinates, time zone, and default radius. The app keeps this information in memory and requests it again after sign-in or session restoration on a new launch. An explicit place or Anywhere takes precedence, including when the profile response arrives late. Missing or failed profile data leaves unrestricted discovery and manual location search available. Search overrides do not change the saved profile or request device location permission.
The registration API still returns internal multiline exception descriptions for some validation failures (verified with an empty, rejected request on September 8, 2026). The app displays concise API messages when available and uses plain fallback feedback for internal or unreadable responses. Validation rules and confirmation email delivery remain backend responsibilities. Live checks did not create an account or send email.
Run the store rules with swift test from the repository root. It needs no Simulator and takes seconds: the root Package.swift compiles every app file that does not import SwiftUI, so keep stores, clients, and models in files of their own, apart from views. Run the full local suite, UI journeys included, with ./scripts/test-behaviors.sh. It uses four simulator workers, keeps build products between runs, and prints the elapsed time and paths to the log and result bundle. No tests are excluded. Use HUDDLZ_TEST_WORKERS=2 ./scripts/test-behaviors.sh on a Mac with less CPU or memory. Override HUDDLZ_TEST_DESTINATION or HUDDLZ_TEST_DERIVED_DATA when needed.
For focused work, pass Xcode test selections: ./scripts/test-behaviors.sh -only-testing:HuddlzUITests/RSVPUITests or ./scripts/test-behaviors.sh -only-testing:HuddlzTests/RSVPBehaviorTests. Command-U also runs the full suite; the shared scheme allows parallel UI execution. Discovery journeys are split into browsing, pagination/refresh, location, venue, and artwork classes so Xcode can distribute them independently. Registration, manual city selection, and location-permission journeys also have separate classes. Test names describe the behavior they protect.
Measured locally on September 10, 2026 with Xcode 26.6, iOS 26.5, and reused build products: the previous serial full run took 18m49s; two workers took 9m40s; two four-worker runs took 5m36s and 5m37s. Each full run passed 110 tests / 149 executions with no skips. A cold build or a Mac with fewer resources will take longer.
Most behavior tests use Swift Testing at the store edge: the real store and client, with only the network faked by HTTPFixture. Each test acts as a person would (search, load more, retry, sign in) and checks the state they would see, so refactors that keep behavior keep tests passing. Error, retry, filter, pagination, and race rules belong there and run in seconds. UI tests are slow, so they cover the core journeys and their wiring: signing up, signing in, discovering, RSVPing, deleting an account, and system handoffs only the app can show, such as permission prompts, Maps, and the native refresh spinner. When a store test covers a rule, don't repeat it in a UI test. AGENTS.md has the full rules.
UI tests pass a response script through HUDDLZ_UI_HTTP_SCRIPT. The debug build uses it only at the HTTP boundary; requests, decoding, state, and views remain real. A missing or invalid scripted response fails locally instead of contacting production. Release builds exclude this hook.
State timing tests hold and release responses explicitly, so cancellation and overlapping searches do not depend on sleeps. Refresh tests cover retained cards, failure, cancellation, and a newer search superseding a pending refresh. A visual test delays the HTTP response and captures the native spinner during refresh; restoring the conflicting search integration makes this test fail. Keep live API smoke checks separate from this deterministic suite.
A pagination UI test scrolls through real cards and verifies bottom progress and a stable scroll position. State tests cover retry after a failed 8894 batch, a repeated batch, overlapping requests, the final batch, and old responses arriving after a new search. Pagination observes refresh state in its own footer view; observing it in the view that owns refresh hid the native spinner on iOS 26.5. Discovery uses one lazy stack; nesting it inside a regular stack caused scrolling to hang during layout on iOS 26.5.
Account tests use real Keychain entries with unique test service names, plus HTTP fixtures for the authentication endpoints. UI journeys sign in, request a password reset, and register with explicit legal acceptance; each signs out to remove its saved token. Store tests cover incorrect credentials, reset errors and retry, rejected registration fields, relaunch, and sign-out. State tests verify credentials and bearer headers, session expiry, retry after transient failures, and local sign-out when server revocation fails. When sign-in is only a precondition, launchWithSavedSession() seeds a real token in the isolated test Keychain and uses normal account restoration. The helper removes the seed from subsequent launch environments, so reopening after sign-out cannot silently recreate a session. Sign-in, registration, and sign-in detour journeys still use their real forms. Test-session namespaces and session seeding are excluded from Release builds and never read the normal app session. Account completion waits allow up to 60 seconds and return as soon as the expected UI appears. CI diagnostics showed real Simulator Keychain saves and deletions taking tens of seconds; short UI deadlines failed while those operations were still running. A delayed HTTP response reproduced the original timeout during diagnosis; routine tests keep responses immediate. These behavior checks verify completion, not Keychain speed.
Artwork tests send PNG bytes through an HTTP fixture and verify visible image pixels in cards and details. Missing images, failed requests, and unreadable image data retain the event-type illustration. A malformed image URL does not prevent the event from loading.
The app uses the API’s resolved image_url, with thumbnail_url retained for older responses. After backend #430 deployed, live event artwork and the group image fallback were verified in discovery; the group image also appeared in event details on September 7, 2026.
Place-search tests replace Apple’s external Maps search and exercise the real request, map-item conversion, state, and views. UI fixtures use HUDDLZ_UI_MAP_SCRIPT; when UI HTTP fixtures are active, place lookup also fails locally on missing fixtures. Both fixture hooks are excluded from Release builds.
Signup-location tests use native permission prompts and simulated device location, with external Maps responses supplied by HUDDLZ_UI_MAP_SCRIPT and HUDDLZ_UI_REVERSE_CITY. Reverse lookup fixtures require the HTTP test script and never fall through to live lookup. Tests cover confirmation, skipping, city-center coordinates and time zone, failed saves, permission denial, unavailable location, and cancelled lookups. Separate read-only checks on September 8, 2026 confirmed the deployed GraphQL mutation and its inputs; no real profile was changed. Live Maps checks resolved a Kansas City coordinate to a city center and time zone, and manual St. Augustine search returned a complete city. Reverse lookup returned no match for two St. Augustine coordinates; the app leaves manual search and skipping available in that case.
Venue-map UI tests control the external place lookup, render the native map, and tap the address to launch Apple Maps. Store tests cover unavailable and ambiguous lookups and which huddlz have no map action. Swift Testing also verifies the exact place coordinates and encoded address sent to Maps. Map tiles and the Maps app remain system services; assertions do not depend on their live search results or tile imagery. Handoff tests allow up to 30 seconds for Maps to enter the foreground and keep it alive between fixture cases, then terminate it at test teardown. CI has delivered its foreground update more than 12 seconds after a tap; short launch deadlines can fail even when the link works. A failed handoff saves a screenshot.
A current-location UI journey uses Apple’s simulated device location and the real system permission prompt to find nearby results. Store tests replace Core Location to cover permission, denied access, unavailable and stale fixes, and retry. The HUDDLZ_UI_LOCATION_FAIL_FIRST fixture still lets a UI test fail one external location request; it requires HTTP fixtures and is excluded from Release builds.
Profile-default tests cover sign-in, relaunch with a changed profile city, explicit location precedence, missing and failed profiles, and signing out during a pending profile request. Held HTTP responses make race tests deterministic. UI tests verify nearby cards, the city and radius controls, and clearing the location. Separate read-only checks verified the deployed profile route rejects anonymous access with 403; authenticated response handling is tested against the documented contract with fixtures, without reading or changing a real profile.
Host behavior tests open a card through the real request, decoding, and UI. They check the matching group name and details with missing or withheld host information. A UI journey opens the host and returns to the huddl. GroupDetailStore tests cover empty lists, unavailable groups, and retrying initial and later huddl batches. Separate read-only checks on September 9, 2026 returned HTTP 200 for a public group and its 16 upcoming huddlz. No account or profile was changed.
Attendance behavior tests cover confirmed, waitlisted, and absent RSVPs after sign-in and relaunch, refresh after a background change, retry while preserving public details, and no status claim while signed out. Native Keychain storage and real decoding remain in the path. Held HTTP responses cover sign-out races; malformed or mismatched responses must report errors instead of an absent RSVP. Separate read-only checks on September 9, 2026 verified the deployed schema and anonymous attendance_state response. Authenticated behavior uses fixtures; no real RSVP was read or changed.
Search-badge tests cover going, waitlisted, and unmarked cards, foreground and pull-to-refresh updates, sign-out, stale-response rejection, failed refresh recovery, and bounded batch requests. HTTP fixtures preserve repeated query parameters for ID arrays. Separate read-only checks on September 9, 2026 verified that the deployed sparse search endpoint accepts the ID-array filter; no real RSVP was read or changed.
GitHub Actions runs these jobs:
- Store rules (1m20s on November 9, 2026) runs
swift teston the Mac with no Simulator: the 90 Swift Testing rules. - Behavior tests runs every UI journey across four Simulator jobs side by side. The first three jobs run the classes listed for them in the workflow; the last,
everything-else, skips those classes, so a new test class runs there without an edit. It also runs the store rules again inside the Simulator. The four jobs took 9 to 12 minutes on free hosted runners, about seven of them before a job's first test starts.
When those jobs run depends on whether main has a merge queue, which the Choose Simulator jobs job checks on every run:
- With a merge queue, a pull request runs the store rules and the compiler check only, and hears back in about two minutes. Choosing "Merge when ready" puts it in the queue, which runs every UI journey on the exact commit that would land. A failure there keeps the change off main. A push to main then runs five core journeys on one Simulator (
CORE_JOURNEYSin the workflow), which also keeps the Simulator cache on main for the queue to restore. - Without a merge queue, every pull request and every push to main runs every UI journey.
The queue is the gate for every contributor. To see a UI journey fail sooner, run ./scripts/test-behaviors.sh on a Mac before you queue.
Each Simulator job builds before it boots, because a booting Simulator slows the build sixfold. A hosted runner's Simulator has never booted, and its first boot took 1 to 8 minutes, so one run caches the booted Simulator's data and later runs on the same runner image restore it. Cloning Simulators for parallel workers took longer on hosted runners than the whole serial run. Each job must pass with no skips. The required “Native behavior tests” check passes only when the store rules, the Simulator jobs for that event, and the Xcode 27.1 compiler check succeed. You can also start it from Actions → iOS tests → Run workflow.
Simulator builds use ad-hoc signing so tests can exercise the real Keychain. Disabling signing prevents Keychain access; no signing certificates or developer team are required for these simulator tests.
The behavior-test jobs use Xcode 26.6 and an iPhone 17 simulator running iOS 26.5 on macos-26. The separate required compiler job uses stable Xcode 27.1 (27A9275) and the iOS 27.1 SDK to build all test targets in Debug and the app in Release. It verifies the compiler version and build. Both checks must pass; a successful build does not count as a behavior-test pass. No signing certificates or production credentials are required.
Xcode 27.1 is available on GitHub's public-preview xcode-27 runner, through /Applications/Xcode_27.1.app. See the latest-compiler inventory and behavior-test runner inventory. The compiler job saves Debug and Release build logs as ios-latest-compiler-results for seven days.
The October dependency review enabled Swift 6 for all targets. The October 19 Xcode 27.1/iOS 27.0 attempt reproduced twelve UI failures: Discover search and tab navigation, search filters and refresh, artwork rendering, and registration legal links. Its remaining group also reached the 30-minute job limit before completing. The Xcode 27.1/iOS 26.5 fallback downloaded the supported runtime and compiled successfully, but XCUITest failed to initialize with “Timed out waiting for AX loaded notification.” That host failure does not establish a behavior pass or an app regression. Keep native behavior execution on the known-working Xcode 26.6/iOS 26.5 runner while requiring latest-compiler compatibility. No tests are skipped or weakened. Full Xcode 27.1 runtime adoption and the iOS 27 UI migration remain blocked; Xcode 27.2 beta is excluded from stable maintenance.
Open Behavior tests on a PR to see its Xcode logs. Each job saves an ios-test-results-… artifact for seven days with the build and test logs, test summary, and an .xcresult bundle you can open in Xcode.
Joining integration tests cover opening the system browser, hybrid organizer access without an RSVP, revoked access on app return, sign-out, retry, and the absence of an online section for in-person events. Held HTTP responses verify sign-out discards a pending link; malformed URLs and responses for another huddl cannot produce an action. The client requests visible_virtual_link through an authenticated, cookie-free sparse detail request and accepts absolute HTTP(S) URLs. Separate read-only checks on September 9, 2026 verified the deployed schema and a null link in an anonymous response. No real private joining link was fetched or opened.
RSVP integration tests cover the native sign-in detour, RSVP/cancellation, leaving an existing waitlist, pending requests, full and failed requests, closed events, joining access, and search badges. Swift Testing exercises real requests and Keychain sessions, including expired sessions, old responses after a fresh sign-in, and a status read completed after a successful RSVP. Live checks for this change read only the deployed OpenAPI contract; no real attendance was changed.
Use the current product names and deployed API routes. The backend refactor removed the old “my-” naming; do not introduce that prefix in new UI, documentation, or assumed API paths. Upcoming plans belong to the regular huddlz experience.