Version: 5.0 Date: 2026-06-15 Application: DMH (Dead Man's Hand) — watchdog timers, reminders, social tasks, chat, donations, settings, PWA support, and all current user-visible state combinations Frontend: Next.js 15.5.x + React 19 Backend: NestJS 11 Audience: third-party manual tester with no access to project infrastructure
The purpose of this plan is release confidence, not a demo-path smoke test. Execute it with the assumption that any feature may work in one role, browser, locale, network condition, task setting, or account state and fail in another. A feature is not considered verified until its relevant state combinations below have passed or have a written, product-approved skip reason.
0. Scope Rules
This plan is written for a tester who has only:
A public or staging base URL.
A modern browser and browser devtools.
Disposable email inboxes for test accounts.
Optional tester-owned external services for feature-specific checks (for example a Telegram bot, webhook.site URL, Home Assistant instance, SSH test host, or ESP32 board).
The tester must not need Docker, database access, Redis, server logs, cloud consoles, deployment access, Stripe CLI, internal API keys, or repository access.
Current Working Scope
Test only behavior that is currently visible and usable from the application UI:
Public pages: /, /login, /register, /forgot-password, /new-verification, /docs, /docs/USER_GUIDE, /donations, /feed, challenge detail pages reached from /feed.
Admin-only page only if an admin test account is explicitly provided: /admin/icons.
User-facing API behavior only when triggered by the UI.
Out Of Scope Until Re-Enabled
Do not test these as working flows:
Stripe checkout, Stripe webhooks, Stripe redirect success/cancel flows, Stripe test cards, and Stripe CLI.
Exit Matrix payment completion. The /exit page can be checked for rendering and consent gating only; do not require a successful payment.
Monobank acquiring/card invoice flow. Only the current Monobank Jar link or disabled "coming soon" state is in scope.
Internal endpoints that require x-internal-key, admin-only backend APIs, anti-fraud admin APIs, backup cron/pg_dump jobs, direct database state, queue workers through infrastructure manipulation, or unit-test coverage summaries.
Direct /leaderboard route. The current user-facing leaderboard is the slider on /feed.
Provider delivery for SMS, SSH, Home Assistant, or custom Telegram/API targets unless the tester owns a safe test endpoint or credentials. UI validation and graceful failure are still in scope.
Pass / Fail / Skip Rules
Pass when the expected result is visible from the browser or from a tester-owned inbox/device/service.
Fail when a visible, in-scope feature breaks, crashes, loses data, exposes another user's data, shows a 5xx/uncaught error, or cannot complete the expected user flow.
Skip as Not Available when a feature is hidden, disabled, region-gated, requires unavailable tester-owned hardware, or depends on a currently out-of-scope provider.
Do not mark skipped external-provider checks as failures unless the UI claims the provider is configured and the tester has been given valid test credentials.
Required Test Data
Prepare these before execution:
Account A: primary test user with disposable email inbox.
Account B: second user with disposable email inbox for contacts, sharing, chat, challenge, and ownership tests.
Account C: optional unverified or blocked/disposable account for limits and destructive language/self-block checks.
Browser profiles: at least two independent profiles or one normal + one private/incognito session.
Optional test targets: webhook.site URL, Telegram test bot/chat, Twilio test credentials, Home Assistant test instance, SSH test host, ESP32 board with USB cable.
Never use real secrets, production customer data, or personal payment details.
Release-Confidence Execution Model
Use this plan as a state-space test, not as a linear checklist. For every feature scenario:
Record the active account, role, auth state, email verification state, locale, theme, UI scale, timezone, browser, viewport, network mode, notification permission, task-type setting set, and data volume.
Test at least one negative path before marking the matching positive path stable.
Test reload, browser back/forward, second-tab visibility, and logout/session loss for any workflow that saves data.
Treat "works in one configuration" as insufficient. If the same behavior fails in any required configuration, mark the feature Failed until fixed or explicitly scoped out.
Do not rely on database cleanup, server logs, queues, or admin consoles. Create unique data with a run prefix such as QA-2026-06-15-A-.
Keep an evidence ledger with screenshots/video for every Fail and for every Critical path Pass.
Mandatory State Axes
The tester must cover these states across the plan. Full Cartesian coverage is not required, but every value listed here must appear in at least one relevant scenario, and high-risk flows must use the mandatory configuration matrix below.
Axis
Values to cover
Auth
Logged out; registered but unverified; verified credentials user; logged-in user after reload; logged-in user in a second tab; revoked/expired session; OAuth user if provider buttons are visible; Telegram WebApp user if a launch link is provided
No account; unverified Account C; verified Account A; verified Account B; paid tier only if explicitly provided by environment owner
Local task-type settings
Default set: all five current types; Reminder-only; Watchdog-only; each type enabled; attempt to disable the final remaining type
Task data volume
Empty account; one task; mixed list with at least 8 tasks across types/statuses; long title/description; duplicate title; special characters/Unicode; deleted item; stale URL/id after deletion
English; Ukrainian; one long-label locale such as German/French/Polish; one RTL locale such as Arabic or Urdu; unsupported Accept-Language fallback; Russian self-block option only on disposable Account C
Visual preference
Dark theme; light theme; normal UI scale; compact UI scale
Timezone/time
Browser default; Europe/Kyiv; America/New_York or another negative UTC offset; Asia/Tokyo or another positive UTC offset; due soon; due in the past; date at month end if feasible
Browser/device
Chrome desktop; Safari or Firefox desktop; iOS Safari or Android Chrome; installed PWA if supported; private/incognito profile
Viewport
1440x900 desktop; 768x1024 tablet; 390x844 mobile; mobile with software keyboard open
Network
Online; offline after cache warmup; slow 3G; reconnect after offline mutation; backend/API error if naturally exposed by UI
Browser permissions
Notification default; notification granted; notification denied; clipboard allowed; clipboard blocked/denied; passkey prompt success; passkey prompt cancel; Web Serial supported/unsupported
Two tabs same account; two profiles different accounts; rapid double-click submit; edit same item in tab A while tab B reloads or acts on stale data
Mandatory Configuration Matrix
Run the whole plan through these named configurations. Individual sections may add more targeted combinations. If a browser/device is unavailable, record the exact reason and choose the closest available alternative; do not silently skip.
ID
Account/session
Browser/device
Locale/theme/scale
Network/permissions
Must cover
C1
Logged out
Chrome desktop
en, dark, normal
Online, default permissions
Public routes, auth redirects, docs, feed, donations, challenge detail read-only
C2
Logged out
Mobile Safari or Android Chrome
uk, light, normal
Slow 3G
Public routes, landing/register/login/feed responsive behavior
C3
Account C unverified
Chrome desktop
en, dark, compact
Online, notification denied
Verification banner, blocked chat/share/server-task limits, safe destructive-language self-block only if explicitly run
Consent gating only; payment is out of scope while Stripe is disabled
/admin/icons
Admin only
Icon moderation only with admin test account
Route coverage rules:
Every public route is tested logged out, logged in, after reload, and from mobile.
Every protected route is tested logged out, logged in as Account A, after logout, and after session revocation from Settings.
Any route with a dynamic id is tested with a valid id, deleted/stale id, malformed id, and another user's id when such an id can be obtained from the UI.
Any route reachable from a link is tested by direct URL entry and by clicking the in-app link.
Every route has a C1-C10 configuration id recorded in the run notes.
2. Global Checks For Every Page
Run these checks on each visited page unless a scenario says otherwise.
Page loads without a blank screen.
No uncaught console errors after load.
Back/forward browser navigation works.
Reload preserves expected state or shows a clear loading/auth state.
Desktop viewport: 1440 x 900.
Mobile viewport: 390 x 844.
No text overlap, clipped primary controls, hidden submit buttons, or unusable fixed banners.
Keyboard can reach primary inputs and buttons.
Loading, empty, error, and disabled states are understandable.
No private data from another account appears.
The same page is opened with fresh localStorage, existing localStorage, and after clearing site data where safe.
Slow network does not leave permanent skeletons, duplicate submits, or disabled controls that never recover.
Offline mode shows a deliberate offline/cache/error state, not a framework crash.
If a mutation succeeds, reload and open a second tab to verify persisted state.
If a mutation fails, user-entered data remains recoverable unless the product intentionally discards it with a warning.
Long text, narrow viewport, translated labels, and compact UI scale do not hide primary controls.
Browser console is checked after page load, after the first mutation, after navigation away/back, and after reload.
3. Public And Onboarding Flows
3.1 Landing Page
Open /.
Verify brand/title and primary value proposition are visible without login.
Verify landing feature cards include the current feature set, including action chains.
Click Get Started; expected: navigates to /register.
Return to /, click Sign In; expected: navigates to /login.
Simulate offline mode in devtools; expected: offline banner/page behavior is graceful.
Check mobile layout: no hero/nav/footer overlap.
3.2 Registration
Open /register.
Submit empty form; expected: validation errors, no account created.
Test invalid email, weak password, mismatched confirmation, and duplicate email.
Test leading/trailing spaces in email and password fields; expected: predictable trim/no-trim behavior and clear validation.
Test very long name/email local-part if fields allow it; expected: validation, not layout break or server crash.
Register Account A with a unique disposable email and strong password.
Expected: success message asks user to verify email.
Confirm the submit button is disabled or guarded while pending.
Rapidly double-click submit or press Enter twice; expected: one account/verification email, not duplicates.
Refresh after success; expected: no accidental resubmit.
If social buttons are visible, click each one far enough to confirm it starts the provider flow, then cancel or return. Do not use personal OAuth accounts unless approved.
3.3 Email Verification
From Account A's inbox, open the verification link.
Expected: /new-verification?token=... shows loading, then success, then a route back to login.
Open /new-verification without token; expected: clear missing-token error.
Open /new-verification?token=invalid-token; expected: clear invalid-token error, no crash.
If verification email is not received, record it as an email-delivery bug only when the environment owner said email is configured.
3.4 Login, Logout, And Auth Errors
Open /login.
Submit invalid email and empty password; expected: inline validation.
Submit wrong password for Account A; expected: generic invalid-credentials error.
Login with Account A; expected: redirect to /dashboard.
Open /login while authenticated; expected: redirect to /dashboard or already-authenticated state.
Logout from the app; expected: session clears and protected routes redirect to /login.
Open /dashboard while logged out; expected: redirect to /login.
Login in two browser profiles; revoke one session from Settings; expected: revoked profile cannot perform the next protected action.
In two tabs of the same profile, logout in tab A and perform an action in tab B; expected: tab B redirects or shows an auth error without data loss.
Simulate backend/network loss during login submit; expected: recoverable error and submit button re-enables.
Open /forgot-password; expected: clear "not self-service yet" style page and contact/report link, no 404.
Open /error and /session-ended; expected: pages render without crashing.
3.5 Passkey Login
Run only on HTTPS or localhost with a WebAuthn-capable device.
Login to Account A.
Go to Settings → Profile → Passkeys.
Add a passkey; expected: browser WebAuthn prompt appears and a credential is listed.
Try to add a second passkey with the same device if the browser allows it; expected: duplicate is prevented or listed clearly.
Logout.
Use passkey login from /login; expected: Account A is signed in.
Cancel the WebAuthn prompt; expected: visible non-crashing error.
Try passkey login from a browser profile without the credential; expected: clear error or browser-managed not-found state.
3.6 Telegram WebApp Authentication
Run only if the tester is given a Telegram bot/app launch link.
Open DMH inside Telegram's in-app browser.
Expected: Google/GitHub OAuth buttons are hidden if the environment does not support them there.
Telegram auto sign-in starts without exposing raw init data in the UI.
Successful Telegram auth lands on /dashboard.
Invalid/stale Telegram launch data shows an auth error, not a blank page.
4. Dashboard Baseline
4.1 Layout And Navigation
Login as Account A and open /dashboard.
Start with an empty account; expected: empty state and new-user tooltip do not block creation.
Repeat with an account containing at least 8 tasks across task types/statuses; expected: list remains scannable and filters still work.
Verify clock/date, sidebar, create/search control, filters, task list, and right panel on desktop.
On mobile, verify single-column task list and usable sidebar/navigation.
Sidebar links navigate to Dashboard, Feed, Chat, Donations, Docs, and Settings.
Protected sidebar pages redirect to login after logout.
Change timezone and reload dashboard; expected: clock and task due displays use the selected timezone.
Open dashboard in two tabs; create/edit in tab A, reload/refocus tab B; expected: no duplicate/stale task row after sync.
4.2 Create/Search Bar
In create mode, type a unique title and press the plus/submit control.
Expected: task is created, toast appears, input clears, task appears as Inactive.
Default new task type should be Reminder when Reminder is enabled.
Create with duplicate title; expected: allowed only if product allows duplicates, but the two rows remain distinguishable by schedule/type/status.
Create with a very long title and Unicode/special characters; expected: saved text displays without overlap or broken filtering.
Rapidly submit the same title twice; expected: either one task or two deliberate separate tasks, never a loading deadlock.
Toggle to search mode; type part of a task title.
Expected: list filters by title.
Unknown search text shows empty state without clearing data.
Slash commands from the search field:
/report navigates to /report.
/backup navigates to /backup.
/exit navigates to /exit.
Unknown command such as /foo does not navigate.
4.3 Filters And Sorting
Status filter: All, Inactive, Active, In Progress, Completed, Failed.
Task-type filter includes only task types enabled in Settings.
Shared filter shows tasks shared with Account A.
Sorting order: Active, InProgress, Completed, Failed, Inactive; then by start time.
If a task type is disabled in Settings, it disappears from the creation/filter controls without deleting existing tasks.
With Reminder-only enabled, create/search/filter only Reminder tasks; expected: no hidden Watchdog default leaks into creation.
With Watchdog-only enabled, create/search/filter only Watchdog tasks; expected: default creation is Watchdog and Watchdog validation applies.
With all five types enabled, each type can be selected, created, filtered, edited, and deleted.
Clear localStorage key dmh_enabled_task_types and reload; expected: all five current types are enabled by default.
Set dmh_enabled_task_types to invalid JSON in devtools and reload; expected: app recovers to safe defaults, no blank dashboard.
4.4 Universal Task Edit/Delete
For each task type that is enabled, create at least one task and verify:
Accordion opens and closes.
Title can be edited and saved.
Description can be edited and saved where present.
Start date/time can be changed to a valid future value.
Invalid required fields block Save/Run with visible errors.
Delete prompts for confirmation.
Cancel delete keeps the task.
Confirm delete removes the task and does not leave stale expanded/editing state.
Open a deleted task's stale URL/action if one is available from history; expected: graceful not-found/refresh, no crash.
Edit the same task in two tabs; save tab A, then save stale tab B; expected: either deterministic last-write behavior or visible conflict/error, never partial corruption.
Close accordion with unsaved changes; expected: confirmation or deliberate discard behavior.
Change task type on an existing inactive task; expected: confirmation modal, old type-specific fields are reset or migrated intentionally.
Cancel task-type change; expected: original type, subtasks, and metadata remain unchanged.
4.5 Task Icon Picker
Open a task edit form and click the icon button beside the title.
Expected: selected icon appears in the task row and persists.
Remove icon; expected: task returns to no-icon state.
Community tab: approved community icons load or an empty state is shown.
Upload tab: choose PNG/JPEG/WebP, preview appears, image is resized locally, selecting it updates only this task.
Upload unsupported or corrupt file; expected: visible non-crashing error.
Icon picker closes on close button, outside click, or Escape without changing the task unless an icon was selected.
5. Task Lifecycle Matrix
Run this matrix for Reminder, Watchdog, Challenge, and Personal Report where the controls are available.
Use the canonical statuses: INACTIVE, ACTIVE, IN_PROGRESS, COMPLETED, FAILED. The only valid status transitions are INACTIVE -> ACTIVE, ACTIVE -> IN_PROGRESS or INACTIVE, IN_PROGRESS -> COMPLETED/FAILED/INACTIVE, COMPLETED -> INACTIVE, and FAILED -> INACTIVE.
Starting state
User action
Expected result
Inactive
Save
Changes persist after reload
Inactive
Run
Status becomes Active or valid task-specific active state
Active
Deactivate
Status returns to Inactive
Active
Wait until due
Status moves through InProgress to Completed/Failed/rescheduled according to task type
Completed
Reopen
Status returns to Inactive
Failed
Deactivate
Status returns to Inactive
Also verify:
Any transition not listed above is hidden, disabled, or rejected with a clear error.
Status changes through the visible dropdown and through task-specific buttons follow the same rules.
Status changes made while offline either queue and sync cleanly or are blocked with clear copy.
The status filter updates immediately after a status change.
Active task displays countdown or scheduled time.
Completed task has a visually distinct completed state.
Failed task shows readable error details.
Refreshing the page does not duplicate tasks or lose saved changes.
A task due in the past is handled deterministically: either it reschedules, completes/fails, or shows a correction modal.
System clock/timezone changes do not make countdowns negative forever or fire repeatedly.
6. Watchdog Tasks
6.1 Configuration
Enable Watchdog task type in Settings if it is disabled.
Create a Watchdog task with a future start time.
Try start time in the past, now, exactly first-warning minutes ahead, and exactly first-warning-plus-one minutes ahead.
Expected: invalid boundary times are blocked; the minimum valid time can be saved and run.
Verify postpone period options are available.
Test all visible postpone options: 5 minutes, 10 minutes, hour, day, week, month, year where feasible.
Open Watchdog options and add an Email subtask.
Try to Run without required subtask fields; expected: validation blocks activation.
Fill Email recipient, subject, and content using a tester-owned inbox.
Save and reload; expected: subtask configuration persists.
Override per-task first/second warnings; expected: first warning must be greater than second and overrides persist.
Toggle postpone shift mode; expected: the next postpone uses the selected mode and survives reload.
6.2 Subtask UI And Validation
For each subtask type, add it, test required-field validation, save, reload, edit, and delete it.
Home Assistant: webhook, service, and event modes with JSON validation.
Provider execution checks:
Email end-to-end delivery is in scope if outbound email is configured and tester uses a disposable inbox.
API Trigger end-to-end is in scope if tester uses a safe webhook.site-style URL.
Telegram/SMS/SSH/Home Assistant end-to-end is optional and only in scope with tester-owned credentials/targets.
Without provider credentials, expected result is a clear validation or failure state, not a crash.
6.3 Subtask Chain Behavior
Use safe test targets only.
Single subtask fires once.
Two sequential subtasks fire in order.
Two parallel subtasks can both complete.
Failed subtask surfaces readable error on the parent task.
Deleting/reordering subtasks does not corrupt the saved chain.
Save a chain, reload, edit one subtask, save again, and verify unchanged subtasks keep their config.
Duplicate rapid Run/Force/Expire actions do not execute the same subtask chain twice.
6.4 Activation, Postpone, And Trigger
Run a valid Watchdog task.
Expected: status Active, countdown visible.
Reload while Active; expected: countdown resumes from persisted deadline.
Open in a second tab while Active; expected: both tabs agree on status/deadline after refresh.
Click the in-app postpone area/button.
Expected: deadline moves forward by the selected period and toast confirms.
Change postpone shift mode in Advanced settings; expected: saved setting affects the next postpone.
Trigger first-warning and second-warning local notifications with notification permission granted.
Repeat with notification permission denied; expected: in-app state remains usable and no repeated permission nag.
Let a short Watchdog expire in a safe test account.
Expected: subtask chain executes or task fails with visible provider error.
No duplicate subtask execution for one expiration.
Go offline while Active before expiry, then reconnect after expiry; expected: no duplicate execution and final status is clear.
Deactivate before expiry; expected: no warning/expiry/subtask execution after deactivation.
6.5 Forced Start Page
For an Active Watchdog, click Force.
Expected: navigates to /dashboard/forced-start/<task-id>.
Verify full-screen countdown, task summary, immediate force action, and postpone action.
Click postpone; expected: returns to dashboard and task deadline is extended.
Open forced-start page logged out; expected: redirect to login.
Open forced-start page as Account B for Account A's private task; expected: denied/not found.
Open forced-start page after the task is deleted/deactivated; expected: graceful error or redirect.
For invalid/non-existent id, expected: graceful error or redirect, no blank screen.
6.6 ESP32 Healthcheck Device And Firmware
Run hardware checks only if tester has an ESP32 board and permission to flash it.
Create a Healthcheck and open its ESP32 device section; PIR and mmWave sensor type options are visible.
Before task is saved, firmware/pairing controls are disabled or explain "save first".
After saving, firmware download URL is available.
Web Flash button appears only where Web Serial is supported.
Pairing modal issues a code and QR code.
Copy pairing code works.
Without hardware, record this section as Not Available, not failed.
With hardware, pair device, verify online/offline state, and verify a motion event re-arms the Healthcheck for its configured interval.
7. Reminder Tasks
7.1 Alarm Mode
Create Reminder → Alarm → One-time.
Enable/disable sound.
Try due time in the past, now, and one minute in the future; expected: correction modal or deterministic scheduling.
Run and wait for due time; expected: notification/toast/local notification according to browser permission, then Completed.
Daily repeat: select all weekdays, then a subset such as Mon/Wed/Fri.
Verify the UI prevents deselecting every weekday.
Pick a weekend start with Mon-Fri selected; expected: schedule aligns to the next selected day.
Create an overdue daily alarm by leaving the page until after several occurrences if feasible; expected: it catches up to the next future occurrence, not a past date.
Monthly repeat: use a safe future date; expected: next schedule keeps monthly cadence.
Yearly repeat: expected: next schedule keeps yearly cadence.
Edge dates such as Jan 31 or leap day are tested only if feasible; otherwise record Not Run with reason.
Change timezone after creating an Alarm; expected: displayed due time is understandable and the task does not fire twice.
7.2 Pomodoro Mode
Create Reminder → Pomodoro.
Verify work duration 1-120 min, break 1-30 min, long break 1-60 min, sessions before long break 1-10.
Try values below minimum, above maximum, blank, decimal, and non-numeric input; expected: clamped or validation error.
Enable working hours; expected: start/end selectors appear and end must be after start.
Start outside working hours; expected: task schedules to the next valid work period or explains why it cannot start.
Run a short-cycle Pomodoro using minimum durations.
Expected: work → break → work cycle is visible and reschedules rather than disappearing.
Reload during work phase and during break phase; expected: phase and current session are preserved.
Deactivate/stop returns it to an inactive or stopped state without duplicates.
Try empty and very long memorize content; expected: validation or readable saved display.
Run an intra-day task and verify current interval indicator advances after a due event.
Reload after each interval advancement; expected: repetition index/progress persists.
Switch format from multi-day to intra-day before Run; expected: progress resets intentionally.
After the final interval, expected: task completes.
7.4 Local Notifications And Offline Reminders
Grant notification permission when prompted.
Create an active reminder due soon.
Keep tab visible; expected: exactly one notification/toast when due.
Put tab in background; expected: reminder still fires within browser limitations.
Repeat with notification permission denied; expected: in-app state still completes/reschedules without browser notification.
Go offline, create or edit a Reminder if UI allows it.
Reload while offline; expected: local reminder state persists.
Go back online; expected: sync completes without duplicate tasks.
Clear localStorage after documenting state; expected: server-backed reminders reload, local-only fallback state is handled gracefully.
8. Challenge Tasks And Feed
8.1 Create Challenge
Enable Challenge task type in Settings.
On Dashboard, filter task type to Challenge.
Create a public Challenge with title and optional max participants.
Expected: task is created and can be opened.
Create a Challenge with max participants = 1, join as Account B, then try to join as Account C if available; expected: capacity limit is enforced.
Try max participants blank, zero, negative, decimal, and very large; expected: validation or safe normalization.
Create a private Challenge.
Expected: private Challenge is not visible to Account B through public feed.
Switch public/private before saving if UI allows it; expected: saved visibility matches final selection.
8.2 Feed And Leaderboard Slider
Open /feed while logged out.
Verify Templates and Articles tabs load or show empty states.
Verify top challenges slider loads entries or shows "no public challenges".
Open a challenge from the slider or feed.
Expected: /challenges/<id> loads.
Use show more/less on long feed items.
Copy/share link if visible; expected: copied URL opens the same item.
As logged-out user, click Clone; expected: auth-required behavior, not silent failure.
Open /feed as Account A and Account B; expected: public content is consistent and private content is not leaked.
Test empty feed/search/filter states if the environment has no public challenges.
Reload after scrolling/show-more state; expected: no duplicate cards or broken pagination.
8.3 Challenge Detail
Login as Account B and open Account A's public challenge.
Open the same challenge logged out; expected: stats/participants/report visibility matches public read-only rules and actions require auth.
Join challenge.
Expected: participants count updates and Account B appears in participant list.
Try to join the same challenge twice; expected: no duplicate participant.
Report completion with comment.
Expected: completion count and reports tab update.
Try to report before joining from a fresh account if possible; expected: blocked with clear error.
Try to report completion twice; expected: duplicate is blocked.
Leave challenge.
Expected: participant status updates.
After leaving, reports/votes for that user are removed or no longer counted according to visible UI.
If voting is visible, vote for another completed participant, remove vote, and verify counts.
Try to vote for yourself; expected: action hidden or rejected.
Try to vote for a non-completed participant; expected: action hidden or rejected.
On a private/non-public challenge URL obtained as Account A, Account B must not see stats, reports, votes, or participants.
9. Personal Report, Sharing, Contacts, And Comments
9.1 Contacts
Login as Account A.
Open /chat, switch to Contacts.
Search Account B by search tag; query below minimum length should not search.
Search by partial tag, exact tag, wrong discriminator, self tag, and unknown tag.
Expected: self cannot be added, unknown users show empty state, minimum length is enforced.
Send contact request to Account B.
Send the same request again; expected: duplicate pending request is blocked or idempotent.
Login as Account B in another browser profile.
Accept request; expected: both users see accepted contact.
Reject flow: Account A invites disposable Account C, C rejects, and A cannot send messages in that pending/rejected room.
Block flow: block a disposable user, then verify invite/search/message/share attempts are blocked or hidden.
Free-tier contact limit: if Account A already has one accepted contact, adding another should show clear limit/upgrade copy without payment completion.
9.2 Chat Rooms And Messages
Account A starts or opens chat with Account B.
Before Account B accepts, verify room is Pending and message input is disabled or guarded.
Send a message.
Expected: message appears for both users, persists after reload.
Account B replies.
Delete a message if control is visible; expected: deleted/removed state is reflected.
Pending invite room cannot send messages until accepted.
Disconnect network temporarily; expected: clear offline/retry state or fallback polling when reconnected.
Send empty, whitespace-only, very long, multiline, and Unicode messages; expected: validation or readable rendering.
Rapidly send the same message several times; expected: no UI lock and any rate-limit message is clear.
Open chat by direct /chat?room=<id> URL for valid, deleted, and non-member rooms; expected: select or deny safely.
On mobile, switch from room list to message area and back without losing draft text unexpectedly.
9.3 Task Sharing
Account A creates a normal task.
Share to Account B as WATCHER.
Expected: Account B sees shared task but cannot perform owner-only edits.
Share another task as ASSIGNEE.
Expected: Account B can perform allowed report/status actions but cannot change owner-only fields.
Account B accepts shared task message; expected: shared task appears in Dashboard shared filter.
Account B rejects or ignores a shared task if that control exists; expected: no shared task appears.
Share a task that is already shared with Account B; expected: no duplicate share row/card.
Delete the original task after sharing; expected: Account B loses access or sees a clear removed state.
Change Account B's role from WATCHER to ASSIGNEE via a new share if UI allows it; expected: final permissions match final role.
Remove share.
Expected: task disappears from Account B's shared list.
9.4 Comments
Add a comment to a shared task.
Expected: comment appears in order with author attribution.
Account B adds a reply.
Delete comment if visible; expected: deleted state is clear and no unrelated comments disappear.
9.5 Personal Report
Enable Personal Report task type.
Create Personal Report and share/assign it to Account B.
Owner view: Account A sees assignee and comment history but cannot submit assignee-only completion controls unless owner is also assignee.
Account B marks it Completed with a note.
Account A sees status and note.
Repeat with Failed status on a separate report.
Expected: repeated updates append or preserve history without data loss.
Account C/non-assignee opens shared links or dashboard references if available; expected: no access.
Long comment and empty comment states are handled without layout break or data loss.
10. Settings
10.1 Interface
Open /users/settings.
Switch tabs: Interface, Profile, Tasks.
Change language; expected: UI strings update and persist after reload.
Test English, Ukrainian, one long-label locale, and one RTL locale.
In each tested locale, revisit Dashboard, Feed, Chat, Donations, and Settings; expected: no clipped primary controls or unreadable directionality.
Change UI scale normal/compact; expected: page density changes and persists.
Change dark/light theme; expected: theme updates immediately and persists.
On mobile, tabs remain visible and usable.
Clear theme/language/scale storage and reload; expected: safe defaults.
Put invalid values into localStorage/cookies for theme/language/scale and reload; expected: fallback, not a crash.
Expected: first warning must remain greater than second; invalid ranges are prevented or show warning.
Set first warning to 5 and second to 2, save/reload, then create a Watchdog; expected: validation minimum uses first warning + 1 minute.
Set invalid localStorage for dmh_forced_start_delay and dmh_watchdog_warnings; expected: safe defaults and no settings crash.
Disable Challenge and Personal Report, reload, then re-enable both; expected: existing tasks are preserved and controls return.
10.5 Self-Block Language Option
Run only with disposable Account C.
Select the destructive self-block language option if visible.
Expected: account is blocked/logged out exactly as the UI warns.
Do not run this on Account A or B.
After block, login as Account C again if possible; expected: blocked state is clear and no Account A/B data is affected.
11. Backup Export And Import
11.1 Export
Login as Account A and open /backup.
Export with settings only.
Expected: ZIP downloads with a DMH backup filename.
Export with tasks included.
Expected: ZIP downloads and no browser error.
Export from an empty account and from an account with mixed task types/statuses.
Start export, navigate away/back, then export again; expected: no stuck loading state.
Verify the ZIP name/date is understandable and no private data is shown in the UI during download.
11.2 Import
Upload a non-ZIP file.
Expected: validation rejects it.
Upload a corrupted/renamed ZIP.
Expected: clear validation/import error, no partial UI crash.
Upload the exported ZIP into a disposable account or after documenting current state.
Expected: import reports created tasks/settings and does not crash.
Reload dashboard/settings; expected imported data appears as described by the import result.
Import settings-only backup; expected: task list remains unchanged while settings update.
Import tasks backup into a non-empty account; expected: duplicates/conflicts are reported or imported deterministically.
Repeat the same import twice; expected: no uncontrolled duplication without clear reporting.
Try import while offline; expected: blocked or recoverable error.
12. Donations
12.1 Summary
Open /donations logged out.
Expected: donation statistics/AWS cost area loads or shows graceful empty state.
Change language/timezone if available; expected: region-specific method visibility updates.
Repeat logged out and logged in; expected: payment method visibility is identical unless product copy explicitly differs.
Test C1, C2, C5, and C8 at minimum; expected: locale/RTL/mobile does not reveal hidden Stripe controls.
12.2 Current Payment Method UI
Verify Stripe is not shown as a selectable method.
Inspect all visible tabs/buttons/links on the page; expected: no visible Stripe checkout, Stripe card form, Stripe redirect button, or Stripe test-card instructions.
Ukrainian locale/non-onion: Monobank tab may appear.
If Monobank Jar URL is configured, button opens a send.monobank.ua/jar/... link in a new tab.
If Monobank Jar URL is not configured, expected: disabled/coming-soon state.
Non-Ukrainian locale: Monobank is hidden; Crypto remains available.
Onion/Tor mirror if provided: only Crypto should be visible.
Crypto tab shows BTC address and copy button.
Copy button writes address to clipboard or shows a non-crashing failure if clipboard is blocked.
Refresh after switching methods; expected: no hydration mismatch or wrong default tab.
Do not test Stripe checkout, Stripe redirect query params, webhooks, or test cards.
13. Report, Docs, Error Pages, And Exit
13.1 Feedback Report
Login and open /report.
Submit empty form; expected: submit disabled or validation blocks.
Submit subject over 120 characters or message over 4000 characters; expected: counter/limit prevents invalid submit.
Submit valid feedback.
Expected: success toast and fields clear, or clear error if feedback service is unavailable.
Submit twice rapidly; expected: one report or clear rate-limit/pending state.
Go offline before submit; expected: recoverable error and message text is not lost.
13.2 Documentation
Open /docs.
Open /docs/USER_GUIDE.
Verify headings, tables, code blocks, links, and anchors render correctly.
On mobile, tables/content do not overflow unusably.
Unknown doc slug shows not-found behavior, not a crash.
Test docs in English, Ukrainian, and one RTL locale; expected: readable content and navigation.
Open docs after offline cache warmup; expected: cached content or graceful offline fallback.
13.3 Exit Matrix
Open /exit.
Expected: consent step renders.
Continue button disabled until both checkboxes are checked.
After both boxes, continue to payment step.
Stop here. Do not click payment while Stripe is out of scope.
Manually open /exit?success=true; expected: unlocked visual state may render, but do not treat this as payment verification.
Open /exit logged out; expected: redirect to login.
Refresh during consent step and after reaching payment step; expected: no accidental unlock/payment action.
Browser back from payment step returns to consent/payment state without data leak or crash.
13.4 404 And Global Error
Open a definitely missing route such as /this-route-does-not-exist.
Expected: friendly 404 with a way home.
Navigate back to app; expected: no broken session.
14. PWA, Offline, Push, And Responsive
14.1 Installability And Service Worker
In Chrome, confirm manifest is detected and app is installable where browser supports it.
Install PWA if available; expected: standalone window opens and basic navigation works.
Reload installed PWA; expected: authenticated state and theme survive.
Clear browser cache/site data, then reinstall or reopen; expected: app returns to safe defaults and login works.
After deployment/update if tester is told a new build is live, reload PWA and browser tab; expected: no chunk-load blank screen.
14.2 Offline Behavior
While online, visit /, /dashboard, /docs/USER_GUIDE, /donations.
Switch devtools to offline.
Refresh each visited page.
Expected: cached/offline fallback is shown gracefully.
Switch online; expected: app recovers without manual localStorage clearing.
Expected: either queued/recovered behavior or clear blocked state; never silent data loss.
Repeat after clearing service worker/cache; expected: first-load offline state is understandable.
14.3 Push Permission
Grant notification permission from the app prompt or browser controls.
Subscribe to push if UI exposes the control.
Trigger a safe reminder due soon.
Expected: one notification, click focuses/opens the correct dashboard task.
Deny permission; expected: app does not repeatedly nag or crash.
Reset permission to default and reload; expected: prompt appears only at intentional moment.
14.4 Responsive Smoke
Run primary flows at:
Desktop 1440 x 900.
Tablet 768 x 1024.
Mobile 390 x 844.
Check:
Sidebar/navigation remains reachable.
Modals and full-screen overlays fit viewport.
Fixed banners respect iOS safe-area/notch.
Forms can be completed with touch keyboard open.
15. Limits, Access Control, And Privacy
15.1 Verification And Tier Limits
With unverified Account C, try restricted actions such as chat/sharing and multiple Watchdog tasks.
Expected: clear verification/limit modal or blocked action.
With verified Account A, verify allowed actions work within free limits.
Hit a known free limit only with disposable data; expected: paid-limit modal or clear upgrade/referral path.
Do not complete any payment from the modal while Stripe is disabled.
Verify unverified Account C can still create Reminder tasks if that is currently allowed.
Verify unverified Account C is limited to one total non-Reminder/Watchdog-style server task where the UI exposes that limit.
Verify verified free Account A is limited to three active Watchdog tasks, but can keep inactive Watchdogs if allowed.
Verify global client pre-checks show clear state near total/active limits only if the environment has sufficient disposable data; otherwise record Not Run with reason.
15.2 Ownership
Account A creates a private task.
Account B should not see it in dashboard/feed/chat unless explicitly shared.
Account B cannot open or mutate Account A's private task through visible UI.
Shared WATCHER cannot edit owner-only fields.
ASSIGNEE can only perform allowed report/status actions.
Account B tries direct URLs/actions copied from Account A for dashboard forced-start, challenge detail, chat room, and shared task references where available.
Expected: public data only for public challenges/feed; all private/owner data denied or not found.
After Account A deletes/removes share, Account B reloads; expected: access disappears.
15.3 Rate Limit Smoke
Do not attack the environment. Use light smoke only.
Make several wrong login attempts.
Expected: either normal invalid-credentials responses or clear rate-limit message after threshold.
Stop after rate limit appears; do not continue flooding requests.
16. Admin Icons
Run only if an admin test account is provided.
Open /admin/icons.
Expected: pending icon count and cards render.
Approve one safe pending icon.
Reject one safe pending icon.
Non-admin account should not be able to moderate icons.
Logged-out user is redirected or denied.
Non-admin direct URL access is denied without showing pending icon data.
After approve/reject, reload and verify the icon leaves the pending list and appears/does not appear in the community icon picker as expected.
If there are no pending icons, empty state is clear and approve/reject controls are not shown.
If no admin account is provided, mark this section Not Available.
17. Cross-Feature Regression Flows
Run these final end-to-end paths after individual sections.
Account A registers, verifies email, logs in, creates Reminder Alarm, receives notification, completes task.
Account A creates Watchdog with Email + API Trigger subtasks, postpones once, then lets it fire against disposable targets.
Account A creates public Challenge; Account B joins, reports completion, and appears in challenge detail.
Account A and B become contacts, chat, share a task as WATCHER, then as ASSIGNEE.
Account A changes language/theme/timezone, exports backup, logs out, logs back in, and settings persist.
Logged-out user can browse landing, docs, donations, feed, and challenge detail without seeing private data.
Mobile user can register/login, create a task, edit it, and navigate to settings without layout breakage.
Unverified Account C hits a restricted server-task/chat/share flow and receives verification/limit UI, while Reminder-only flow still behaves according to current product rules.
Account A creates data in desktop Chrome, edits in mobile browser, then verifies desktop tab recovers after refresh.
Account A creates an active Reminder and active Watchdog, goes offline before both are due, reconnects, and verifies final statuses with no duplicate notification/subtask execution.
Account B opens stale links after Account A deletes a shared task, leaves a challenge, and revokes a chat/share; expected: no private data remains visible.
With all five task types enabled, create one of each, export backup, import into disposable account, and verify settings/tasks survive reload.
With only Watchdog enabled, create/run/postpone/force a Watchdog; with only Reminder enabled, create/run an Alarm. Expected: no hidden disabled type leaks into creation.
18. Completion Checklist
The test run is complete when:
Every C1-C10 configuration is executed or has an explicit Not Available reason.
Every value in Mandatory State Axes has at least one Pass/Fail/Skip entry.
Every route in section 1 has Pass, Fail, or Skip with reason.
Every enabled task type has create, edit, run, and delete coverage.
Default, Reminder-only, Watchdog-only, and all-four task-type settings have each been tested.
Empty, single-item, mixed-list, long-text, duplicate-title, deleted/stale-id, and cross-account data states have each been tested.
Auth states cover logged-out, unverified, verified, revoked session, second tab, and second browser profile.
Watchdog has at least one real safe subtask execution or a documented environment reason why delivery could not be tested.
Reminder Alarm, Pomodoro, and Spaced Repetition each have at least one lifecycle test.
Reminder coverage includes notification granted/denied/default, due-past correction, reload during active timer, timezone change, and offline/reconnect.
Two-account social flows cover contacts, chat, sharing, and challenge participation.
Social coverage includes pending/accepted/rejected/blocked contacts, pending/active rooms, WATCHER/ASSIGNEE roles, duplicate invites/shares, and stale/deleted access.
Donations verify current visible methods and explicitly confirm Stripe is absent/out of scope.
Settings, sessions, passkeys, backup, docs, report, PWA/offline, and responsive checks are covered.
Locale coverage includes English, Ukrainian, one long-label locale, and one RTL locale.
Browser coverage includes desktop Chrome and at least one non-Chrome engine or mobile browser.
Storage coverage includes fresh profile, existing profile, cleared localStorage, and malformed localStorage recovery.
No Critical or High bug remains open unless the product owner explicitly accepts the release risk in writing.
All failures include: account used, browser/device, exact route, steps, expected result, actual result, screenshot/video, console errors, and whether the issue is reproducible.
19. Bug Report Template
Use this format for every issue:
### BUG-###
Severity: Critical | High | Medium | Low
Route:
Account:
Configuration ID:
Auth state:
Role:
Locale / theme / scale / timezone:
Browser / device:
Viewport:
Network / permissions:
Task-type settings:
Data state:
Preconditions:
Steps:
1.
2.
3.
Expected:
Actual:
Reproducible: Yes / No / Intermittent
Console errors:
Network errors/status codes visible in browser:
Screenshots / video:
Regression scope: Does it fail in other C-configurations?
Notes:
Severity guide:
Critical: data leak, account takeover, payment attempted unexpectedly, destructive action without confirmation, app unusable for all users.
High: core task/auth/watchdog/chat flow blocked.
Medium: feature works only with workaround, confusing validation, broken responsive state on common device.
Low: copy, minor layout, non-blocking polish.
20. Feature-State Coverage Matrix
Use this matrix as the final audit before closing the run. Each row must have at least one evidence link or bug id.
Empty/invalid/valid forms; duplicate registration; unverified login; verified login; logout; revoked session; two tabs; OAuth visible/cancelled if available; passkey success/cancel/not found
Dashboard shell
Empty list; mixed list; loading; server error if exposed; search no results; all filters; sidebar open/closed; mobile keyboard; compact scale; stale tab
Task settings
Default Watchdog+Reminder; Reminder-only; Watchdog-only; all types; invalid saved localStorage; final type cannot be disabled
Task CRUD
Long text; duplicate title; special characters; save; cancel; reload; delete cancel/confirm; stale deleted id; two-tab edit
Task lifecycle
INACTIVE, ACTIVE, IN_PROGRESS, COMPLETED, FAILED; every valid transition; invalid transition blocked; due past; due soon; timezone shift; offline/reconnect
Min/max values; invalid numeric input; working-hours on/off; work phase; break phase; long break; reload mid-cycle; stop/deactivate
Spaced Repetition
Multi-day; intra-day; empty/long content; interval advancement; reload after advancement; final completion; format switch
Watchdog
Min start boundary; warning override; global warnings; postpone options; shift mode; active reload; forced-start; expiration; duplicate prevention; deactivation before expiry
Watchdog subtasks
Email; SMS; Telegram; API Trigger; SSH; Home Assistant; required-field validation; save/reload/edit/delete; sequential; parallel; provider failure
Healthcheck ESP32/Web Serial
Unsupported browser; saved vs unsaved Healthcheck; firmware download; pairing code/QR/copy; hardware Not Available; paired online/offline; motion re-arms the configured interval