TidalTask is an ADHD-focused task management app built to help manage the unique challenges of ADHD. Created by Daniel Wedding (@DoctorNovus), it provides structured, supportive tools for day-to-day organization.
- Task scheduling — prioritize and organize tasks with due dates and repeating schedules
- Reminders — local and server-pushed notifications
- Tags & groups — filter tasks by custom labels or shared team groups
- Calendar view — week and day views with task occurrence tracking
- Priority levels — High / Medium / Low priority with visual indicators
- Announcements — in-app What's New feed for release notes
- Two-factor authentication — TOTP-based 2FA with AES-256-GCM encrypted secrets at rest
- Passkeys — WebAuthn passkey registration and login
- API keys — per-user API keys (stored as SHA-256 hashes) for programmatic access
- OAuth 2.0 — authorization server with PKCE support for third-party integrations
- MCP endpoint — Model Context Protocol endpoint at
POST /mcpfor AI assistant integration - Data portability — full GDPR Art. 20 data export
- Right to erasure — GDPR Art. 17 / CCPA-compliant account + data deletion
- PWA + native — installable as a web app or native iOS/Android app
| iOS | Android |
|---|---|
sequenced/
├── packages/
│ ├── app/ # React + Vite + Capacitor frontend
│ └── api/ # Node/Express backend
├── .habitat/ # Habitat deployment config (docker-compose + dockerfiles)
├── docker/ # Nginx config for production
└── .env # Root env vars (picked up by Habitat/Docker Compose)
- Node.js ≥ 22 and npm ≥ 10
- MongoDB running locally (or any MongoDB URI)
git clone https://github.com/DoctorNovus/sequenced.git
cd sequenced
npm installCreate .env in the repo root (used by the API in dev):
# Required
DATABASE_URL=mongodb://localhost:27017/sequenced
PORT=8080
SESSION_SECRET=<random 64-char string>
APP_URL=http://localhost:5173
FRONTEND_URL=http://localhost:5173
# 2FA — encrypt TOTP secrets at rest (AES-256-GCM)
TOTP_ENCRYPTION_KEY=<64-char hex string (32 random bytes)>
# WebAuthn / Passkeys
WEBAUTHN_RP_ID=localhost
WEBAUTHN_RP_NAME=TidalTaskFor email features (password reset, welcome emails):
RESEND_API_KEY=re_...
RESET_FROM_EMAIL=no-reply@yourdomain.com
WELCOME_FROM_EMAIL=no-reply@yourdomain.com
WELCOME_EMAIL_SUBJECT=Welcome to TidalTaskFor Discord webhook logging (optional):
UPDATES_WEBHOOK_URL=https://discord.com/api/webhooks/...cd packages/api
npm run dev # starts on http://localhost:8080In a second terminal:
cd packages/app
npm run dev # starts on http://localhost:5173The frontend auto-detects DEV mode and points to http://localhost:8080.
- A Linux server with Docker and Docker Compose installed
- A domain with DNS pointing to the server
- TLS certificates in
/etc/letsencrypt(e.g. via Certbot)
git clone https://github.com/DoctorNovus/sequenced.git /root/sequenced
cd /root/sequenced
npm installCreate .env in /root/sequenced:
# Required
DATABASE_URL=mongodb://mongouser:mongopassword@mongo:27017/sequenced?authSource=admin
SESSION_SECRET=<random 64-char string>
APP_URL=https://api.yourdomain.com
PORT=8080
FRONTEND_URL=https://yourdomain.com
# 2FA encryption — generate once and keep secret
TOTP_ENCRYPTION_KEY=<64-char hex string (32 random bytes)>
# WebAuthn / Passkeys
WEBAUTHN_RP_ID=yourdomain.com
WEBAUTHN_RP_NAME=TidalTask
# Email (Resend)
RESEND_API_KEY=re_...
RESET_FROM_EMAIL=no-reply@yourdomain.com
WELCOME_FROM_EMAIL=no-reply@yourdomain.com
WELCOME_EMAIL_SUBJECT=Welcome to TidalTask
# Discord webhook logging (optional)
UPDATES_WEBHOOK_URL=https://discord.com/api/webhooks/...Note: If
TOTP_ENCRYPTION_KEYis set, the API automatically migrates any plaintext TOTP secrets to AES-256-GCM on startup. If it is not set and users have 2FA enabled, a warning is logged.
Edit docker/nginx/conf.d/ to match your domain and certificate paths. The stack includes an Nginx reverse proxy that routes:
yourdomain.com→ frontend (port 80 internally)api.yourdomain.com→ API (port 8080 internally)
npm run deployThis runs habitat build && habitat start — builds Docker images locally and starts all containers (API, frontend, MongoDB, Nginx). Use this for local testing of the full stack.
For production, images are built in CI and pushed to GHCR — the server just pulls them:
docker compose pull
docker compose up -d --remove-orphansnpm run habitat:build # build images only
npm run habitat:start # start containers
npm run habitat:stop # stop containersPush to main to trigger the deploy.yml workflow:
build-images— buildssequenced-apiandsequenced-frontendDocker images and pushes them to GHCR (using layer caching for fast rebuilds)deploy-server— SSHs into the server, pulls the new images from GHCR, and restarts containersios-release— builds the iOS app and submits to App Store (runs in parallel with the server deploy)
Required GitHub secrets:
| Secret | Description |
|---|---|
DEPLOY_SSH_KEY |
Private SSH key for the server |
GHCR_PAT |
GitHub PAT with read:packages scope — used by the server to pull images from GHCR |
Required GitHub variable:
| Variable | Description |
|---|---|
VITE_API_URL |
API base URL baked into the frontend at build time (e.g. https://api.tidaltask.app) |
- macOS with Xcode and Xcode Command Line Tools
- Ruby ≥ 2.6 and Bundler (
gem install bundler) - An Apple Developer account with a distribution certificate and provisioning profile
- An App Store Connect API key (Key ID, Issuer ID, and
.p8file)
Create packages/app/.env.asc.local (gitignored):
ASC_KEY_ID=XXXXXXXXXX
ASC_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Provide one of:
ASC_KEY_PATH=~/private_keys/AuthKey_XXXXXXXXXX.p8
# or base64-encoded content of the .p8:
# ASC_KEY_CONTENT=$(base64 -i AuthKey_XXXXXXXXXX.p8)Install Ruby gems:
cd packages/app
npm run fastlane:setupcd packages/app
npm run open:ios:full # builds web, syncs Capacitor, opens XcodeBuilds the app, auto-increments the build number against the latest TestFlight build, and uploads:
npm run upload:ios:ascSame as above but also waits for processing and submits directly to App Review with auto-generated release notes from git commits:
npm run release:ios:ascThe ios-release job in deploy.yml runs on every push to main. Required secrets:
| Secret | Description |
|---|---|
ASC_KEY_ID |
App Store Connect API key ID |
ASC_ISSUER_ID |
App Store Connect issuer ID |
ASC_KEY_CONTENT |
Base64-encoded .p8 API key content |
Signing is handled automatically by Xcode (-allowProvisioningUpdates) — no certificate or provisioning profile secrets needed.
All platform version files are updated in one command:
cd packages/app
npm run bump-version 3.2.0This updates:
| File | Field |
|---|---|
packages/app/package.json |
"version" |
ios/App/App.xcodeproj/project.pbxproj |
MARKETING_VERSION (both build configs) |
android/app/build.gradle |
versionName + versionCode (e.g. 3.2.0 → 30200) |
- GDPR Art. 13/17/20/32 and CCPA — users can export or permanently delete all their data from the app settings; see Privacy Policy and Terms of Service
- TOTP secrets are encrypted with AES-256-GCM at rest; plaintext secrets are migrated automatically on first server startup after
TOTP_ENCRYPTION_KEYis set - API keys are stored as SHA-256 hashes — raw values are shown only once at generation time
- Session cookies are
httpOnly,secure(production),sameSite: lax - Security headers —
Strict-Transport-Security,X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy,Permissions-Policy - Auth rate limiting — 20 failed attempts per 15 minutes on login, register, and password reset endpoints
Questions, feedback, or bug reports: support@tidaltask.app