HyperTodo is a test application for the dj-hyperview package. It combines a Django backend with an Expo mobile host that uses Hyperview to render native screens from server-provided HXML.
The project exists to exercise dj-hyperview in a realistic application. It is not intended to be a reusable task-management product.
- Django login, sessions, CSRF and per-user task/category ownership.
- Task/category forms, filters, completion and partial HXML updates.
- Filesystem and database templates, Admin editing, automatic validation and caching.
- Contextual SSE refresh, draft protection and account/session isolation.
- Light/dark themes, English/Spanish, avatars, biometrics and accessible native UI.
Automated checks and manual device acceptance are separate; a passing XML or
Jest test does not prove every native flow. Hyperview 0.112.0 keeps the 0.111.0
fragment-fetch cleanup (covered by mounted regressions) and, replacing
createTestProps, maps XML id to testID, as HyperTodo's custom components
already did. The backend pins the published dj-hyperview 0.1.0b3, whose
corrected 0.111.0 XSD is byte-identical to upstream's 0.112.0 one and stays the
contract. None of this changes the SSE wire protocol or needs a Navigation 7
migration.
| Path | Purpose |
|---|---|
backend/ |
Python 3.14 / Django 6.1.1, pinned to dj-hyperview[editor,realtime]==0.1.0b3. |
mobile/ |
Expo SDK 57, React Native 0.86 and Hyperview 0.112.0 host. |
Makefile |
Install, run and quality commands for both applications. |
Prerequisites: macOS with bash (the Makefile targets it), Python 3.14 with
uv, Node 22.19.0 through nvm/Corepack (nvm install 22.19.0 once), and
Expo Go for SDK 57. SSE also needs an existing Redis server; installing its
Python client does not start one. Run commands from the repository root.
Database safety: migration/seed commands below are for deliberate setup of a new disposable database. For existing data, back up and review migrations; do not seed to upgrade. The seed can reset demo accounts/data. Follow the installed-package and safe startup guide for credentials, existing DB overrides and deployment details.
Seeded accounts: while DJANGO_DEBUG is 1 (the default; any other value turns
DEBUG off), make backend-seed creates the superuser admin / admin123 and the user
demo / demo123, unless HYPERTODO_ADMIN_PASSWORD / HYPERTODO_DEMO_PASSWORD are
set. Set both before binding beyond loopback (backend-run-device, or backend-run-sse
with LAN_IP); backend-run and backend-run-redis listen on loopback only.
| Command | Use |
|---|---|
make help |
List every available target. |
make setup |
Install backend/mobile dependencies; does not migrate or seed. |
make backend-migrate, make backend-seed |
Initialize a new disposable demo DB, not an upgrade shortcut. |
LAN_IP=192.168.1.20 make backend-run-sse |
Start the same DB-first ASGI/SSE app, bound to the supplied LAN address. |
LAN_IP=192.168.1.20 make mobile-start-go |
Start the matching Expo Go QR workflow with explicit local-HTTP permission. |
make backend-run, make backend-run-redis |
Start ASGI/SSE on loopback only, without or with the Redis template cache, respectively. |
LAN_IP=192.168.1.20 make backend-run-device |
Start the same ASGI/SSE app on all interfaces with Redis cache and device host/CSRF settings. |
make mobile-start, make mobile-start-device |
Development-client workflows, not Expo Go; device target requires LAN_IP. Every development target enables the local-HTTP opt-in itself, so no mobile/.env is needed. |
make lan-ip |
Print the default-route interface address (en0, else another en*, skipping 169.254.x.x, when a VPN holds the route) as a candidate; verify reachability from the phone. |
For SSE, run make setup, prepare the database as appropriate, then keep the
ASGI and Expo Go commands in separate terminals. Replace the example IP in
both with the same reachable private computer address, scan the QR and sign in.
No native build is needed. Use only trusted development networks, not real data
or publicly exposed demo credentials; stop both terminals with Ctrl+C.
![]() Login |
![]() Light dashboard |
![]() Dark dashboard |
![]() Task actions |
![]() Edit task |
![]() Categories |
![]() Settings |
![]() Side menu |
![]() About |
These extensions belong to HyperTodo, not dj-hyperview or Hyperview core. HXML declarations describe the interface; the registered mobile implementation provides the native behavior. Adding a schema declaration alone installs nothing.
Five registered elements use https://hypertodo.app/components (app: below).
App registers the visual components;
AppSessionSurface adds the realtime pair.
| Element | Why it exists |
|---|---|
app:side-menu |
Animated drawer/backdrop with HXML-provided contents. |
app:edge-menu-opener |
Edge gesture that fetches the menu without replacing the screen. |
app:swipe-row |
Task/category action tray with equivalent screen-reader actions and optional destructive confirmation. |
app:realtime |
Coordinates resource dependencies, safe refresh, forms and route/session ownership. |
app:realtime-page |
Invisible request/page marker for correlating actual layout; adds no row. |
app:swipe-action is child data read by SwipeRow, not a sixth component.
Keep its normal form/CSRF context for mutations. See real
task rows and
side-menu markup.
The six actions in owned behaviors use native ports while retaining their source and session generation. They are actions, not HTTP verbs or permission checks.
| Action | Why it exists |
|---|---|
probe-biometrics |
Discover hardware/enrollment and reveal available sign-in controls; does not authenticate. |
biometric-unlock |
Prompt through the OS, then submit the captured login form; Django still authenticates. |
store-biometric-token |
Store or explicitly clear an authorized device credential; arbitrary HXML cannot grant write authority. |
pick-avatar |
Select/resize an image and update its draft preview; saving remains an ordinary form action. |
show-snackbar |
Show brief response feedback using the native host. |
notify-resources |
Mark local dependent screens stale after an operation; does not publish to Redis or replace authenticated SSE. |
navigate, back, reload, replace, append and dispatch-event remain
built-in Hyperview actions; get/post choose the HTTP method. See the
login panel and
task transition for usage.
These helpers are mounted by React, not addressable as XML tags.
| Helper | Purpose |
|---|---|
AnimatedSplash |
Branded startup, reduced motion and bounded animation fallback. |
Loading/Error screens, ElementErrorBanner |
Branded loading and safe page/fragment errors. |
OfflineRefreshControl |
Finish a failed pull-to-refresh indicator without retrying or declaring success. |
SnackbarHost, RealtimeNotice |
Transient feedback versus persistent non-conflict warnings/errors. |
RealtimeConflictDialog |
Explicit Update / Go back choices for an open form's relevant remote change. |
AppSessionSurface, gate/navigation |
Authentication shielding and request/navigation lifetime across account changes. |
Extra attributes on core elements are not new components: image.variant
selects biometric icons, and picker-item entity metadata tracks the selected
category dependency. None grants entity access. Implement/register new extensions
in the host and declare their backend schema; preserve authentication,
ownership and CSRF. See the contextual-update policy.
Every backend command uses config.settings: active database templates take precedence, with filesystem fallback when no active override exists. Startup never rewrites stored templates. A fresh demo seed creates About and Categories overrides.
Sign into /admin/ as an authorized superuser, open Hyperview database templates → Hyperview templates, edit a template and save. With Redis available, committed changes send a ui hint to connected clients; the next authenticated HTTP refresh resolves the updated DB template without rebuilding the app. The stored screen must retain its realtime boundary for automatic refresh; older overrides need review. For existing data, follow override adoption instead of seeding or overwriting deliberate Admin edits.
Template editing is code-deployment authority: dj-hyperview permits mutations only to superusers by default. Format and Validate is context-free; it does not preview a rendered screen or prove every dynamic branch.
The installed beta applies the corrected standard XSD automatically; there is
no validation-off switch. HyperTodo adds only its own components in
hypertodo.xsd and behavior/attribute declarations
in schema_extensions(). Startup requires the
automatic-xsd-v1 capability.
Tests render real route contexts, themes, languages and valid/invalid forms; XML acceptance does not prove native component registration or device behavior. Review effective DB overrides before upgrading the package/app pair. See the package validation guide.
The single config.settings enables HYPERVIEW["REALTIME"] independently of cache. All backend launchers use Uvicorn/ASGI and the same DB-first source order, Redis endpoint and namespace. Redis must already be running for notifications; REDIS_URL defaults to redis://127.0.0.1:6379/15. Use the same configuration for Admin, other writers and stream workers. Authentication, sessions, CSRF and validation remain unchanged. Redis PubSub channels are not isolated by database number. See startup/configuration and the backend contract.
Committed hints cause authenticated HTTP refreshes; they carry no full document and do not guarantee replay. The current app wires these areas:
| Area | Relevant changes | Visible behavior |
|---|---|---|
| Tasks / Categories | Task/category saves and deletes; ui presentation/template changes. |
Automatic refresh, retaining filters and the bounded loaded prefix. |
| Dashboard | tasks, categories and ui. |
Automatic refresh; a stale return loads fresh content before showing it. |
| Task / category forms | Current record, selected category for a task, and the owner's ui changes. |
Update / Go back dialog, whether untouched or edited; precise metadata excludes unrelated records. |
| Settings | Owner's User first_name, last_name, email; Profile theme, language, avatar. |
Same remote-change dialog; this app's own operations stay quiet. |
| About | ui presentation/template changes. |
Automatic refresh of the readonly screen. |
Settings is already wired: normal Django Admin saves of the signed-in user's name should notify it. The Admin writer must also have realtime enabled and use the same Redis namespace and service as the stream server. QuerySet.update() and bulk_update() bypass save signals and need explicit publication; they are not equivalent to an ordinary Admin save.
The side menu is a fetched fragment, not an independent SSE boundary. Login/recovery use session reconciliation, not change dialogs. Own-operation feedback and login/resync stay quiet. See the mobile policy for draft safety, pagination and actual layout acknowledgement; this inventory is not a new native acceptance result.
make checkRuns backend Ruff lint and format checks, tests and coverage, installed
Admin-editor JavaScript, Django checks and migration-drift checks, plus mobile
TypeScript/Jest/Expo Doctor. Doctor runs against DOCTOR_API_URL, by default the
HTTPS .invalid address https://hypertodo-ci.invalid/hv/, which is
validation-only, not a backend. It must resolve Expo config and report all
checks successfully, needs network access, and unavailable online checks are
not a PASS. No native build or private mobile/.env is required.
CI also runs the full backend suite against a disposable Redis 8 service, with the same coverage gate. The Redis tests exercise the default cache, database session ownership and live SSE, including a post-idle publish. They use unique key namespaces and never flush a shared Redis database.
Use make backend-test / make mobile-test for separate suites and
make acceptance for the manual iOS/Android checklist. Optional
make backend-test-redis requires an owned disposable loopback Redis service:
set HYPERTODO_REDIS_TEST_OWNED=1 and REDIS_TEST_URL to its explicit port and
database 14. Never point it at shared data or flush a shared service. See the
package documentation.
HyperTodo is distributed under the MIT License.









