# DoTo Manual

> DoTo — Task Manager, Simple. A ridiculously fast, light and powerful task
> manager that lives entirely in your browser. No account, no server, no build step.
>
> Live app: <https://doto.arazgray.com/>

## Contents

- [Getting started](#getting-started)
- [Sync and settings](#sync-and-settings)
- [Views](#views)
- [Tasks](#tasks)
- [Notes](#notes)
- [Trash](#trash)
- [Reminders](#reminders)
- [Search, filters and sorting](#search-filters-and-sorting)
- [Keyboard shortcuts](#keyboard-shortcuts)
- [Command palette](#command-palette)
- [Time tracker](#time-tracker)
- [Import and export](#import-and-export)
- [Installing the app](#installing-the-app)
- [Hosting it yourself](#hosting-it-yourself)
- [Data and privacy](#data-and-privacy)
- [FAQ](#faq)

## Getting started

1. Open <https://doto.arazgray.com/> in any modern browser.
2. You start with one list, **General**, holding a single **Example Task** with every field filled in — open it, then delete it when ready.
3. Click the menu button (top left) to open the sidebar — or on touch screens,
   drag right starting in the left half (this also works in Board view when
   the columns are scrolled fully left) — then **Create new list** for your own categories.
4. Type in the **Add a task** bar and press Enter. Done — that is 90% of the app.

Everything is saved automatically in your browser as you type.

## Sync and settings

By default your data lives only in this browser. **Sync & Settings** (blue
button at the bottom of the sidebar, or the status pill in the top bar)
connects your Google Drive for multi-device sync — still with no DoTo server:

1. Open Sync & Settings and press **Sign in with Google** (the app ships with
   its own client ID — no setup needed; only repo forks need their own, see
   [Hosting it yourself](#hosting-it-yourself)), then **Sync now**.
2. From then on: changes upload automatically a few seconds after you make
   them, and the app pulls on launch, when the tab regains focus, and when
   you come back online.

How it works and what to expect:

- The synced copy is a single file in Drive's hidden app folder — only your
  Google account can see it.
- Merging is per item: edits made on one device at a time always merge
  cleanly. Reordering a list, or both devices marking the same task complete,
  never counts as a conflict.
- Deletes sync too. The navbar pill shows `Not synced yet`, `Syncing…`,
  or `Synced Xs ago`.
- If the same task, list, note, trash item, time record, or label was edited
  on two devices between syncs (or edited on one side and deleted on the
  other), the newest version applies immediately — then a dialog shows each
  conflict with a field-by-field diff (due date/time shown as one "Due" row;
  hover any value for the full text) so you can keep your version or take
  Drive's. The choice is per whole item, pre-selected to whatever is showing
  now. **Later** dismisses the dialog without changing the applied version
  (it stays queued until you review it or the next sync). Plain settings
  (label renames, your name, Home layout) always take the newest version
  without asking.
- Signing out keeps a full copy on that device; signing back in merges it.
- **Pull to refresh**: on touch devices, drag down from the very top of any
  page and release to force a Drive sync.
- Sync tab → **History** shows a log of recent sync events (pushes, pulls, conflicts, errors).
- The dialog is split into tabs: **Sync** (account, name, sync controls),
  **Labels** (rename + custom labels), **Home** (which Home sections
  show), **Options** (show completed, dark mode), and **Data**
  (JSON backups, Google Tasks import). Your **name** is used in the Home
  greeting and synced across devices.

## Views

| View | What it is for |
| ---- | -------------- |
| **Home** | Greeting, stat cards (open / overdue / due today / completed / tracked today), today's weather, a daily quote (tap refresh for a new one), a Pinned notes section (editable inline), a Notifications section for fired reminders, and sections: Overdue, Today's tasks, Highest priority first, Heavy lifting. The Home sidebar row carries a red badge counting unseen notifications — tapping Home marks them read. Which sections appear is configurable under Sync & Settings → Home. |
| **List** | One category at a time: add bar with quick presets, open tasks, collapsible Completed section. |
| **Board** | Kanban columns — one per list. Drag tasks between columns, add per column, reorder columns by their grip. |
| **Calendar** | Month grid with task chips, a Year overview with busy dots, and a day agenda with its own add box. Drag a task onto a day to reschedule it. |
| **Time** | Stopwatch per task (play / pause / stop). The timer survives reloads. |
| **Notes** | Google Keep-style quick notes: title + text, label colors, pinning, and a flag to show a note on Home. |
| **Trash** | Deleted tasks and notes, restorable or deletable forever. The Trash button is the delete icon next to Sync & Settings at the bottom of the sidebar. |

Switch views from the sidebar, the command palette, or press `g` then `h` / `b` / `c` / `t` / `n` (Notes) / `r` (Trash).

## Tasks

- **Create**: the add bar (or per-column / agenda boxes), the Home **New**
  button, the `n` key, or the command palette (`Ctrl+K`).
- **Complete**: the circle on the row, or select it and press `x`. Completed-by-mistake items can be undone from the toast popup; deleted items go to [Trash](#trash) and can be restored from there.
- **Details**: click a row (or select + `Enter`) for notes, due date + time, repeat rules, label, weight, priority, external reference (URL or ticket number), list assignment and subtasks. On mobile the panel slides up as a bottom sheet. Everything saves as you type; **Save** closes the panel and forces a sync push, while **Mark complete** toggles completion.
- **Rename inline**: double-click the title.
- **Labels**: tap the label dot on the row. Labels carry your own names, and
  you can add fully custom labels too (Sync & Settings → Labels, e.g.
  red for Home, blue for Work, a new teal for Side projects). Any label can
  be deleted when no task uses it (otherwise the app tells you to change
  those tasks first); built-ins can be restored with Reset. Custom labels
  and names sync, export and import alongside everything else.
  **Weight / Priority**: tap the badges on the row.
- **Move**: drag onto another task, board column, sidebar list or the empty list area — or the move button on the row (desktop), or the List selector in details.
- **Repeat**: daily, weekly (optionally on chosen weekdays), monthly, yearly, or custom "every N days/weeks/months/years". Repeating tasks appear on every matching day in the Calendar (computed forever — daily ones show every day at their time; picking Daily hides the date field and keeps only the time). Completing a dated repeating task schedules the next occurrence and resets its subtasks.
- **Subtasks**: in the details panel, with a `done/total` progress badge on the row.
  The first few subtasks also show under the task title everywhere — tap one to toggle it.
- **Delete**: the trash icon on the row, `Del` on a selected task, or the list
  menu's Delete options. Deleted tasks are not gone — they move to
  [Trash](#trash), with an undo toast right after.

## Notes

Keep-style quick notes for anything that is not a task. Open **Notes** from
the sidebar (`g` then `n`):

- **Create**: title + text at the top, pick a label color, press Add note
  (or the palette's New note command). The text box starts tall (160px) and
  stays resizable.
- **Organize**: tap the pin to keep a note on top (Pinned section). Tap the
  color dot on any note row to recolor it without opening it. Search filters
  notes by title and text.
- **Show on Home**: tap the home icon and the note appears in the Pinned
  notes section on Home — **before** Notifications — where both title and
  text stay editable inline.
- **Edit**: click a note row for the full editor (title, text, color, pin,
  show-on-home, delete).
- Notes sync, export and import alongside everything else.

## Trash

Deleting a task (single, completed-bulk, or a whole list's tasks) or a note
moves it to **Trash** instead of erasing it — open it via the delete icon
next to Sync & Settings at the bottom of the sidebar:

- Each entry shows what it was and when it was deleted, with **Restore**
  (tasks return to their list, or General if that list is gone) and
  **Delete forever**.
- **Empty trash** permanently deletes everything after a confirmation (still
  undoable from the toast right after).
- The trash holds the last 300 deleted items; older ones fall off automatically.

## Reminders

Open Details → Reminder and pick how far in advance: 1 or 5 or 30 minutes,
1 or 3 hours, or 1 day. The reminder counts back from the due date + time
(a dateless time defaults to 9:00 AM); without a due date there is nothing
to count back from.

Sign in with Google (the same **Sign in** as sync) and reminders run in the
background — no extra Calendar setup. The app keeps a dedicated **"DoTo"**
Google calendar for them (created automatically; if your reminders previously
fell back to your main calendar, one Sync now moves them over). The event updates when you edit the
task and disappears when you complete or delete the task, or switch the
reminder off. Moving the due date moves the reminder with it, and
completing a repeating task carries the reminder to the next occurrence.

Once a reminder's time passes it also shows up in the **Notifications**
section on Home — the Home sidebar row carries a red unread badge, and
tapping Home marks everything read and clears the app-icon badge.

Timed tasks are timezone-aware: a due time entered in one timezone shows
converted to local time on your other devices (e.g. 5:00 PM entered in
Istanbul shows as 5:30 PM in Tehran) and reminders fire at the same moment
everywhere. Date-only tasks stay on the same calendar day on all devices.
Tasks created before this behavior need one re-save of their date/time on
the device where the time is correct.

## Search, filters and sorting

- **Search** (`/`): matches titles, notes, references and subtasks across every view. Searching from Home jumps straight to Board results. Notes have their own search box on the Notes page.
- **Filters**: label, weight and priority in the sidebar. Active filters show as removable chips on every view.
- **Sorting**: My order (manual drag order), Date, Priority & weight, Title — from the sort button in the top bar.

## Keyboard shortcuts

Shortcuts work when you are not typing in a field. Press `?` anywhere to see this list.

| Keys | Action |
| ---- | ------ |
| `Ctrl+K` (or `Cmd+K`) | Command palette |
| `/` | Focus search |
| `n` | New task |
| `j` / `k` | Select next / previous task |
| `Up` / `Down` | Move selection (once a task is selected) |
| `Enter` | Open selected task |
| `x` | Complete / reopen selected task |
| `Del` | Delete selected task (undoable). On Mac this is the Delete key (sends Backspace). On Windows/Linux only the Delete key deletes — Backspace does not. |
| `g` then `h` | Go to Home |
| `g` then `b` | Go to Board |
| `g` then `c` | Go to Calendar |
| `g` then `t` | Go to Time tracker |
| `g` then `n` | Go to Notes |
| `g` then `r` | Go to Trash |
| `g` then `1`–`9` | Jump to list by position |
| `u` | Show / hide completed tasks |
| `d` | Toggle dark mode |
| `?` | Shortcut help |
| `Esc` | Close panel / dialog |

## Command palette

Press `Ctrl+K` (or `Cmd+K` on Mac) — it works even while typing. Start typing to filter:

- **Commands**: jump to any view (including Notes and Trash), new task / new note / new list, sorting, theme, import / export, this manual.
- **Lists**: jump straight to a list.
- **Tasks**: jump straight to a task's details.

`Up`/`Down` + `Enter` to run, `Esc` to close.

## Time tracker

1. Pick a task from the searchable list (each shows its total tracked time).
   (On desktop, the timer button on a task row jumps here pre-selecting it.)
2. Press play. Pause holds the clock, stop saves a record.
3. Records group under Today / Previously and can be deleted (undoable).
   **Copy day** next to Today copies the whole day as text, e.g.
   `5h - Write report` per line.
4. The running timer keeps going across page reloads — the total on Home counts it live.

## Import and export

- **Export** (Sync & Settings → Data → Export): downloads `doto-export-YYYY-MM-DD.json` with lists, tasks, notes, trash, time records and labels. Back these up — your data lives in this browser plus, if enabled, your Drive sync copy.
- **Import** (same tab, multi-select): pick the source — **Auto-detect**,
  **DoTo backup**, or **Google Tasks** — then choose files. Accepts DoTo exports
  (appended as new lists; notes and trash merge by id, so re-importing your own backup is a no-op instead of doubling everything) and Google Takeout Tasks exports (full backups, per-list files, or bare arrays). Starred Google tasks become high priority, links become external references, parents become subtasks, recurring series collapse to one repeating task.

## Installing the app

DoTo is installable (PWA) and works offline once installed:

- **Desktop Chrome / Edge**: install icon in the address bar, or menu → Save and share → Install.
- **Android Chrome**: menu → Install app / Add to Home screen.
- **iPhone / iPad**: Share → Add to Home Screen for a fullscreen icon on your home screen.

Installing requires the hosted `https://` address — it does not work from a downloaded `file://` copy.

## Hosting it yourself

DoTo is static — no server, no build step. Fork it and host it anywhere:

1. **Fork** the repo at <https://github.com/arazgray/doto> (or download it).
2. **Serve it**: in your fork go to Settings → Pages → Deploy from a branch
   → `main`, folder `/ (root)`. Your copy lives at
   `https://<you>.github.io/doto/`. Any static host works the same.
3. **Use it as-is** — everything except Google Drive sync works immediately.
   Sync needs its own client ID, because the shipped one only accepts the
   original site's address (Google answers other origins with an
   origin-mismatch error).

### Your own Google client ID (for sync on your host)

1. Open <https://console.cloud.google.com/> and create (or pick) a project.
2. **APIs & Services → Library**: find and **Enable** the **Google Drive API**
   and the **Google Calendar API** (one sign-in covers sync + reminders).
3. **APIs & Services → OAuth consent screen**: choose External, fill in app
   name + support email, and add these five scopes:
   - `https://www.googleapis.com/auth/drive.appdata`
   - `https://www.googleapis.com/auth/userinfo.email`
   - `https://www.googleapis.com/auth/calendar.events`
   - `https://www.googleapis.com/auth/calendar.calendarlist.readonly`
     (`calendar.events` alone cannot call `calendarList.list` — without the
     readonly list scope every calendar lookup answers 403
     `ACCESS_TOKEN_SCOPE_INSUFFICIENT`.)
   - `https://www.googleapis.com/auth/calendar.app.created`
     (lets the app create its own secondary "DoTo" calendar via
     `calendars.insert` — without it reminders fall back to your main
     calendar.)
    - Publish the project if prompted (Production mode) so sign-in stays
      persistent — Testing mode limits sign-in to listed users and expires
      about weekly. The shipped app at <https://doto.arazgray.com/> already
      runs in Production, so it stays signed in; forks should publish too.
4. **APIs & Services → Credentials → Create Credentials → OAuth client ID** →
   application type **Web application**. Under **Authorized JavaScript
   origins** add your exact site address, e.g. `https://<you>.github.io`
   (address only, no path at the end), then Create and copy the client ID
   (it ends with `.apps.googleusercontent.com`).
5. In your fork, paste it into `app.js` as `GOOGLE_CLIENT_ID` (top of the
   sync section), commit and push. Bump the release trio as usual (`?v=`
   stamps in `index.html`, `APP_VERSION`, `version.json` — all the same
   `1.0-<unix time>`) so installed copies pick up the update.
6. Open your hosted copy → Sync & Settings → Sign in with Google → Sync now.

That is all — sync data moves only between your browser and your own Drive;
there is still no DoTo server involved.

## Data and privacy

- All data lives in your browser's `localStorage` (`doto-v1`): lists, tasks, notes, trash, time records, view, filters, label names, your name, Home layout and panel sizes. Sync metadata (`doto-sync`), sync history (`doto-sync-log`), notification read state (`doto-notif-seen`), theme (`doto-theme`) and weather location (`doto-loc`, 7-day cache) are stored separately. With Drive sync enabled, an additional copy lives in your Drive's hidden app folder.
- If a save ever fails validation (corrupted data), the app keeps a timestamped backup copy in your browser and starts fresh instead of breaking.
- The network requests the app itself makes: Google Identity Services + Drive API (only when you use sync), and the Home weather card (Open-Meteo, BigDataCloud, ipapi.co for location fallback). Fonts and icons ship with the app and work offline. Nothing else ever leaves your device.

## FAQ

**I lost my tasks after clearing browser data — can I get them back?**
Only from a JSON export or your Drive sync copy (re-sign-in re-pulls it). Export regularly.

**Does it sync between phone and desktop?**
Yes — via Sync & Settings (Google Drive). Sign in on each device and both stay merged.
The OAuth client runs in Production, so the grant persists — there is no
weekly expiry and no background refresh loop. The app reuses its token and
renews it silently on demand whenever Drive/Calendar answers 401; if that
silent step is refused (notably iOS home-screen WebViews), just tap Sync now
once to re-auth.

**Can I share a list with someone?**
Not yet — export the JSON and send them the file; they can import it.

**Sync keeps asking me to sign in, or says "Sync failed".**
Most common cause: the Google Drive API is not enabled for your Cloud project
(Drive answers 403) — enable it under APIs & Services, then Sync now. Also
make sure you ticked the Drive checkbox on Google's consent screen and that
sign-in popups are not blocked. A "timed out" failure means the Google window
never reported back — finish it instead of closing it early, allow popups for
this site, and allow third-party cookies for `accounts.google.com` (without
them the login cannot return to the app). If the Google window opens and closes with
nothing happening, allow popups for this site and try again — the exact
reason is recorded under Sync → History. That History page also has a
**Copy diagnostics** button: if sync looks wrong (e.g. pill says sign-in is
needed while the dialog shows you signed in), open it right after the failure
and send the text — it shows token state, last sync and recent events.

**Calendar says "needs its permission" and Sync now does nothing / nothing appears in Google Calendar / reminders land in the main calendar instead of "DoTo".**
Only tasks with Details → Reminder set create events (in the "DoTo" Google
calendar, or your main calendar if creation is not allowed) — dateless tasks
need a due date first. If you signed in before a Calendar scope was added,
tap Sync now once to re-grant it (allow the popup and tick the Calendar
checkboxes — "DoTo" needs the list + app-created scopes, not just events).
"Google Calendar API is off" means enabling the API in your Cloud
project, then Sync now. Calendar errors also show inside Sync & Settings and
under Sync → History.

**The weather card is empty.**
It needs location permission (or IP-based fallback) and internet. Everything else works offline.

**Does the Update button refresh the styles (CSS) too?**
Yes. Update unregisters the offline worker, wipes the whole offline cache
(styles included), and reloads with a one-time URL so no cached page can
survive — then the page pulls its stylesheet, script and fonts under fresh
per-release URLs. The only requirement is that a release bumps those URLs,
which is part of the normal release step.

**My phone shows an old version of the app.**
Open the app with internet — it checks for updates on launch and shows an
**Update** button when one is ready. To force it any time: sidebar bottom row
→ **Update** wipes the offline cache and reloads the newest version. If the
update toast keeps coming back instead of finishing, it escalates by itself:
after two tries the button becomes **Full refresh**, which does the same
cache wipe. Every step is logged under Sync → History. If it
stays stuck (iOS has no hard-refresh), remove the home-screen icon and re-add it.

**Where do I report a bug or ask for a feature?**
Open an issue at <https://github.com/arazgray/doto/issues>.
