← Back to portfolioMinn Khant Thu

Mobile · web · backend · media

PerseusTV+

A streaming experience, from the creator’s upload to the viewer’s next play.

PerseusTV+ is a streaming product with several connected surfaces: a viewer app, creator tools, an operations dashboard, backend services, and a public download website. My freelance work spans these surfaces, especially the boundaries between the player, content access, media delivery, and publishing workflows.

Google Play downloads
10K+
Google Play · Thailand
4.5/5
US App Store · 12 ratings
4.8/5

Public store snapshot · . Downloads are not active users.

Engagement
Freelance development
Focus
Cross-platform product engineering
Case-study basis
Implementation and test-source review · September 2026

The problem behind the screens

A working video screen is only one part of a streaming product. Content has to finish processing before it can be watched; access rules must agree across the app and server; interrupted playback needs a recovery path; and creators need to understand what happened to an upload. Older app versions also need a compatible view of a changing catalogue.

My role

My contribution spans Flutter client development, React administration interfaces, Node.js API integration and services, media-delivery integration, and the download website. This is a description of my engineering scope, not a claim that I single-handedly created every dependency or service in the system.

One product, different responsibilities

The viewer, creator, and operator need different interfaces. The shared backend coordinates the rules and data between them.

  • Viewer application

    Flutter · Riverpod · Dio · media_kit

    Content browsing, playback-session integration, player recovery, watch progress, and version-compatible media responses.

  • Creator workspace

    React · TypeScript · TanStack Query

    Video upload and processing feedback, posts, playlists, comments, and channel-management workflows.

  • Operations dashboard

    React · TypeScript · role-aware interfaces

    Separate operational interfaces for managing channels, content, and review workflows.

  • Application services

    Node.js · Express · MongoDB

    Content metadata, publication and access checks, playback sessions, and compatibility rules for different app generations.

  • Media delivery

    HLS · object storage · signed delivery

    Railway-backed media storage and an authorized delivery path. CDN-backed delivery is configuration-dependent, not a claim that every environment uses the same route.

  • Public download website

    React · Vite · Tailwind CSS · Express · Railway

    I built download.perseus-tv.app, including the app-download experience, same-origin API proxy, share-page metadata, and mobile app-link association support.

From upload to playback

A simplified engineering flow. Storage and CDN routing depend on the deployed configuration.

  1. Prepare the content

    A creator uploads through the web workspace. Multipart transfer and media processing are separate states; completing an upload does not mean the video is ready to watch.

  2. Request playback

    The Flutter app asks the API for a playback session. The backend checks identity, content readiness, publication, channel availability, and the applicable viewing entitlement.

  3. Return a scoped session

    An authorized request receives an expiring session and manifest information. The client resolves the media source before handing it to the player.

  4. Deliver and recover

    The player loads HLS media through the authorized delivery path. In the configured CDN path, media bytes are delivered outside the application server; playback failures use a bounded recovery policy.

  5. Remember progress

    Playback position is saved locally, with cloud synchronization when enabled. Ordered writes keep a late progress update from overtaking a completion update.

The engineering decisions

Five examples of the constraints and implementation choices behind the product.

Recover the player without an endless restart loop

Challenge
An error before playback begins is different from a transient failure after the video has already advanced. Treating both as an immediate restart can fight the native player’s own recovery.
Implementation
The retry policy distinguishes startup from recovered playback, caps startup attempts, and allows a recovery grace period after progress. Recovery is determined by an advancing playback position, not just a successful player initialization.
Trade-off
Bounded retries may still end in a visible error on a poor connection. The aim is predictable failure and recovery, not a promise of uninterrupted playback on every network.

Keep watch progress responsive and ordered

Challenge
Saving every player event remotely adds unnecessary writes. Concurrent updates can also leave an older position arriving after a newer or completed state.
Implementation
A local progress store provides a resume point. Cloud writes are throttled and serialized, with increasing sequence values and session information. Completed local entries restart from the beginning rather than resuming at the end.
Trade-off
Local and cloud state are not instantly identical. This favours a useful local experience while explicitly managing synchronization and session conflicts.

Make upload progress mean something

Challenge
Large video uploads can fail partway through, and successful transfer is not the same as successful processing. A single “uploading” spinner hides both problems.
Implementation
The creator uploader separates initialization, part transfer, completion, processing, readiness, failure, and cancellation. It uses bounded concurrency, part retries, progress reporting, and processing-status polling.
Trade-off
The interface has more states to explain, but creators can distinguish a transfer problem from a processing problem. Part-level retries are not presented as guaranteed resume after closing the browser.

Keep access decisions on the server

Challenge
Hiding a video in the interface is not an access-control boundary. A playable item also needs consistent readiness, publication, channel, and subscription checks.
Implementation
The backend evaluates those rules before issuing a scoped, expiring playback session. The client handles the resulting playback or access state rather than deciding entitlement from UI flags alone.
Trade-off
Session expiry and authorization failures become part of the player experience. Signed delivery limits access; it is not a claim that content is impossible to copy or that a DRM rollout has been verified.

Evolve the catalogue without assuming every client has updated

Challenge
New content types and channel behaviour can reach the backend before older mobile clients understand them.
Implementation
Version-aware visibility rules distinguish app generations and restrict newer content where needed. Compatibility tests cover missing version information, older clients, and newer-client access to the expanded catalogue.
Trade-off
Supporting old clients adds backend branching and test cases. I treat compatibility as an explicit contract instead of relying on everyone upgrading immediately.

Evidence & verification

  • Playback behaviour

    Existing tests exercise bounded retries, recovery based on actual position progress, HLS session parsing, and media-model compatibility.

  • Progress consistency

    Existing tracker tests cover completed-item resume behaviour and ordered cloud updates with increasing sequences.

  • Client compatibility

    Backend tests exercise generation detection and catalogue visibility rules for old and new clients.

  • Public-facing work

    The download website is a public example of my web contribution. Internal dashboards and customer data are intentionally not reproduced here.

Scope of this review

This account is grounded in reviewed implementation and existing test source. It is not a fresh end-to-end production audit or a report that those tests were rerun for this page. Device playback, network behaviour, and CDN configuration need separate live verification. Public store listings, download milestones, and ratings were checked separately on 23 September 2026 and are linked above. Downloads do not measure active users. No uptime, revenue, crash-free rate, or performance-improvement metrics are claimed.

What this work demonstrates

The strongest part of this work is not the number of screens. It is connecting the viewer experience to the operational system: a creator can see processing state, the server makes access decisions, the player has a bounded recovery path, and watch progress has an explicit synchronization model.

I can discuss the client, API, and delivery trade-offs in an interview without exposing private source code or customer data.

Discuss this work ↗