React Native application
Install, configure, and operate the PlayHub Android and iOS application. Explore features, publishing, Live streaming, platform setup, and the documented development history.
React Native application
Application overview and supported platforms
The PlayHub mobile application connects to the same PlayHub installation as the website through the versioned /api/v1 API. It combines video and Shorts playback, creator profiles, discovery, libraries, community posts, messages, notifications and creator tools. Available screens depend on the installed website, account permissions and the capabilities returned by the server.
The supplied records document implementation work and development builds through 9 October 2026. The 9 October connected run records Android Live PASS on a physical Samsung device. The records do not establish a signed production Android release, a distributable iOS IPA or release-wide acceptance across supported platforms. The recorded iOS development build uses application version 1.0.0, build 1; this is development artifact metadata. See version and update history and iOS installation and release requirements.
| Platform | Application and API scope |
|---|---|
| Android phones and tablets | React Native application with development-build evidence and a 9 October physical Samsung Android 15 Live pass. Complete release-wide acceptance remains separate; test the final signed build and supported hardware before distribution. |
| iPhone and iPad | Shared React Native application with native iOS modules. A Simulator development build compiled successfully; actual iOS execution and signed physical-device acceptance remain outstanding. iOS 16.4 is the recorded Simulator artifact's minimum. |
| Android TV and Apple TV | The API supports android-tv and tvos, with device-code sign-in and restricted token abilities. A finished TV application or accepted TV build is not established by these records. |
| Samsung Tizen and LG webOS | The same HTTP contract supports tizen and webos. These require separate TV web runtimes, packaging, remote navigation and platform testing. |
Use the website documentation to install the backend and the API reference for endpoint methods, parameters, schemas and authentication. Live services have their own installation and capability guide.
Requirements and deployment prerequisites
A working PlayHub backend
- Deploy the current website code and database migrations, including native sessions, version policies and the capabilities required by the features you enable.
- Use PHP 8.3 or newer supported by the website package. The native API baseline was exercised on PHP 8.3.33; check the website guide for the complete PHP extension and service requirements.
- Provide an API origin that the target device can resolve and reach over trusted HTTPS. Production endpoints must use public DNS and a valid trusted certificate.
- Set independent, strong backend
APP_KEYandPLAYHUB_NATIVE_HASH_KEYvalues. Keep these values on the server. - Configure exact social-login callback allowlists, permitted CORS origins and the platform version policies for each client you intend to support.
- Run healthy background queue workers and FFmpeg/FFprobe for upload processing. Verify media storage, protected delivery, CDN signatures and byte-range requests.
- Configure SMTP, SMS and social providers only for the login or registration methods you enable. Live viewing and publishing also require the configured LiveKit services.
- If enabling native push, configure the appropriate FCM/APNs credentials and required tables, and supervise a worker for the configured push queue, which defaults to
push. A worker listening only tovideos,defaultdoes not deliver push jobs.
The application project and build tools
Work from the supplied react-native-app project, including its lockfile, local native modules, Expo plugins, configuration files and package scripts. You need npm and a Node.js version compatible with that package, an Android SDK/build environment for Android, and an Apple build environment or EAS Build for iOS. Signing credentials, native identifiers and store configuration belong to your deployment.
The documentation archive does not contain the application package itself or specify a universal Node, JDK or Android SDK version. Use the requirements pinned by the actual application package rather than upgrading native dependencies independently. The iOS guide lists the evidenced iOS profiles and commands.
The source records used a private .test host. Your phone, simulator, cloud build and hosted test service each need working DNS, certificate trust and network access for their selected endpoint. A local host that works on the developer computer may be unreachable from a physical phone or EAS worker.
Install and prepare the application
Google IMA SDK and advertising terms
This application integrates Google IMA SDK. Buyers must comply with Google’s IMA SDK Terms of Service, Google APIs terms, and the applicable advertising-service terms and policies, including Google Ad Manager requirements.
1. Install the supplied package
Open a terminal in the supplied react-native-app directory and install the dependencies from its lockfile:
cd react-native-app
npm ciKeep the package's postinstall step enabled. The recorded project uses guarded, version-specific native and LiveKit patches; a dependency-only install that skips those steps may omit required fixes. If installation reports unsupported versions or changed source anchors, resolve the package mismatch before building.
2. Configure the target environment
Review app.settings.json, app.config.ts, eas.json and the package's environment configuration. Set EXPO_PUBLIC_API_BASE_URL to the real HTTPS API endpoint for the selected deployment, ending in /api/v1. Configure the appropriate native application identifier, branding, provider player IDs and EAS project before producing an artifact. See configuration.
3. Produce a native development build
Use the supplied project's native build scripts and Expo configuration. The recorded Android workflow uses tools/build-android-windows.ps1; its optional -ManifestOnly mode checks the merged release manifest without producing a signed release. Generate native projects from the persistent configuration and plugins so camera, microphone, MediaProjection and network security settings survive the next prebuild.
The documented application includes native playback, advertising, Cast, AirPlay and real-time media modules. Use a compatible native development build for those integrations. A development client requires Metro; a standalone artifact has a different build profile. For iOS, follow the exact profile and command guide.
Standard Expo CLI workflow for local Android development
After installing the locked package and configuring its native plugins, Android Studio/SDK and device, Expo CLI can compile and install a debug build. Connect a phone with USB debugging enabled, or start an emulator:
npx expo run:android --deviceThis starts Metro after installation and generates native directories if absent. For subsequent JavaScript-only work, start Metro with the command below. Native/configuration changes require regeneration through the package's persistent plugins and a rebuild. These are the standard Expo local-build steps; prefer the supplied Windows helper when it handles project-specific preparation.
npx expo start --dev-clientPlayHub includes custom native video, LiveKit and provider modules, so use its own native development build. See Expo development builds for device/emulator setup.
4. Verify the installed app
- Confirm the app reaches its intended
/api/v1/bootstrapusing normal certificate verification. - Check branding, enabled features, minimum-version handling and maintenance messages before signing in.
- Sign in, restart the app and confirm secure session restoration. Test logout and account changes without retaining another account's private data.
- Play a known compatible native video, seek, pause, leave playback and verify media stops when closed. Test each enabled external provider separately.
- Test permission denial and permission grants, then upload or use Live only when those features and their backend dependencies are enabled.
- Validate the final signed artifact on the supported devices. A successful JavaScript export or debug manifest check does not replace native build and device testing.
For an existing installed development app, the recorded Android workflow used adb install -r with the corrected APK and retained the signed-in session. Use the APK generated for your own build and compatible signing identity; this is not a store release procedure.
5. Prepare Android distribution
Select the Android release profile supplied in eas.json, configure your approved application ID and public API, and complete the package's release checks. Use your publisher's signing keystore, preserve it for upgrades, and increase the Android version code for each distributed update. Build a signed AAB for Google Play or an APK profile for authorized direct installation; a debug APK is not a store artifact. The recorded Android development identity used com.playhub.mobile.dev, version name 1.0.0 and version code 1.
Follow the supplied package's Android build command/profile and EAS signing/build setup. Validate the actual signed artifact on target devices, with bundled JavaScript and no Metro, before distributing. Verify upgrade/session persistence, camera/microphone denial and recovery, playback, background cleanup, deep links, privacy declarations, and configured push delivery. Store submission is separate from successful compilation.
Configure connections, identity and services
| Setting or file | Purpose | Configuration guidance |
|---|---|---|
EXPO_PUBLIC_API_BASE_URL | Public application API endpoint. | Use the real trusted HTTPS origin plus /api/v1. This is embedded public configuration; it must contain no passwords, tokens or server secrets. |
app.settings.json | Deployment settings and native identity. | Edit the existing package's documented fields. Keep local, cloud acceptance and production API selections distinct. The full settings schema is supplied with the application package, not this archive. |
app.config.ts | Persistent Expo/native configuration. | Controls generated native behavior, plugin integration and permission declarations. Regenerate native output after changing this configuration. |
eas.json | Build profiles and environments. | Select the appropriate development, preview, Simulator or production profile. Keep the bundle's API value and the API checked by preflight consistent. |
connection.developmentApiBaseUrl | Local development connection. | Use only for a development device/network that can resolve and trust the chosen backend. |
deployment.iosSimulatorApiBaseUrl | Dedicated cloud Simulator API selection. | Requires a public, trusted HTTPS endpoint accessible to cloud services. See iOS configuration. |
native.ios.productionBundleIdentifier, PLAYHUB_IOS_BUNDLE_IDENTIFIER | Approved production Apple identity. | Set the actual Apple bundle identifier for your application. Do not infer it from an Android package name. |
native.ios.appleTeamId | Apple team identity. | Use the real authorized Apple team and matching provisioning/signing access. |
providers.dailymotionIosPlayerId, EXPO_PUBLIC_DAILYMOTION_IOS_PLAYER_ID | Public Dailymotion iOS Studio Player ID. | Configure separately from Android. This initializes the official iOS player and is not a provider API secret. |
Backend APP_URL, APP_KEY, PLAYHUB_NATIVE_HASH_KEY | Canonical website origin, encryption and native credential hashing. | Server configuration only. Use independent strong keys and protect the backend environment file. |
Backend PLAYHUB_NATIVE_SOCIAL_RETURN_URIS | Exact native OAuth callback allowlist. | Configure the actual callback URI or approved universal/app link for each intended client. Default contract URI: playhub://auth/callback. |
| Website Admin settings | Authentication, publishing, ads, storage, Live and provider availability. | Configure the website first; the app reads effective capabilities through bootstrap and account capability endpoints. |
Backend config/push.php and push worker | FCM/APNs delivery configuration and queue selection. | Delivery defaults to disabled. Configure real platform credentials and required tables, then run a worker that consumes the configured queue, default push. Credentials stay server-side. |
Runtime configuration and version policies
At cold start the app calls GET /bootstrap. Enforce maintenance and unsupported/required-update states before normal navigation. Build sign-in options from authentication, registration from the returned policy, and screens from features, playback, uploads and advertising. Refresh this private, 60-second-cacheable document after sign-in, app upgrades and foregrounding when stale.
The server supports version policies for ios, android, android-tv, tvos, tizen and webos. The administrator version-policy routes require server-side authorization; the consumer app does not gain administration privileges from capability discovery.
Permissions and network security
Request camera and microphone access when the user enters a feature that needs them. The Android capture-permission correction keeps the image-picker and WebRTC plugin descriptions consistent so prebuild does not remove required permissions. After a new permission grant, Go Live requires a fresh Test action before capture starts.
Production network security uses system certificate authorities and denies cleartext transport. The existing Android development certificate trust is confined to debug configuration. Configure an actual development certificate and device trust where required; never bypass TLS or hostname verification to connect the application.
Features and how to use them
Home, Explore, More, Library, profiles, Creator Studio and Settings provide entry points appropriate to the signed-in account. Server-side feature flags, ownership, publishing policy and quotas determine which controls are shown and which requests are permitted.
Discover and watch
| Feature | Available behavior |
|---|---|
| Home | Device-aware server feed and paginated sections, with Explore and More entry points. |
| Explore | Refreshing and paginated discovery using the installation's enabled categories, public topics, recent/popular videos and actual creator summaries. |
| Trending | Today, Week, Month and All-time ranges with video/Short and category filters. The server ranks and filters results before pagination. |
| Search | Suggestions and search for supported videos, Shorts, creators, live streams, playlists and categories. Results still obey server visibility and access rules. |
| Shorts | Cursor-paginated vertical discovery with playback, likes, comments, sharing, saved progress and Watch Later integration. Only the active external-provider card mounts its player. |
| Subscriptions | Latest, Popular, Continue and Creators views; server-supported Today, New, Unwatched, Replay and content filters. Subscription changes refresh related profile, discovery, community and Live state. |
| Live directory | Live, Upcoming and Replay sections with real enabled categories, following/date/sort filters and current server counts. See Live features and requirements. |
| Watch and player | Compatible native media and official external-provider playback, resume progress, related content and social actions. Full provider and device support depends on the final build and configured services. |
Library, creators and communities
- Library: Watch Later, Liked Videos, purchased videos, subscriptions, watch history and Continue Watching are scoped to the current account.
- Playlists: create and edit playlists, manage privacy and metadata, add or remove permitted videos, and open visible public or owned private lists.
- Favorites: save creator channels and browse their latest public content. Favorites remain separate from channel subscriptions.
- Creator profiles: Videos, Shorts, Live/replays, playlists, About and community content; permitted subscribe, favorite, message, report and share actions.
- Communities: creator channel posts with search, latest/relevant discovery, suggested channels, hashtags, upcoming events, following and type filters. Joining means subscribing to the creator channel.
- Community creation: text, link, image, poll, video and event posts, safe link previews, supported media validation, owner editing/deletion, polls and permitted voter lists.
- Community interaction: likes, replies, bookmarks, share counts, image galleries and context-aware comment navigation. Locked paid photos reveal only media the account is allowed to access.
- Comment moderation: an owner-scoped video/community comment inbox with permitted pin, delete, mute and thread-navigation actions.
- Messages: native private conversations, recipient lookup, message lists, sending and read state when the current backend enables messaging and permits the recipient relationship.
- Notifications: in-app inbox, unread count, preferences, read/delete actions and authorized destinations. Remote push delivery has separate availability; see notifications and push.
Communities use creator channel posts; standalone groups, separate membership directories and community rules are not part of the documented backend model. Owner profile layout/pinning, advanced preferences and some provider workflows use the existing website.
Creator Studio and publishing
- Dashboard: current account/channel capabilities and shortcuts to publishing, content, analytics, growth and earnings.
- Upload and import: resumable video/Short uploads with metadata, thumbnail, captions, chapters and asynchronous processing; configured provider URL import using existing server validation.
- Content management: actual status/type/monetization filters, metadata search, server counts and sorting, multi-select visibility/deletion with confirmation and partial-failure recovery, series assignment and playlist shortcuts.
- Video editing: supported metadata, visibility, scheduling, artwork, captions, chapters and monetization settings. Paid pricing and unsupported advanced per-video controls remain website workflows.
- Channel settings: name, slug, biography, About, website/social links and artwork, with unsaved-change handling.
- Analytics: supported period/date/comparison controls, cumulative content views, signed-in identities represented in saved progress, saved-progress totals/averages, engagements, subscribers, daily returned series, top content and content/visibility mixes.
- CSV export: share the actual returned daily metrics; unavailable per-video subscriber values remain blank.
- Growth Hub: current advisory information and shortcuts to upload, Shorts, content, analytics, profile and community tools.
- Go Live: configured metadata, schedule, device/network preflight, host controls and moderation. See the current Live capability and acceptance guide.
Saved progress records the latest playback position. It does not measure cumulative watch time or average view duration. The documented backend has no historical daily view/revenue series, traffic-source, geography, device/platform or realtime analytics measurement.
Account, storage and financial information
| Area | Behavior and boundary |
|---|---|
| Account and security | Profile/contact/privacy settings, muted users, tips/donations preference, password, two-factor authentication, device sessions and logout. Account switching uses a safe sign-out/sign-in flow with private-cache reset. |
| Account storage | Server-reported used/quota/remaining/percentage, provider and current plan. Upload eligibility is rechecked by the server before a session is created. Phone cache usage is a separate setting. |
| Earnings | Actual available, lifetime, last-30-days and pending-withdrawal information plus paginated transactions and supported source filters. Amounts and ownership come from the backend. |
| Wallet | Balance, earnings, pending/reserved amounts and paginated transaction history. A confirmed withdrawal creates an administrator-processed request subject to server balance, minimum and eligibility rules; it does not execute an automatic bank transfer. |
| Plan and billing | Actual plan catalog/current tier, prices, quotas/features, available subscription metadata, billing history and owner billing-information editing. Payment-card data is not stored in the native account form. |
| Digital checkout | Native StoreKit/Google Play purchase creation remains disabled. Existing authorized web purchases can play. Plans, top-ups, paid media, creator tips and boost budgets use the relevant configured website workflows, which may require browser sign-in. |
| Core video boosts | Eligible creators can open the website's existing budget, billing, pause/resume/cancel and history workflow. Availability follows real video-promotion settings and eligibility. |
Language, help, TV and optional extensions
Settings provides the installation's available interface languages, translated authored labels, cached language packs, a device-scoped language preference and RTL direction support. Video titles and user content are retained as authored. Light, Dark and System appearance use the existing native accessibility and reduced-motion behavior.
About/Help exposes the enabled managed About, Contact, Developers, FAQ, Support, Refund, Privacy, Terms and Cookie pages at their canonical website addresses. Connect TV previews an existing device code and requires explicit account/device/code confirmation before approval; expired and reused codes fail safely.
Plugins require installation, enablement, healthy boot state, explicit mobile support and account permission, plus a compatible native implementation. Unknown or unavailable plugin links return safely to More. Campaigns is an optional add-on and was not installed in the audited core source. Core video boosts are a separate feature. Platform administration remains on the permission-protected website; browser advertising slots do not become native card scripts.
Video playback and provider configuration
Fetch the video details, then request a fresh playback session immediately before starting or resuming. Use the explicit provider, source_type, provider_id and provider_url fields rather than guessing from an arbitrary URL. Existing imported records are normalized by the server.
| Returned source | Playback integration | Requirements |
|---|---|---|
| Native MP4 | Native player using Media3/ExoPlayer on Android or AVPlayer on iOS. | Prefer a compatible default rendition. Generated video is H.264/AAC fast-start MP4. |
| Direct HLS/DASH import | Native player where supported. | The backend can return compatible imported streams but does not generate adaptive manifests. iOS excludes DASH and needs a real MP4/HLS fallback. |
| YouTube | Official YouTube IFrame player. | Use the returned provider metadata and the provider's permitted controls and behavior. |
| Vimeo | Official temporary API play links when available; otherwise official embed playback. | Refresh expiring links. For embeds, preserve provider_url, including an unlisted privacy hash when present. |
| Dailymotion | Official SDK/provider player. | Configure the required platform Player ID. iOS has a separate ID and compiled native bridge; actual runtime acceptance remains outstanding. |
| Twitch | Official channel, VOD or clip embed. | Use an approved HTTPS parent; IDs are namespaced as channel:, video: or clip:. Clip telemetry has provider limitations. |
Protected media, captions and seeking
- Use the returned source URL and
mime_typedirectly. Never construct upload or storage paths in the application. - For creator avatars and banners, use the API's complete
avatar_urlandcover_url. Current private-cloud display assets can use signed application image routes; stripping a signature or rebuilding an unsigned uploads URL breaks access. - Protected video and caption URLs contain expiring query signatures. Do not append bearer tokens to them. Refresh the playback session before
expires_at. - Local delivery supports MIME types, content length, byte ranges,
206responses, suffix ranges and416for unsatisfiable ranges. S3/CDN delivery must retain range behavior, CORS headers and query signatures. - Sidecar WebVTT uses
text/vtt; SRT usesapplication/x-subripwhen reported client support permits it. Generated MP4 may also contain embeddedmov_text. Legacy TXT captions are not native sidecar tracks. - Remote direct media must use HTTPS and a compatible container. External origin codecs, MIME, TLS, CORS and range support remain deployment/provider dependencies.
Progress, player ads and receiver handoff
Start at resume_position_seconds. Send PUT /videos/{video}/progress with one UUID event_id per logical event and reuse it only when retrying that event. Follow the returned minimum interval, currently ten seconds, and send pause, completion and background transitions when possible.
PlayHub player advertising applies to native sessions. Resolve an enabled ad break shortly before playback of the ad instead of delaying video-session creation on an ad server. Payout-bearing completion is tied to the authenticated native session; anonymous playback does not create creator earnings. External embedded providers control their own advertising.
Before configuring Google IMA advertising, review the Google IMA SDK and advertising terms in the installation guide.
The API exposes receiver-playback endpoints for native video/Short Cast handoff. The server rechecks access and permitted public HTTPS receiver origins, returns bearer-free media, and rejects unsafe external URLs. The default receiver advertises no PlayHub ad integration. Device discovery, routing and native Cast/AirPlay/PiP behavior still require platform acceptance; see iOS media limitations.
The backend does not generate HLS/DASH segments, provide Widevine/FairPlay DRM, signal HDR or authorize offline downloads. Playback reports drm_required: false and download_allowed: false. A Downloads screen or client capability flag does not grant a download entitlement.
Sign-in, secure sessions and TV pairing
Registration and login
Use POST /auth/login with the configured login identifier, password and native device context. Registration follows bootstrap policy through availability, CAPTCHA and email/phone challenge endpoints where enabled; /auth/register may sign the user in immediately or require /auth/confirm-registration. Present server-provided CAPTCHA or two-factor requirements rather than substituting a browser session.
Mobile sign-in accepts ios and android. Successful authentication returns access_token, refresh_token, expires_in, refresh_expires_in, the device session and the current user. Store both credentials in Keychain or Keystore-backed encrypted storage. Never store tokens in AsyncStorage, URLs, analytics, crash metadata or logs.
Token refresh
Default access-token lifetime is 30 days; refresh credentials have a 180-day sliding lifetime. Refresh does not need a valid bearer token or browser cookie. It requires the current refresh credential and the same stable device ID and platform.
- Refresh before access expiry or once after a protected request returns
401 unauthenticated. - Allow one refresh request per installation at a time; queue other authenticated requests behind it.
- After success, atomically replace both stored credentials before releasing queued calls. The server preserves the session ID and rotates both credentials.
- Retry the original protected request once with the new token.
- Clear local credentials for an invalid, expired or reused refresh credential, or an unavailable account, and show the appropriate sign-in/account message.
A consumed refresh credential is retained only for replay detection. Reuse revokes the device session family, newest access token, refresh credentials and matching push registration. A platform/device mismatch is rejected without consuming the credential. An ambiguous lost refresh response must not trigger a blind retry with the old credential.
Sessions and account changes
Use GET /auth/me to restore the account while its token remains valid. Manage Devices uses GET /auth/sessions, account-scoped rename/revoke and current/other/all-device logout. The default active-session limit is ten, subject to server policy. Password resets and session revocation invalidate matching credentials; suspended/banned accounts cannot continue refreshing.
Mobile token abilities include account and creator mutation, uploads and Live publishing where the account is authorized. TV tokens omit those abilities. Clear account-bound queries, private caches and session state on sign-out or account changes.
Social login
Google, Facebook and Apple buttons follow the effective website provider flags on sign-in and registration. Use the system authentication browser with an exact allowlisted callback URI and PKCE S256. Generate a 43–128-character verifier, send its SHA-256 base64url challenge to /auth/social/{provider}/redirect, then exchange the single-use returned handoff code plus the original verifier at /auth/social/exchange. Discard both after completion.
The default documented callback is playhub://auth/callback; configure your actual scheme or approved claimed HTTPS links consistently in both the app and server allowlist. Provider credentials and enabled web OAuth configuration are still required.
Connect a TV
A television starts /auth/tv/device-authorizations and displays its user code, expiry and verification/QR link. Keep the separate device code secret. The signed-in website or mobile Connect TV screen previews the waiting TV and approves only after explicit confirmation. Poll the token endpoint no faster than the returned interval; honor authorization_pending, slow_down, Retry-After, denial and expiry.
Codes expire after ten minutes by default, bounded by policy to 2–30 minutes, and approval can be consumed only once. Connect TV approval in the phone app does not itself establish that a packaged television client has shipped.
API integration reference
All paths in this application guide are relative to your installed /api/v1 base. The versionless website API is not the native contract. The provided OpenAPI 3.1 contract has 191 paths, 230 HTTP operations and 232 component schemas. Its info.version: 1.0.0 describes the API document, independently of the installed application's version.
Open the full endpoint and contract reference for operation parameters, request bodies, response schemas, security and downloadable OpenAPI.
Client headers
| Header | Value |
|---|---|
Accept | application/json |
Authorization | Bearer <access_token> for protected API calls; optional on public discovery; omit for refresh and signed media URLs. |
X-PlayHub-Client | ios, android, android-tv, tvos, tizen or webos. |
X-PlayHub-App-Version, X-PlayHub-OS-Version | The actual installed app and OS/runtime versions. |
X-PlayHub-Device-Id | A stable random installation identifier, 8–128 safe characters; never an advertising ID. |
X-PlayHub-Device-Model | A recognizable device model/name. |
X-PlayHub-Locale, X-PlayHub-Timezone | The selected locale and an IANA time zone. |
X-PlayHub-Capabilities | At most 4,096 bytes of truthful JSON codec/container/resolution/subtitle/DRM/HDR and client-feature support. |
X-Request-ID | A UUID per logical request; retain it only for transport retries of that request. |
The API replies with X-Request-ID, X-PlayHub-API-Version: 1 and X-Content-Type-Options: nosniff. Canonical client headers take precedence over equivalent device/platform values in authentication bodies.
Responses, pagination and retries
{
"data": { "message": "Request completed." },
"meta": { "request_id": "a UUID for this request" }
}
{
"error": {
"code": "validation_failed",
"message": "The submitted data is invalid.",
"status": 422,
"request_id": "a UUID for this request",
"validation": { "email": ["Enter a valid email address."] }
}
}Every non-204 JSON success uses the data/meta envelope. Field validation belongs to error.validation; branch on error.code and retain request_id for support. Empty plugin and translation dictionaries remain JSON objects, while list results remain arrays.
Length-aware lists return meta.pagination with page, per-page, total, last-page and has-more values. Cursor lists return opaque next/previous cursors, per-page and has-more values. Links, when provided, live under meta.links.next and meta.links.previous. Keep filters and sorting stable between pages; replace the list for a fresh search and append only after a successful next-page request.
| Status | Client behavior |
|---|---|
| 401 | Run the single-refresh decision or ask the user to sign in. |
| 403 / 404 | Respect denied or unavailable content. A hidden resource may deliberately return 404. |
| 406 | Explain incompatible playback capabilities and use an available supported source. |
| 409 / 422 | Handle a state conflict or show correctable field errors; avoid automatic write loops. |
| 429 | Wait for Retry-After, then use bounded retry with backoff and jitter. |
| 503 | Show an unavailable-service state and use bounded retry. |
The common outer limit is 240 requests per minute per authenticated user or source IP; sensitive operations have tighter limits. Login/social exchange is 8/minute and 40/hour, refresh is 15/minute and 120/hour, progress is 30/minute and upload session/chunk calls are 120/minute. Read the operation-specific policy and returned rate-limit headers.
Likes, Watch Later, subscriptions, playlist membership and progress use retry-safe set/update semantics. Guard record-creating comments, reports, live messages, votes, upload completion and refresh against duplicate or ambiguous submissions. Some newer financial/live operations require their documented immutable idempotency keys.
Upload, import and processing
Native uploads require a mobile token with uploads:write plus actual account publishing and storage eligibility. Refresh GET /uploads/capabilities before beginning; the returned limits, MIME types, chunk sizes, moderation policy, renditions and storage state are authoritative.
- Create
POST /uploads/sessionswith a safe filename, exact file size, MIME type, selected chunk size andtotal_chunks = ceil(file_size / chunk_size). - Send zero-based multipart chunks in the
chunkfield toPOST /uploads/sessions/{uploadSession}/chunks. A retry at the same index replaces or confirms that chunk. - After interruption, read
GET /uploads/sessions/{uploadSession}and reconcile the server's received chunks before resuming. - Complete the upload with metadata and optional supported thumbnail/captions after every chunk is present.
- Show the returned processing state while background jobs probe/transcode the video. Cancel abandoned sessions through their DELETE endpoint.
| Capability | Documented baseline |
|---|---|
| Input video | MP4, MOV/M4V, WebM and MKV, subject to the current server capability response. |
| Chunk sizes | Defaults: 1 MiB minimum, 8 MiB maximum, up to 20,000 chunks. |
| File size | Configurable; the source controller baseline is 50 GiB. This is not an unconditional account allowance or substitute for returned limits/quota. |
| Caption uploads | SRT, VTT and TXT accepted by the upload contract. Native sidecar playback uses supported VTT/SRT; TXT is not advertised as a native subtitle format. |
| Explicit Short upload | Portrait, width-to-height ratio 0.45–0.8, maximum 60 seconds. |
| Transport | Resumable application-mediated multipart chunks. direct_to_cloud: false; S3 storage does not make uploads direct S3 multipart transfers. |
| Processing | Asynchronous queue/transcoder work requiring FFmpeg/FFprobe and working storage. |
Shorts classification and provider import
Ordinary local uploads measured at 1–60 seconds are classified as Shorts, including forms that send the default content_type: video and older local records with stale standard-video flags. Processing checks duration again. Shorts disable video ads and chapters. Sale-enabled records explicitly classified as standard videos keep that classification to preserve purchase access; provider imports keep their provider classification and live replays remain replays. Navigate using the returned content type.
Provider imports use POST /creator/imports and the providers advertised by /creator/options. Imported items begin private and remain subject to the existing provider, visibility and publishing validation. Provider imports do not authorize hidden-stream extraction or guarantee external media availability.
Notifications and push registration
In-app notifications
The server-backed in-app inbox provides paginated notifications, authoritative unread counts, read/read-all, deletion and preferences. Comment/reply, mention and new-subscriber notifications honor the saved preferences; account and creator status notices remain available. Saved newsletter/live-reminder preferences and subscription-upload preferences do not establish producers for those notifications.
Route notification actions by their constrained type and identifiers. Reauthorize the destination through its API before displaying it. Video and community comment-context endpoints return the comment ID and root-to-parent ancestor IDs so the app can load and expand the correct reply chain; unavailable or broken chains return 404.
Device registration and delivery status
The API can store encrypted FCM registrations for Android production and APNs registrations for iOS sandbox/production. Registration requires the current native session's same installation ID and platform. The server returns metadata without exposing the raw provider token, and a replacement installation token retires older registrations, including a previous account's registration on a shared device.
The current shared backend includes FCM and APNs senders, a durable delivery outbox, queue dispatch, bounded retries, recovery, and registration/preference checks. This supersedes the older API/readiness notes that described sending as absent.
Delivery defaults to disabled. Bootstrap enables features.push_delivery only when the relevant platform credentials and required tables are ready; features.push_registration describes the separate registration lifecycle. Actual device delivery remains unverified in the supplied records. Keep permission prompts and user-facing availability aligned with the real returned capability.
Configure and operate delivery
- Configure the intended FCM or APNs credentials on the backend and apply the required registration/outbox migrations.
- Review the backend push configuration, enable only the intended platform and confirm its bootstrap delivery capability.
- Supervise a worker for the configured queue, which defaults to
push. The ordinaryvideos,defaultworker alone does not consume that queue. - Verify queue dispatch, bounded retry and recovery behavior, then test actual delivery, preferences and revocation on a correctly signed device build before declaring the channel ready.
When delivery is configured and enabled, register only after OS permission and provider registration, refresh on provider-token rotation, and select the actual signed APNs environment. Revoke on logout; server session revocation and refresh replay also revoke matching registrations. If logout happens offline, suppress local notification presentation immediately and retry remote cleanup after reconnection. Delivery must continue to honor current registration, native-session and saved preference state.
Broadcast, watch, interact, and replay
The React Native application uses PlayHub's existing Live authorization, stream records, chat, moderation, polls, wallet ledger, and recording pipeline. Active media uses LiveKit and native WebRTC. Completed replays use the existing PlayHubPlayer with react-native-video v7.
Current Android acceptance: 9 October 2026
Physical Android connected acceptance and Web-to-mobile Live parity passed on a Samsung SM-G998B running Android 15 against the local acceptance installation. The checks covered Android host to Web viewer, Web host to Android viewer, sustained video and human audio checks, chat, test-wallet gifts/tips, guests, moderation, polls, scheduling, network restoration, recording, and native replay. Older 3–4 October blocked results are historical.
This milestone used a development Android build and local API. Public DNS/TLS, production signing, distribution, broader device testing, and iOS signing and physical acceptance have their own requirements. TURN UDP media passed; TURN TCP/TLS were unconfigured, and optional RTMP/OBS was not rerun in the final camera-host pass.
Discovery and viewer controls
- Live, Upcoming, and Replay: browse authorized streams and ready recordings, with search, categories, following, sort, and date filters. Counts, topics, popular creators, and server time come from the backend.
- Featured carousel: up to three Live, Upcoming, then Replay items, preserving API order within each status. Autoplay advances every 6.5 seconds and pauses during interaction, reduced motion, background, hidden screens, or navigation away from Discover.
- Silent previews: video-only subscriptions use exclusive preview ownership. They do not capture media, play audio, create guest requests, or increase the watching count.
- Native stage: receive host and guest tracks, use grid/focus/split/spotlight layouts, mute/volume/output controls, fullscreen, connection state, and reconnect feedback. Layout changes retain the room owner.
- Identity and counts: see title, tags, thumbnail, creator, verification, duration, and current audience. Publishing hosts/guests are excluded from ordinary watching counts; ordinary and anonymous viewers count.
- Share and subscribe: share the canonical
/live/{slug}URL and reuse the existing creator channel subscription workflow. Share links never contain connection grants or stream keys. - Access: everyone, signed-in, subscriber, invited, and private rules are checked server-side for viewers, guests, and previews. Global availability, account eligibility, stream settings, and actual service readiness gate controls.
Configure and start a phone broadcast
- Open Creator Studio / Go Live. Set title, description, category, tags, thumbnail, visibility, audience, and invited usernames where supported. Configure appearance, accent, layout, engagement, and recording options.
- Choose phone camera hosting. Grant camera and microphone permission when requested. Previewing does not activate the stream; denied permission has contextual recovery/settings guidance.
- Select available quality, FPS, and bitrate settings. Camera switching and camera/microphone controls work before and during publishing. Changing source, quality, or FPS releases the old preview and requires a new successful preflight.
- Run Test connection and resolve each displayed latency, upload, camera, or permission failure. Use Retry connection test after correcting the issue.
- Start once the matching saved preflight is ready. The app starts the stream, obtains its owner grant, connects and publishes, then activates only after actual source publication.
- Manage chat, activity, participants, guests, moderation, polls, recording state, and read-only SDK diagnostics from the host screen.
- Use End broadcast and its confirmation to stop the stream, remove publications/guests, release the owned camera/microphone/room, and transition viewers to the ended or replay state.
A scheduled time is entered locally and stored as ISO UTC. Upcoming displays the appropriate timezone. Starting a due saved stream preserves its original scheduled timestamp. Scheduling does not automatically turn on a phone or publish a camera. New or changed schedule values still receive normal validation.
A phone camera broadcast ends when the host application backgrounds; indefinite background hosting is unsupported. Viewers close their media room in background and rejoin once on return. Android host screen sharing uses OS-consented projection. The iOS ReplayKit broadcast extension remains separate implementation work; see iOS limitations.
Connection testing and quality targets
Web and native use the same backend gate. The test measures one authenticated 1 KiB multipart HTTP probe and one configured upload sample. Camera acquisition, draft saving, and payload preparation are outside the HTTP timing boundary. The result is application/server round-trip and finite-sample throughput, rather than an isolated network-interface or WebRTC packet benchmark.
| Item | Documented behavior |
|---|---|
| Latest accepted local maximum latency | 2,000 ms, owner-configured on 4 October. The earlier 300 ms test results are historical; use the actual administrator configuration for your installation. |
| Upload sample | 512 KiB in the accepted configuration; the client honors the backend-supported 64–2,048 KiB range. |
| Accepted camera-host profile | 720p / 1280 × 720, 30 FPS target, 3,000 Kbps video and 128 Kbps audio. |
| Required upload | (video Kbps + audio Kbps) / 1000 × 1.25; the accepted profile requires 3.91 Mbps. |
| Quality defaults | 480p: 1,500; 720p: 3,000; 1080p: 6,000; 1440p: 12,000; 2160p: 24,000 Kbps video. Explicit selection resets its configured bitrate. |
| Retry policy | Explicit Test/Retry; no automatic quality fallback or hidden warmup. Failed preflight does not create an active room. |
| Native timeout | The 30-second request timeout supports navigation cancellation; it is separate from the allowed connection-test latency. |
| FPS interpretation | Requested/reported and encoded FPS are targets/metadata. Physical capture often delivered approximately 24–25 FPS in the accepted lighting/thermal conditions; locked delivered 30 FPS is not certified. |
Chat, emoji reactions, and polls
Chat provides bounded history, avatars, role/verified badges, timestamps, emoji input, held/pinned messages, and authorized deletion. The native feed uses bounded 3.5-second foreground polling, matching the actual web transport. Messages sharing a timestamp sort by ID for stable ordering. Quick reactions are ordinary emoji chat messages.
Server-enforced chat settings include slow mode, followers-only, unique-message, and blocked-term rules. Private blocked terms/restrictions remain authorized. Completed contribution history stays independently visible when chat is disabled.
Hosts can create, edit, schedule, launch, close, and delete polls. Viewers vote, inspect results, and view paginated voters when permitted. Duplicate and expired votes are rejected. Scheduled activation/expiry requires the Laravel scheduler and a currently live stream.
Guests, cohosts, and moderation
- Viewers request audio or audio-and-video access, cancel requests, and leave the stage. Duplicate pending requests are prevented; the host accepts or declines.
- An accepted guest explicitly chooses Join stage before publishing camera/microphone. Guest media modes are
audioandaudio_video; guest screen sharing is absent. - Owners/moderators can invite eligible guests/cohosts through the existing role flow. There is no separate invented invitation-acceptance endpoint or fixed guest-seat quota; participant ceilings come from server settings.
- Owners and assigned moderators can delete authorized messages, restrict/restore chat, mute/remove current participant tracks, manage all microphones/cameras, and ban/restore stream access within assigned privileges.
- Kick disconnects the participant and permits a fresh ordinary viewer grant. Ban prevents re-entry until restored. Removing a guest stops publishing and supplies a distinct permitted viewer connection.
- Current-policy signaling admission invalidates cached grants after guest removal, kick, ban, and End. Connected removal and new-token rejection are separate parts of enforcement.
Gifts, tips, Super Chat, wallet, and earnings
Enabled gift and Super Sticker catalogues supply IDs, prices in cents, images, currency, and categories/pages. Tips and Super Chat enforce administrator/creator limits and messages. Quick tip presets come from supported server settings. The server resolves recipient, price, fee, and net earnings; the client cannot set a trusted price or credit its balance.
Wallet balance, transaction history, and creator earnings reuse the existing ledger. Native wallet purchase remains disabled; funding/management uses the existing protected web handoff. Receipts distinguish gross, fees, and actual creator net amounts. Goals use a monetary title, target, and net total.
Pending-action guards prevent rapid duplicate submissions. A sender-bound UUID idempotency key retains immutable stream/product/amount/message intent. Financial requests do not automatically replay after authentication failure. If the outcome is ambiguous, explicitly retry the same intent to recover its receipt without another debit. A changed sender, stream, or intent cannot reuse that receipt; exact completed recovery remains valid after repricing, disable, or End.
Pinned messages, contribution/subscription/goal alerts, and sound use actual stream settings. Alert queues are bounded and deduplicated: up to 8 pending alerts and 200 tracked IDs, with old receipts seeded without replay. Enabled Live ads use the existing inventory, impression, and completion security while preserving RTC volume; VOD IMA remains separate.
The physical financial check used isolated test credit and reconciled three gifts plus one tip with viewer balance and creator net earnings. Actual card charges and payouts were not tested. Implemented notification producers include creator_tip, live_moderator, and live_replay_ready; external email/push delivery depends on configured services.
RTMP and external encoders
Enable Ingress, select the external-encoder source, then prepare/reveal/copy the owner-only ingest URL and key. Publish from OBS or another encoder and wait for real ingress publishing state before Start. Native RTMP monitoring does not use camera activation. Leaving the monitor preserves the running encoder; explicit End stops the stream. Credentials clear on blur, background, or unmount. The final physical camera-host pass did not retest this optional workflow.
Recording, retention, and replay
Recording needs Egress, a reachable trusted recording template, writable output, FFmpeg/ffprobe, queue workers, and the scheduler. It begins after real publication. End queues finalization of a stable MP4, then existing video processing produces the ready replay. Privacy, approval, access, and retention continue to govern playback/discovery.
Replay uses the existing PlayHubPlayer and normal video route, with a bounded read-only archive of messages, contributions, moments, and manual timestamp/checkpoint seeking. It does not automatically synchronize rolling chat with the current playhead; checkpoints are separate from authored video chapters. Denied/expired/processing/unrecorded replays stay out of directory counts and topics, and denied/disabled cached chat is hidden.
Physical acceptance produced and played a real H.264/AAC 1280 × 720 replay of approximately 32 minutes 25 seconds. Playback, pause, timeline seek, fullscreen, portrait return, and close passed. Active replay used one player and released it on close. Test media was removed after validation.
Feature and performance boundaries
Active RTC Picture in Picture and genuine active Live DVR seeking are not exposed. Completed replay retains ordinary VOD behavior. Peak/unique viewers and average/total watch time are not persisted Live analytics; current audience must not be called peak audience. Clip creation, actual reminder subscriptions, coin/combo/quantity gifts, gift leaderboards, timed timeout actions, chat reply/mention entities, pinned products/links, mature-age controls, and guest screen media are absent from the current web inventory.
The accepted network outage recovered after owner-restored connectivity; it does not establish a 12-second recovery guarantee. Debug hot reload during active capture can leave an old idle helper after its JavaScript runtime is destroyed; end/leave before reload and restart the development app if needed. Normal End/leave/background cleanup passed separately. Debug multi-session memory did not immediately return to baseline, and temperature reached 40.7°C. These measurements do not certify release-build memory efficiency, leak freedom, sustained CPU use, every audio route, or every Android GPU.
Install and configure the Live backend
The mobile app uses the same streaming backend as the website. Follow the website LiveKit guide and configure Live through the authenticated Admin settings. The mobile bundle receives public API/signaling configuration and short-lived authorized grants; LiveKit keys, Redis passwords, and recording credentials stay on the server.
Prerequisites and pinned services
| Component | Purpose | Supplied version / requirement |
|---|---|---|
| Existing PlayHub Laravel/PHP, database, HTTPS | Authorization, API, lifecycle, chat, contribution ledger, and jobs | Working PlayHub installation and production trusted DNS/TLS |
| LiveKit core | Live rooms and camera/microphone/screen media | livekit/livekit-server:v1.13.3 |
| Authenticated Redis | Core, Egress, and Ingress coordination | Existing reachable private Redis; no additional container required when reachable |
| Media networking | Real RTC and optional TURN connectivity | Reachable published TCP/UDP ports and a correct advertised address |
| Laravel queue and scheduler | Thumbnails, finalization, processing, polls, cleanup, and retention | Worker handles videos,default; scheduling every minute |
| Egress + output storage | Thumbnails, recordings, and replay source artifacts | livekit/egress:v1.13.0; optional for unrecorded camera hosting |
| Ingress | External RTMP/OBS publishing | livekit/ingress:v1.5.0; optional for phone-camera hosting |
| FFmpeg / ffprobe | Replay media validation and processing | Configured binaries accessible to the actual PHP worker |
| Node and Docker CLI | Read-only Live health tooling | Node 22+ and access to local Docker CLI |
Generate the runtime and start services
Save actual engine/Redis/ports/recording settings in Admin and regenerate livekit/runtime/docker-compose.yml. The committed livekit/docker-compose.yml provides the definition. Runtime files are private and excluded from source control. Containers use the livekit bridge network with explicit port publishing; Docker Desktop host networking is not part of this workflow.
On Linux, use the supplied installer from the website guide, adapting the project path and PHP-FPM account:
sudo /var/www/playhub/livekit/install.sh www-dataThe installer/systemd manager is a Linux workflow. Windows uses the generated Compose project directly. From the PlayHub project root, the generated runtime can be validated and core started on either supported Docker host:
docker compose -f livekit/runtime/docker-compose.yml config --quiet
docker compose -f livekit/runtime/docker-compose.yml up -d livekitStart only configured optional services that your workflow needs, particularly on a constrained development machine:
docker compose -f livekit/runtime/docker-compose.yml up -d egress
docker compose -f livekit/runtime/docker-compose.yml up -d ingressConfirm containers remain running with stable restart counts, readable private mounts, writable output, and reachable media transports. Ingress/Egress use ws://livekit:<signal_port> within the bridge. Private host Redis can use host.docker.internal with host-gateway; listener/ACL/firewall must allow that authenticated connection. A host-loopback-only Redis listener may be unreachable from Docker.
Public configuration and ports
Set the mobile EXPO_PUBLIC_API_BASE_URL to your public trusted HTTPS API ending in /api/v1. Set the LiveKit public URL in Admin to the matching trusted WSS gateway, such as wss://video.example.com/livekit. The local acceptance domain and debug CA are development-only; release uses system trust and cleartext remains disabled.
| Traffic | Configuration | Exposure |
|---|---|---|
| HTTPS/WSS | Existing nginx HTTPS listener | Normally 443/TCP; trusted public endpoint |
| Core HTTP/API/WebSocket | signal_port, example 7880/TCP | Host loopback only; proxy through the admission gateway |
| RTC TCP | rtc_tcp_port, example 7881/TCP | Publish/allow intended participant connections |
| RTC UDP | rtc_udp_port_start–rtc_udp_port_end | Publish actual range; repository default 50000–60000 |
| Optional UDP mux | Advanced rtc.udp_port | When selected, match effective core settings and Compose publishing |
| TURN UDP listener | turn_udp_port, example 3478/UDP | Publish if enabled; independent of RTC TCP |
| TURN relay UDP | Advanced turn.relay_range_start–relay_range_end | Publish the whole effective relay range separately from listener/RTC ports |
| TURN TLS | turn_tls_port, domain/certificate settings | Configured TCP listener if enabled; unconfigured in final local acceptance |
| RTMP | rtmp_port, example 1936/TCP | Publish when external encoders are used |
| Egress health | 7981/TCP backend contract | Host loopback only |
| Redis | redis_host / redis_port, example 6379/TCP | Private authenticated service access |
Inspect generated effective settings rather than copying development port ranges. Basic settings and advanced JSON are merged; explicit UDP mux/extra listeners and relay sockets must have matching published mappings. Keep rtc.node_ip / use_external_ip reachable by intended participants. Ordinary nginx HTTP proxying does not forward RTC UDP, and opening only the TURN listener does not publish relay allocation sockets.
Redis 5 supports password-only AUTH: the generator omits the canonical default username while preserving the password/database. A custom username remains configured and requires Redis with named ACL support. Authentication/protected mode must remain enabled.
Guard nginx signaling and protect credentials
Adapt livekit/nginx-app-test-location.conf into the intended nginx virtual host, using that installation's actual upstream, PHP path, and document root. It provides the existing LiveKit routes, HTTP/1.1 Upgrade/Connection and forwarded headers. Validate nginx before reload and avoid competing locations.
Verify nginx includes http_auth_request_module. The private /__playhub_livekit_admission FastCGI subrequest calls Laravel /api/livekit/admission for join/validate variants under the LiveKit prefix. Admission verifies signed JWTs, current stream/account/audience/stage policy, and server-held identity versions. Query and Bearer credentials must match; upstream receives the exact admitted token. Keep direct core signaling host-private.
Removing a participant in self-hosted LiveKit alone does not cryptographically revoke an existing JWT. Policy/version admission blocks cached joins after kick, ban, guest demotion, and End while server APIs remove/update currently connected participants. Initial viewer/guest grants are 90 seconds and host grants 300 seconds, but refreshed credentials mean initial expiry alone is insufficient. Final physical acceptance rejected still-unexpired revoked grants.
Suppress signaling and recording-template access/error URL logging; use the example's Windows NUL sink or Unix /dev/null as appropriate. Runtime configuration, API keys, Redis/TURN credentials, and recording tokens must not enter public pages, mobile variables, support screenshots, or raw diagnostic output.
Queue and scheduler: Linux and Windows
Supervise a project worker handling videos,default. On Windows development, the supplied helpers verify the executable, absolute project Artisan path, and command before accepting a stored process ID:
powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-queue-worker.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-scheduler.ps1Both accept -PhpBinary and -Foreground, and write process IDs/logs under storage/app and storage/logs. These are development processes, not automatic startup services. Production needs an appropriate project-specific supervisor/service or Windows Task Scheduler task. Do not kill a reused PID or start a duplicate unverified worker.
Run php <absolute-project-artisan> schedule:run every minute, or supervise one schedule:work process. The Linux cron convention is:
* * * * * cd /absolute/playhub/project && /absolute/php artisan schedule:run >> /dev/null 2>&1Keep queue retry intervals greater than the longest job timeout. The documented local worker uses 21,600 seconds with DB_QUEUE_RETRY_AFTER=21660. The Redis connection repository fallback is only 90 seconds unless overridden. Confirm the active connection's value to avoid concurrent duplicate reservations of long media jobs.
| Work | Queue / schedule |
|---|---|
| Live thumbnail | GenerateLiveStreamThumbnail, videos, after activation |
| Recording finalization | FinalizeLiveStreamReplay on videos after End; recovery through finalize-live-stream-replays each minute |
| Replay processing/notification | Existing ProcessVideoUpload on videos |
| Poll activation/expiry | activate-scheduled-live-polls each minute |
| Missing publishers/pending cleanup | reconcile-live-stream-publishers each minute with grace/outage policy |
| Replay retention deletion | prune-expired-live-replays hourly |
A running process or registered task is not completed work. Verify job completion, actual schedule run history, poll/lifecycle effects, and replay availability. Scheduled Live appears in Upcoming but does not automatically start a creator's phone. A running external encoder survives leaving its monitor.
Recording storage and real replay verification
Egress uses Room Composite recording, /livekit-recording-template, and mounted uploads/live-streams output. It must reach the template/signaling origin with trusted TLS, connect to configured Redis, and have sufficient CPU/memory/disk. Give the original Egress account write access and the actual queue worker read access with deliberate ownership/ACLs. Avoid recursive world-write permissions.
The recording template sends Cache-Control: private, no-store and Referrer-Policy: no-referrer; suppress token-bearing URL logs. The ignored local development Egress CA overlay is acceptance tooling, not a required production image. Production should use trusted public DNS/TLS.
- Confirm real source publication and recording start.
- End the stream and confirm a stable finalized MP4 exists.
- Allow finalization/video processing to produce a ready replay with valid duration/media.
- Play, seek, enter/exit fullscreen, and close on the intended device.
- Verify access/retention policy and artifact handling using owned test data.
Read-only health checks
node tools/live-health.cjs --jsonFor the supplied local debug CA only, retain normal certificate validation and provide its certificate:
node tools/live-health.cjs --ca-file react-native-app/assets/certificates/playhub-local-acceptance-ca.cer --jsonSupported options include --ca-file (PEM/DER X.509), --docker-binary, --root, and --admin-base. Optional administrator diagnostics use an ephemeral process environment variable PLAYHUB_LIVE_HEALTH_ADMIN_TOKEN to call existing admin-only /api/admin/livekit-status and /api/admin/livekit-test. Do not put the value in command arguments or committed files, and clear it afterward.
The verifier reads generated settings and reports PASS, FAIL, WARN, NOT_CONFIGURED, or UNVERIFIED; required operational failure exits 1. It never starts/stops services, runs jobs, or prints configuration/credential bodies. A STUN reply proves a UDP listener, not authenticated TURN relay media; a healthy process/listener does not prove recording, queue completion, or device acceptance. Prove relay-only media separately for UDP/TCP/TLS.
Live fixes and troubleshooting
These are implementation and validation milestones from the supplied documentation, not invented semantic app versions. The current Android connected result is PASS; earlier failed preflight results remain historical.
Schedules, chat, End state, and host-loss recovery
- Due saved schedules: an unchanged saved date was incorrectly treated as a new past date. Starting now preserves that schedule and omits unchanged
scheduled_atfrom metadata saves; changed/new dates retain validation. - Stable chat ordering: messages sharing a timestamp now use an ID tie-breaker in both shared feeds before reversing the newest-message window.
- Clean ended summary: a stale control-room query could show “not active” after a successful End. The summary suppresses stale active-session query errors while retaining actual action/cleanup errors.
- Abnormal host loss: when LiveKit had closed an empty room, participant listing could return 503 and leave a ghost live stream. A healthy uncached authenticated room listing can confirm absence for this operation. Outages, malformed responses, and existing rooms do not count as absence; grace and locked rechecks remain.
- Physical connected coverage: both hosting directions, owner-heard audio, 20 camera switches, 10 mic cycles, alternating chat/emoji, test-wallet receipts, guest lifecycle, moderation, polls, viewer count, scheduled start, network restoration, UDP relay, native End, recording, and replay seek/fullscreen/close passed.
Supplied validation evidence for this milestone reports 1,146 mobile tests across 130 files, 428 Laravel tests with 9,211 assertions, 34 operational tests, passing application/contract TypeScript, touched-file Pint, and Expo Doctor 21/21. ESLint reported 0 errors and 3 existing warnings. These are evidence from the supplied package, not new test execution performed by this documentation page.
Configured latency limit
The owner raised the maximum Live connection-test HTTP round trip from 300 to 2,000 ms through existing administrator settings, preserving other limits. Earlier physical tests at 300 ms failed latency despite passing upload. The later accepted run used 2,000 ms; customers should inspect their own configured gate rather than copy historical failures.
Preflight, capture profiles, and native ownership
- Configured upload samples: removed the unintended native 512 KiB cap so the 64–2,048 KiB backend-supported setting is honored.
- Quality selection and feedback: explicit selection resets bitrate like web; separate measured failure reasons and Retry connection test clarify the gate without automatic fallback.
- Supported camera profiles: bounded larger-format retry handles a camera returning dimensions below the selected profile minimum. Failed acquisition releases before retry; minimum/FPS/network rules are preserved.
- Native track ownership: obsolete owned tracks release after sender replacement/unpublish/disconnect, preserving shared microphones and remote tracks. Failed release remains retryable. Track registration before first publication blocks cancelled acquisitions from publishing and disconnects uncertain outcomes before disposal.
- Coherent SDK upgrade: LiveKit React Native 2.12.0 → 3.0.0, WebRTC bridge 144.1.2 → 144.2.0, Expo LiveKit plugin 1.0.2 → 1.0.3, and native WebRTC 144.7559.05 → 144.7559.15 include an upstream ordinary recorder shutdown fix. JavaScript LiveKit stays pinned at 2.22.3; the audited Expo 57.0.26 / React Native 0.86.3 application stack remained unchanged.
- Guarded postinstall corrections: handle failed restart/acquisition cleanup, redundant screen acquisition streams, sender identity, rejected/missing native track acknowledgements, and verified sender detachment before SDK ownership clears. The guarded patch must be reviewed when changing pinned packages.
- Local environment corrections: timestamp-validated OPcache and a corrected development emulator host entry reduced diagnosed local server delays. These are environment changes, not a mobile production DNS/authentication change.
Feature parity and server reliability
- Integrated native discovery/carousel/silent previews, viewer stages, camera hosting/settings, activity/diagnostics, chat, guests, moderation, polls, financial interactions, engagement/ads, protected RTMP controls, recording, and replay archive with shared backend behavior.
- Fixed directory following filters serializing
falsewhere Laravel expects0/1, preventing 422 responses. - Stopped cached RTC after terminal access denial, hidden cached replay chat after denial/disable, and cancelled pending native capture consent on background.
- Corrected actual browser Live media rendering, zero-valued participant text handling, and replay panel navigation-context crashes by using its owning screen's active state.
- Reset ended web draft/preflight state and rejected stale control-room responses after End.
- Moved thumbnail work from blocking Windows HTTP after-response execution to the normal
videosqueue after commit. - Required core for camera hosting while independently gating optional ingress/egress; missing/stale Docker status preserves existing readiness probes.
- Added current-policy nginx admission and versioned grant enforcement for removed, kicked, banned, demoted, or ended participants.
- Fixed Windows bind-mounted key permissions with a private 0600 container copy, Redis 5 default-username AUTH compatibility, explicit bridge/TURN relay publishing, project worker/scheduler identity checks, and sanitized health/status reporting.
- Protected runtime and recording-template routes and grant-bearing URL logs; isolated local Egress CA support preserves trusted TLS and production trust boundaries.
Troubleshooting
| Symptom | Check and supported correction |
|---|---|
| WSS 502 | Trace configured nginx route, published signal port, and container listener. Keep public DNS/certificate/Admin URL consistent. |
| WSS 403 without a grant | Expected admission protection. Test with a current authorized PlayHub grant; preserve the gateway. |
| Signaling connects but video/audio does not | Check source tracks, advertised rtc.node_ip/use_external_ip, actual RTC firewall/port mappings, TURN listener plus relay range, and selected ICE transport. |
| Windows key-file permission failure | Docker bind-mounted files may appear 0777. The generated entrypoint copies the read-only key to private container tmpfs with mode 0600. Restrict host source ACLs and preserve LiveKit permission checks. |
| Windows Admin save fails on a bind lock | Stop only this project's Live containers, save intended Admin configuration, and recreate needed services. Plan the interruption if active Lives exist. |
| Redis 5 AUTH errors | Use password-only authentication without canonical default username. Preserve password/database; custom usernames require named-ACL support. |
| Upload passes but Test connection fails | Read individual latency/camera/permission results and actual Admin maximum. Check server runtime/load and full native Test/Retry, separately from shell probes or raw Wi-Fi speed. |
| Camera size or image fails | Inspect supported modes, lens obstruction/lighting, and selected profile. Bounded format retry preserves profile minima; rerun saved preflight after changes. |
| Stream remains live after host loss | Verify scheduler reconciliation and authoritative engine state. Healthy room absence can trigger cleanup; service failure/malformed data must not be treated as absence. |
| Replay remains processing | Check template DNS/trusted TLS, output permissions/free space, real finalized MP4, FFmpeg/ffprobe, videos,default worker, job completion, and scheduler recovery. |
| Docker disk full/read-only or damaged cached image | Restore capacity and verify writable daemon/storage and affected image executables. Local recovery needs at least 10 GB headroom plus images/recordings; production depends on retention/concurrency. Preserve unrelated images/volumes/customer media. |
| Worker is unverified | Inspect service/helper with sufficient process-read access and absolute project Artisan command. An unreadable inventory does not justify a duplicate worker. |
| Old camera helper after development reload | End/leave before reload and restart the development app to clear a helper owned by a destroyed JS runtime. Normal lifecycle cleanup passed separately. |
For the documented Windows configuration bind-lock maintenance, run from the project root:
docker compose -f livekit/runtime/docker-compose.yml stop egress ingress livekit
# Save the intended configuration through authenticated PlayHub Admin settings.
docker compose -f livekit/runtime/docker-compose.yml up -d --force-recreate livekitRestart optional Egress/Ingress separately if required. Stopping core interrupts active streams. Do not weaken key checks, disable TLS/authentication, or broadly reset/prune Docker to conceal a service failure.
iOS installation, configuration and distribution
The supplied React Native application includes an iOS implementation targeting iOS 16.4 and later. Complete the shared application installation and configuration steps first, then configure the Apple identity, build profile and services below.
Prerequisites and native dependencies
- An installed and configured
react-native-app/project connected to a compatible PlayHub V1 API. - An Expo/EAS account linked to your approved project. Check the existing project link before creating another project.
- Apple Developer membership and authorized account access for signed device builds; an approved Apple bundle identifier, a real Apple Team ID, distribution signing and appropriate provisioning.
- A registered, accessible iPhone for internal ad hoc installation. Test iPad separately when distributing with tablet support.
- A public HTTPS API with a normally trusted certificate for cloud testing and store production. Local development requires working device DNS and operating-system trust for its development certificate.
- Real AirPlay/Cast receivers, APNs sender configuration and legitimate provider credentials or entitlements when accepting those features.
The supplied compatibility audit uses Expo 57.0.27, React Native 0.86.3, react-native-video 7.0.0-beta.11, Nitro 0.37.1, LiveKit React Native 3.0.0 and WebRTC 144.2.0. The local IMA/AirPlay pods target iOS 16.4 with Swift 5.9. Dailymotion iOS SDK 1.4.11 shares pinned Google IMA 3.33.0 and Google Cast 4.8.6.
Windows can run the shared checks and use EAS-hosted Apple infrastructure for native compilation. A JavaScript/Hermes export does not compile Swift or produce an IPA. A local Apple Simulator requires an Apple development environment; Windows host access to the API does not configure a Simulator or iPhone.
Apple identity and API settings
Set these values in the supplied configuration system. Environment overrides take effect when building the application; public API addresses and player IDs become part of public application configuration. Keep Apple authentication, certificates, provisioning material and service secrets in secure credential storage.
| Purpose | Setting or override | Configuration requirement |
|---|---|---|
| Local development API | connection.developmentApiBaseUrl; EXPO_PUBLIC_API_BASE_URL | The supplied local workflow uses https://app.test/api/v1. Your Apple device must resolve this host and trust its certificate. |
| Cloud Simulator API | deployment.iosSimulatorApiBaseUrl; EXPO_PUBLIC_API_BASE_URL | Explicit public, trusted HTTPS development/staging address ending in /api/v1. Cloud profiles reject .test, localhost, emulator aliases and raw IP endpoints. |
| Production Apple bundle identifier | native.ios.productionBundleIdentifier; PLAYHUB_IOS_BUNDLE_IDENTIFIER | Use your approved and registered Apple app identity. The Android application ID does not automatically approve an Apple identifier. |
| Apple Developer team | native.ios.appleTeamId; APPLE_TEAM_ID | Use your real Team ID and matching signing/provisioning access. |
| Dailymotion iOS player | providers.dailymotionIosPlayerId; EXPO_PUBLIC_DAILYMOTION_IOS_PLAYER_ID | Create/configure a dedicated public iOS Studio Player ID. The Android Player ID is separate. Player initialization does not require an API secret. |
| Cloud profile enforcement | PLAYHUB_IOS_CLOUD_SIMULATOR=1 | Set by the dedicated cloud profiles; enforces the separate cloud API requirements. |
The shipped development bundle identifier is com.playhub.mobile.dev. Use your actual resolved identifier for device registration and testing fixtures. Changes to native identity, app name, icons, splash screens, permissions or entitlements require a new native build; website bootstrap branding controls the runtime name separately.
EXPO_PUBLIC_API_BASE_URL=https://app.test/api/v1
The local endpoint is a development setting. Do not use it as a public store deployment or assume that a cloud Simulator can reach it. The separate cloud value does not replace your Android/local development API. The build gates retain normal TLS and hostname verification.
Select an iOS build profile
| Profile | Output and use | Connection and signing requirements |
|---|---|---|
ios-local-simulator | Simulator development client for a local Apple Simulator. | Metro plus working local DNS/TLS. The local app.test API is allowed. |
ios-simulator | Cloud Simulator development client. | Explicit public trusted HTTPS development/staging API and a reachable Metro/development connection. |
ios-e2e | Standalone Simulator application with bundled JavaScript; Release build configuration and development identity/policy. | Public cloud API and deterministic real fixtures. No Metro; preferred for hosted acceptance. |
ios-preview | Standalone signed internal physical-device build; developmentClient: false, simulator: false. | Local development API, Apple signing/provisioning and registered test devices. Device networking/trust must work. Internal device builds select production APNs. |
ios-production | Signed store-distribution IPA. | Approved public production API, Apple bundle identifier/team, EAS linkage and distribution signing. |
A Simulator .app archive cannot be installed as a physical-device or App Store IPA. The documented successful ios-local-simulator artifact is a development client requiring Metro; it is not the standalone ios-e2e artifact.
Validate and build
Run commands from react-native-app/. The examples use Windows PowerShell executables; use npm in shells where the .cmd suffix is unnecessary.
npm.cmd run check:ios
npm.cmd run release:local-api:check:ios
npm.cmd run e2e:ios:check
check:ios validates shared code and exports JavaScript/assets. The local API check verifies the iOS bootstrap contract at the configured endpoint from the current host. Neither command installs or runs the application on an Apple device.
npm.cmd run ios:cloud:api:check
npm.cmd run e2e:ios:preflight
npm.cmd run eas:workflow:ios:validate
npm.cmd run eas:ios:e2e:build
Configure the same public API in the current environment and the EAS development environment before running cloud checks. Prepare the real fixtures described below. Workflow service validation also depends on your EAS account entitlement. The cloud pre-install hook checks the real bootstrap over verified TLS before native compilation.
npm.cmd run eas:ios:simulator
npm.cmd run eas:ios:simulator:local
The first command selects the cloud development-client profile; the second selects the local-network Simulator profile. Both require Metro. Building the local profile does not make a private local API remotely reachable.
Signing, internal installation and production
Set your approved bundle identifier and Apple Team ID before configuring signing. Expo authentication and Apple authentication are separate. The supported credential-inspection command is:
eas credentials --platform ios
The configuration inspection repair allows exact Expo JSON configuration reads when production settings are incomplete. Actual prebuild, export, native introspection and build workers still require valid production configuration. Inspecting credentials does not create a signed artifact or waive those gates.
- Confirm your Apple membership, app registration, approved bundle identifier and Team ID.
- Arrange matching distribution certificates and provisioning through EAS/Apple. For
ios-preview, register the authorized test iPhone and use the prepared internal device profile. - Build the configured
ios-previewinternal profile, install its signed artifact on a registered device through the EAS internal-distribution installation link, and prove a cold launch with bundled JavaScript and no Metro. - For production, configure the approved public API and run the production commands below.
- Inspect the actual signed IPA, then complete physical-device and store acceptance. Signing and compilation alone do not complete release verification.
npm.cmd run config:production:check -- --platform ios
npm.cmd run release:api:check:ios
npm.cmd run eas:ios:production
The supplied production configuration was blocked by missing approved public API, Apple bundle identifier/team and signing access. No signed production artifact metadata exists. Version 1.0.0 and build 1 are documented Simulator/configuration values; inspect the intended remote build number and final signed artifact before distribution. Android version codes remain independent.
Permissions, networking and platform behavior
| Permission or capability | Implemented use | Configuration and acceptance |
|---|---|---|
| Camera / microphone | Live host/guest capture and publishing. | Purpose descriptions are configured; permission is requested before first capture. Verify grant, denial, return from Settings and capture cleanup on an iPhone. |
| Photo library | Selected videos/images for creator content, artwork, profile, community, comments and message attachments. | Review the purpose string: its supplied channel-publishing wording is narrower than all implemented uses. Verify limited/denied access and pickers. |
| Local network / Bonjour | Cast discovery and remote playback. | Discovery is delayed until the first Cast-button action. Verify permission denial, receiver discovery and handoff on a real network. |
| Face ID purpose string | The supplied SecureStore configuration includes a description, but source uses device-only Keychain storage without requireAuthentication. | No app Face ID authentication or biometric-data retrieval path was found. Review the misleading biometric-data wording before release; do not advertise Face ID login from this configuration. |
| Background audio / PiP / routes | Background audio policy and player ownership paths are implemented. | Verify actual background playback, interruptions, user pause, headphones/Bluetooth, PiP and AirPlay/Cast ownership on signed hardware. |
| iPad / orientation | Tablet support, portrait/landscape orientations and requireFullScreen: true. | Full-screen presentation supports orientation locking and disables iPad split-view multitasking. Physical iPad layout acceptance remains pending. |
| Push notifications | Native APNs registration and server delivery integration. | Match the signed APNs environment, Apple app capability and server key/topic. Internal signed device profiles select production APNs. |
| URL schemes / Universal Links | Development URL schemes are configured. | Associated domains are not configured/verified in the supplied source. Universal Links require your approved domain, entitlement and association file. |
Arbitrary network loads are disabled. Development configuration permits local networking and a scoped localhost exception for Metro; it does not add an arbitrary-load exception for app.test. A local device must independently resolve the API host and trust its CA. Inspect the final Release Info.plist and use trusted production TLS.
Push enrollment requires authenticated state, OS permission and the backend delivery capability. The supplied local bootstrap reports push_registration: true and push_delivery: false, so registration capability alone does not enable native enrollment. Refresh/token listeners recheck delivery capability, while Settings preserves revocation. No actual iPhone token registration or APNs delivery is verified.
iOS feature boundaries
- Native video: MP4/HLS playback and controls are implemented. iOS source selection excludes native DASH and chooses an available compatible MP4/HLS rendition. A DASH-only asset needs compatible server delivery.
- Dailymotion: the native iOS bridge uses the official SDK, fullscreen/ad presentation and
setMute; arbitrary volume is unsupported (supportsVolume: false). Configure its separate iOS Player ID and accept actual playback, ads and lifecycle. - Provider surfaces: YouTube, Vimeo and Twitch integrations preserve official provider interaction. Vimeo Direct requires legitimate server credentials/entitlement. Twitch clips lack the same interactive playback telemetry as the VOD test fixture.
- Live: camera/microphone host, guest and viewer flows, interactions and server recording/replay integration are implemented. Host screen sharing remains Android-only; no iOS ReplayKit broadcast extension is supplied. Recording requires configured server egress and the replay setting.
- Commerce and downloads: StoreKit purchases, DRM and authorized offline downloads are not implemented. Billing/management links use website payment flows; review the policy for enabled digital purchase flows before store distribution.
Privacy and publisher configuration
Prepare privacy answers from your actual API, storage, providers and advertising configuration. The app can transmit account/profile/contact fields, device/session metadata, media/messages/content, social and library interactions, viewing progress, searches, billing/withdrawal data, Live media/chat and conditional native push tokens. Live recording depends on configured egress and the selected replay setting.
Session credentials use device-only SecureStore; preferences and recent searches use AsyncStorage. Upload recovery retains account/API-scoped source copies and a metadata journal without serializing authentication credentials. Account deletion, session revocation, history clearing and content deletion are implemented, but deployed retention, backups, operational logs, financial records and third-party deletion practices require operator review.
No app-level ATT request, integrated UMP SDK or complete CMP flow was found in the supplied source. IMA can receive consent/ad-request configuration, and Dailymotion sets allowIDFA: false, but these do not prove an end-to-end consent flow or that every provider disables tracking. Review enabled ad suppliers, SDK purposes, regional consent and actual traffic. The app-owned analytics sink defaults to a no-op, which does not exclude backend statistics or provider advertising/analytics.
The supplied Dailymotion integration inventory records a publisher requirement to provide the relevant TCF2 CMP consent string before loading its player in GDPR countries. Configure and verify the required consent handoff before enabling that provider there; a complete CMP flow is not implemented in the documented application.
Confirm the public privacy-policy URL, account/data deletion practices, first-party collection, SDK declarations, encryption declaration and content disclosures. Inspect the actual signed archive and final Xcode privacy report. No App Store privacy answers or consent certification were submitted in the supplied evidence.
iOS testing, Windows workflow and TestFlight readiness
Record native compilation, JavaScript export, Simulator execution and physical-device acceptance separately. The supplied evidence dated 9 October 2026 confirms native Simulator compilation, while all ten defined Simulator cases and physical-device acceptance remain unexecuted.
Testing from Windows
Run the local checks and EAS build scripts from react-native-app/. Keep the local development endpoint for the local profiles and configure the separate public endpoint for hosted acceptance. An iPhone using the local endpoint must independently resolve app.test and trust the development CA; a successful Windows host check proves neither condition.
npm.cmd run eas:ios:availability
At the supplied evidence date, the tested account's interactive Simulator service was unavailable and hosted Maestro required a paid team plan. Check your own account availability and plan before scheduling hosted work. Workflow commands pin EAS CLI 24.12.1, which corrects earlier current-schema parsing and failure-exit behavior.
A development client needs reachable Metro. Use the standalone ios-e2e artifact for hosted acceptance without Metro. Appetize requires a compatible Simulator application and authorized account access; BrowserStack real iPhone testing requires a compatible signed device IPA and account access. Neither alternative service was executed in the supplied evidence.
Prepare real acceptance fixtures
Use tools/ios-e2e-fixtures.json and a disposable account that supports noninteractive password login. The account needs a channel, an existing published creator video and playlist. Prepare deterministic public Home/Search/Shorts resources and all seven provider fixtures. Vimeo Direct must be legitimately entitled; a DASH fixture requires a real MP4/HLS fallback. CAPTCHA/MFA behavior needs its own acceptance.
- Store
MAESTRO_TEST_LOGINandMAESTRO_TEST_PASSWORDas secure EAS development variables. - Set
MAESTRO_TEST_DISPOSABLE_ACK=yes. - Set
MAESTRO_APP_IDto the actual resolved application identifier, including the development suffix when applicable. - Use the same public API in the build and test environment. Do not replace real provider behavior with mocked production records.
npm.cmd run e2e:ios:check
npm.cmd run e2e:ios:preflight
npm.cmd run eas:ios:e2e
The manual-only workflow performs GET-only public preflight, builds ios-e2e, then runs Maestro 2.11.0 with one shard, zero retries and JUnit output. It has no push, pull-request or scheduled trigger. Actual flows can create disposable login sessions and watch history and sign out that device; they read existing profile, playlist and creator data without editing or deleting it.
Keep test artifacts private. Logger message bodies and recordings are disabled, and a sanitizer handles configured credential values in text/JSON/XML outputs. Screenshot/binary artifacts and hosted collection paths have not been certified secret-safe. Review outputs before sharing and rotate disposable credentials if exposed.
Ten core Simulator cases
| Case | Defined coverage | Supplied execution result |
|---|---|---|
| 1. Launch and navigation | Standalone startup, guest Library, Settings and Home navigation. | Not run |
| 2. Authentication | Disposable password sign-in and authenticated Library state. | Not run |
| 3. Home feed | Known public fixture appears in the real guest feed. | Not run |
| 4. Playback and transitions | Real playback evidence, pause/play, fullscreen, mini-player and foreground recovery across native MP4/HLS, compatible DASH fallback, YouTube, Vimeo Direct/embed and Twitch VOD. | Not run |
| 5. Shorts | Two consecutive real Shorts, forward/back navigation and leaving the feed. | Not run |
| 6. Search | Fixture query, expected video and result tabs. | Not run |
| 7. Library and playlists | Existing account playlist and its real video fixture. | Not run |
| 8. Creator Studio | Dashboard, Content and an existing creator video. | Not run |
| 9. Profile and account | Loaded account data, privacy navigation and profile form reads. | Not run |
| 10. Logout and recovery | Restart persistence, current-device sign-out, guest restart and another sign-in. | Not run |
Playback assertions require genuine provider load/first-frame/playing telemetry and advancing progress without an active ad, error or buffering state. Mounting a screen is not playback evidence. The ten cases do not contain a Dailymotion fixture/assertion; accept Dailymotion separately. Creator/profile cases read existing data and do not cover upload or settings mutations.
Physical-device acceptance checklist
- Install and upgrade: verify signed standalone cold launch with no Metro; authenticate and visit Home, Search, Library, Creator, Notifications, Messages, Profile and Settings. Install signed baseline N followed by N+1 with the same approved bundle/signing identity without uninstalling; check login, theme and preferences.
- Native media: play real MP4/HLS and compatible DASH fallback; verify seeking, mute, captions/audio tracks, replacement, buffering/error/retry, fullscreen/rotation, mini-player and cleanup.
- Providers and ads: verify YouTube/Shorts official interactions, entitled Vimeo Direct URL expiry/restoration, Vimeo embed, Twitch live/VOD/offline states and Dailymotion playback/ads/fullscreen. Test IMA preroll/skip/content resume and applicable VMAP pre/mid/post transitions.
- Routes and lifecycle: verify PiP/background/return/exit, user pause, Control Center, calls, headphones/Bluetooth, AirPlay/Cast discovery/handoff/seek/disconnect and single audio/player ownership.
- Live: test actual camera/microphone grant/denial/recovery, front/rear publishing, received audio/video with a real remote viewer, chat/reactions/gifts, reconnect/background recovery and End Live camera/microphone release. If egress is enabled, verify host → recording → processing → replay playback.
- Uploads and mutations: select/upload real files and artwork, verify progress/cancel/recovery, metadata/captions/chapters/scheduling, profile/privacy writes, library edits, comments/replies/moderation/subscriptions and appropriate validation errors.
- Push and sessions: align real Apple/server APNs configuration; verify foreground/background/terminated delivery, badge/read counts, deep links, expiry/revocation and logout behavior.
- Accessibility and layouts: test VoiceOver, Dynamic Type, keyboards, safe areas, notch/Dynamic Island, orientations, offline/empty/error states and supported iPhone/iPad sizes.
- Stability: measure actual startup, long playback, Shorts/Live scrolling, repeated provider switching, memory and cleanup on Apple hardware.
Simulator mocks and source tests cannot establish real capture, native permission sheets, APNs delivery, hardware receiver routing or device performance. The supplied records contain no physical iPhone/iPad result and no iOS hardware performance measurement.
Before TestFlight or App Store distribution
- Pass production configuration/API preflights and create the separate signed production IPA using your approved Apple identity and signing access.
- Inspect its actual identity/version/build number, signature/provisioning, push and background entitlements, release
get-task-allowbehavior, Info.plist, trusted TLS policy, permissions, SDK inventory, privacy manifests and native notices. - Complete physical install/upgrade and functional acceptance, then review release logs and packaged data for secrets/development tooling.
- Finalize store screenshots/assets, public privacy policy, data/consent/encryption/content disclosures and the policy for enabled web billing/digital purchase paths.
- Complete TestFlight/App Store submission through your authorized Apple distribution workflow, install the processed TestFlight build, and repeat the signed-device acceptance checks before wider rollout. No completed distribution is recorded for the documented build.
Supplied validation record
The latest signing-configuration pass records 1,173 passing Vitest tests across 133 files and 81 passing Node tooling tests: 1,254 passing mobile tests. Application/API-contract TypeScript, configuration checks, Expo Doctor 21/21 and optimized local-API iOS export passed. ESLint had zero errors and three existing warnings.
The latest backend full run executed 428 tests and retained one timing-sensitive push retry-budget failure; its focused retry passed. The full run remains failed. Earlier all-green backend totals describe an earlier pass. Production export/readiness remained blocked by required production settings, and actual iOS executions remained zero. These are supplied historical results, not tests performed while updating this documentation.
iOS fixes and implementation history
9 October 2026 · version 1.0.0 implementation and validation updates. The archive records one Simulator version/build, 1.0.0 (1). The updates below are documented implementation changes within that baseline; they are not separate numbered App Store releases.
| Area | Documented change | Result and acceptance boundary |
|---|---|---|
| Native observer cleanup | Retains metadata/legible output handles, fixes the delegate assignment, detaches outputs from their original item and rejects queued callbacks from obsolete items. | Version-checked postinstall patch and regressions protect cleanup and stale-event handling. |
| Audio interruptions and unplug | Pauses on interruption/route loss, clears both auto-resume flags and reports focus/noisy events. Focus restoration reports availability without automatically playing. | Mocked-event regressions passed; real iPhone interruption/routing acceptance remains pending. Android ownership behavior is preserved. |
| First Live capture | Host/guest flows request camera/microphone through the installed WebRTC API before capture. Sequential permission sheets retain the capture transaction; genuine background cancellation remains. | Permission/capture logic covered locally; physical grant/denial and publishing remain unverified. |
| Live audio routing | Uses the installed iOS AudioSession.showAudioRoutePicker API. | Actual AirPlay/Bluetooth routing requires hardware acceptance. |
| iOS source compatibility | Source ranking and legacy conversion skip DASH on iOS and select compatible MP4/HLS fallback. Android retains DASH selection. | Pure native DASH remains unsupported; the server must supply a compatible rendition. |
| AirPlay ownership | Background source reloads/playing callbacks respect external playback ownership. Explicit pause remains effective; disconnect restores normal gating. | Controller/source regressions passed; real output handoff is pending. |
| AirPlay native compilation | Corrects the Swift property to isRouteDetectionEnabled. | Resolves the first native build error; corrected and final Simulator builds compile successfully. |
| Dailymotion iOS bridge | Adds SDK 1.4.11 Swift module/view/session, official fullscreen/ad presentation hosts, lifecycle cleanup, sequenced events and separate iOS Player ID routing. | Native Simulator compile passed. iOS uses setMute and reports supportsVolume: false; configure real iOS player/media fixtures. |
| Advertisement/content evidence | Dailymotion ad and mid-roll transitions clear content playback proof and require fresh post-ad first-frame/progress evidence. | Prevents ad activity from satisfying content playback assertions; provider runtime acceptance remains pending. |
| SDK packaging and licenses | Preserves Dailymotion vendor frameworks, shares IMA 3.33.0 and one dynamic Cast 4.8.6 supplier, rejects duplicate suppliers and packages the original Cast notices. | Simulator compilation/linking and static framework/resource inspection passed. This does not validate device coexistence or signed privacy disclosures. |
| Swift concurrency boundaries | Uses scoped legacy delegate compatibility while retaining main-actor ownership and synchronous main-queue interruption handling. | Final native compilation passed; existing unrelated dependency warnings remain. |
| iPad fullscreen/orientation | Sets requireFullScreen: true for the existing orientation-lock path. | Disables iPad split view; device layout/rotation acceptance is pending. |
| Embedded fullscreen exit | Adds accessible safe-area exit controls and stable selectors for Twitch/Vimeo modal fullscreen. | Render/controller regressions passed; actual provider interaction remains pending. |
| WebView process recovery | Turns WKWebView content-process termination into a retryable provider error, ignores obsolete surface events and remounts the surface on retry. | Local provider regression coverage; real process/network recovery remains unverified. |
| Player and Shorts test evidence | Selectors derive from real ready/first-frame/playing/progress state rather than view mounting. | Core flows are prepared but unexecuted; Dailymotion needs additional acceptance beyond the ten cases. |
| Cloud and production gates | Requires a separate public cloud API, repeats startup/API validation in the EAS pre-install hook and requires an approved production Apple identity. | No silent local endpoint fallback or inherited Android identity; missing configuration blocks artifact generation. |
| EAS workflow tooling | Pins workflow commands to EAS CLI 24.12.1 to handle current-schema reusable jobs and return a failing exit status for validation errors. | Local schema validation passed; hosted entitlement/fixtures/API requirements remain separate. |
| EAS credential inspection | Recognizes exact Expo JSON/public JSON reads so incomplete settings can be inspected. Complete API/Firebase configuration is preserved; artifact and worker guards remain strict. | The supported credential workflow reaches Apple signing inspection. It does not establish signing, a device build or release acceptance. |
Keep native dependency pins and the version-checked postinstall patch when reinstalling dependencies. Rebuild after native configuration/module changes, rerun affected regressions and record actual device results before marking an iOS release accepted.
Application versions, updates and fixes
The supplied records provide development milestones rather than a complete published mobile release history. Version 1.0.0/build 1 is confirmed for the iOS development Simulator artifact; sample API header versions do not identify additional app releases.
| Milestone | Features, changes and fixes | Scope |
|---|---|---|
| API v1 readiness baseline | Documented bootstrap and six client platforms; native login/registration/social/TV flows; device-bound rotating refresh sessions; structured errors and pagination; compatible signed native playback, captions and progress; resumable uploads; protected push-registration storage. | Backend/API readiness with explicit unsupported services. It does not represent a released mobile binary. |
| Website/mobile implementation pass | Added or extended Explore, Trending, Subscriptions, Communities/composer, Favorites, Bookmarks, creator Content/Analytics/Growth, analytics CSV, earnings/wallet/plan/billing/account-storage screens, real language packs, managed help links, TV approval and optional-plugin capability handling. Added Live viewer chat/polls and canonical website actions for appropriate financial/provider workflows. | The historical “complete” declaration described implementation coverage. The later audit supersedes any claim of identical behavior or complete device acceptance. |
| Parity corrections | Preserved empty plugin/translation JSON dictionaries; fixed precise Studio and filtered Live deep-link routing; prevented unavailable-plugin API requests; kept private caches scoped to the account; corrected camera/microphone manifest removal; added a fresh Test prerequisite after permission grants and asynchronous capture cleanup guards. | Documented in the October parity work. Native MP4/mini-player, selected route/language and permission checks were observed; full device/media coverage was not established. |
| Live implementation and Android follow-up | Expanded Live capabilities and real-time controls; hardened capture/track ownership, cancellation and stale-grant behavior; updated the documented native LiveKit stack; fixed Live directory boolean encoding and replay-panel lifecycle behavior. Later Samsung connectivity and media follow-up is recorded separately. | See the Live guide for exact service versions, current fixes, physical observations and remaining acceptance limits. |
| Current parity audit notice | Clarified that the earlier coverage statement did not capture all gaps. Website/mobile behavioral differences and incomplete device, public API and release evidence remain explicit. | The archive references an additional application audit that was not included. No missing details or release version are inferred. |
| Android connected Live acceptance | Recorded Android Live PASS and web-to-mobile Live parity COMPLETE on a physical Samsung Android 15 device against the local backend and separate web accounts. Verified real media both ways, supported interaction/moderation, revocation, recording and physical replay. Focused fixes addressed due saved schedules, equal-timestamp chat order, stale ended-summary errors and abnormal host-loss reconciliation. | Supersedes blocked 3–4 October Live results. It is local development acceptance, not production/iOS/all-device certification. See the complete Live scope. |
| iOS development version 1.0.0, build 1 | Successful native Simulator compilation, iOS provider/media/packaging corrections and a fix allowing EAS credential inspection without weakening artifact-production configuration checks. | Development client, not a signed physical IPA; no iOS execution was recorded. See iOS build, fixes and acceptance. |
| Shared backend capability documentation | The web 0.9.13 source update confirms implemented FCM/APNs sending with durable outbox, queue dispatch, bounded retry/recovery and readiness gates. Shared protected cloud delivery and display-image fixes also benefit native clients using the returned API URLs. | This is a shared backend/source milestone, not a newly numbered mobile release. Push defaults disabled and actual device delivery remains unverified. |
Capability limits carried across these updates
- No native StoreKit/Google Play digital checkout or receipt-validation endpoint; existing authorized web purchases remain playable.
- No generated adaptive HLS/DASH, DRM, HDR signaling, authorized offline download or direct-to-cloud multipart upload. Native remote push is implemented but disabled until its platform configuration and readiness gates pass; device delivery still needs acceptance.
- No shipped TV build, complete iOS runtime acceptance, exhaustive Android/tablet accessibility acceptance or signed production release is established by the supplied reports.
- Live depends on reachable configured services; provider media, financial handoffs and signing require their actual external setup.
For website release versions and backend update instructions, use the website changelog and installation guide. Configure the app's real supported/latest/minimum version policies on the server when distributing your own validated build.
Application troubleshooting
| Symptom | What to check |
|---|---|
| App cannot reach the server | Verify the embedded API base, /api/v1/bootstrap, device DNS, routing and trusted TLS. Local .test names need a reachable resolver and local device trust; cloud builds require their separately configured public endpoint. |
| Development launcher cannot load JavaScript | Ensure the correct Metro process is ready and the device can reach it. Metro connectivity is separate from the API connection. Relaunch the development client after the listener is available. |
| Sign-in fails or a provider button is missing | Check bootstrap login/registration flags, account status, CAPTCHA/two-factor requirements, effective provider configuration and the exact OAuth callback allowlist. |
| Repeated 401 or unexpected logout | Inspect the request's error code and request ID; use one serialized refresh and atomically replace both credentials. Check device/platform consistency and avoid replaying a consumed or ambiguously submitted refresh credential. |
| Video is locked, missing or returns 403/404 | Recheck visibility, publication/moderation, account access and purchase entitlement. The API may intentionally hide inaccessible content with 404. Native checkout remains disabled. |
| Video starts but seeking or captions fail | Use a fresh compatible source, exact MIME and returned caption format. Verify Range responses, signature lifetime, CDN query preservation, S3 temporary URLs and required CORS headers. |
| Cloud avatar or banner fails | Use the API's signed avatar_url/cover_url intact. Check configured private-cloud credentials and provider read limits. The server image cache reduces reads; it cannot fetch an uncached object when the provider refuses it. Do not publish a private bucket to work around an image URL. |
| External provider fails | Use the official returned provider route; check provider availability, player IDs, approved Twitch parent and retained Vimeo URL data. Do not treat a provider embed as a direct native URL. iOS DASH-only media needs an MP4/HLS fallback. |
| Camera/microphone permissions are absent | Inspect persistent Expo plugin settings and the generated/merged native manifest. Conflicting image-picker removal settings can override requested Android permissions. Rebuild the binary after correcting native configuration. |
| Go Live stops after a new permission dialog | After granting access, return to the app and tap Test again. The first-use permission prerequisite deliberately avoids automatic capture/draft creation. Check measured preflight and service readiness before publishing. |
| Live reports unavailable or reconnect fails | Check configured LiveKit/TLS/networking and the current server audience/stage policy. Ended, banned or revoked participants need fresh authorized state. Follow Live installation and diagnosis. |
| Upload remains processing | Check queue workers, FFmpeg/FFprobe, storage access and the video's returned processing/failure state. Resume an interrupted transfer by reconciling the existing session; do not create duplicate completion requests. |
| Storage or plan values look different from a demo | Use the current account's server-returned quota and plan. Example device observations are not fixed product allowances. Local phone cache and account storage are separate. |
| Plugin feature or Campaigns entry is absent | Check installed/enabled/healthy/mobile-supported/permitted capability state and a real compatible native implementation. An absent optional plugin is expected to remain hidden. |
| Remote push never arrives | Check features.push_delivery, platform credentials, required tables, registration/session state, saved preferences and the durable outbox. Delivery defaults disabled. Confirm a worker consumes the configured push queue; videos,default alone is insufficient. Test the actual signed APNs environment or FCM device registration and provider feedback. |
| iOS production build or credential setup is blocked | Confirm the real public API, approved Apple bundle identifier, team, project linkage and signing/provisioning access. Credential inspection does not create missing credentials. See iOS requirements. |
For support, provide the app version/build, platform/OS, selected environment, timestamp, reproducible steps and the API request_id. Keep credentials, private URLs, signing files and server secrets out of screenshots and shared logs.