Engineering
Why We Built MinuteShark as a Keyboard-First Ionic App
A keyboard-first time tracker is not a shortcut cheat sheet. It is a product that assumes the consultant’s hands are already on the keys when they remember the work. If starting a timer requires hunting a nested menu, the clock loses to the next Slack ping.
What we optimized the web app for: type into the giant search — “Search anything or start a task” — get instant results, create a Client / Project / Task from the same field if it does not exist, and hit play. The mouse is allowed. It is not the happy path.
This is an engineering post about that constraint. MinuteShark’s web client is an Ionic + Angular app. We treated the dashboard search as the primary keyboard surface, not as a find-box bolted onto a click-heavy tree. Search uses embeddings so results feel instant and relevant. We did not invent a second “power user mode.” The same field that finds work also starts it.
Why consultants lose to the pointer
Freelance developers and independent consultants do not live in the tracker. They live in an editor, a design file, a call. The moment they decide “this is Homepage mockups, not Internal/admin” is rarely the moment they have a free hand for a sidebar safari.
Enterprise project tools solve that with process: pick a space, pick a board, pick a card, then maybe start a clock if the marketplace plugin loaded. That is a department workflow. Our primary audience is one person with three clients before lunch. If the path is Client folder → Project → Task row → overflow menu → Start, they will skip it and reconstruct Friday from memory.
Keyboard-first, for us, means the object they can always reach is a text field. Type the leaf work. If search already knows the task, play. If it does not, the same field offers create badges so you are not dumped into a wizard. That story has its own product post — why search should create work, not just find it. This one is the platform choice underneath: Ionic’s web shell, Angular 16, and a search index that is allowed to be the command line.
Ionic was a constraint, not a costume
We ship one product across web, iOS, and Android. Capacitor wraps the mobile builds. Ionic gives us a component language that does not fork the information architecture: Workspace → Client → Project → Task → Subtask, time on the task. The web app is still a real browser app. Consultants live in Chrome and Safari all day. Pretending the “real” product is only native would strand the people who start timers between commits.
Ionic apps can become tap-first by default — big cards, low information density, every action behind a sheet. That is fine for a consumer checklist. It is hostile if your user already thinks in names: “Contoso / Website Redesign / Homepage mockups.” A keyboard-first Ionic app means we keep the giant search as the first-class control, keep filter chips like SEARCH IN PROJECT for when the catalog is noisy, and keep play on the result row so a match is one motion from “I found it” to “it is running.”
We did not document a secret Emacs layer. We do not claim chorded shortcuts we have not shipped. The honest keyboard path is: focus the search, type, choose, play. If you need the long form later — History for a manual entry, Reports for What × Who × When — you can leave the keys. The start of the day should not require that.
One running timer, even when you type fast. Keyboard speed is useless if it starts a second clock. MinuteShark allows one running timer. Search play replaces or starts that single object. The sidebar still shows elapsed time, start time, and the client / project / task. The tab title can mirror duration + task name. Fast input does not get to fork the ledger.
Search is the index. The field is the UI.
Instant search is a product promise, not a brand name we wave at customers. Internally, search is why typing three characters of a task name should not feel like a SQL round-trip through a spinner. Consultants forgive a report that takes a second. They do not forgive a start-clock field that thinks.
The index has to stay honest with the hierarchy. A task named “Homepage” under two clients is not one row. Results have to carry enough client and project context that play does not land on the wrong leaf. Create-from-search has to respect the same model: you are adding a client, a project, or a task — not a free-floating note pretending to be work. Time still belongs on a task. Search cannot invent a place to hang an entry that the rest of the app cannot report.
That is also why we did not make the search box a general chatbot. MinuteShark AI is a separate surface (sparkles on web, full chat on mobile) that proposes actions and waits for a confirmation card. Mixing “find Homepage” with “log 90 minutes yesterday” in one unreviewed keystroke is how you get silent writes. We refuse that. Type to navigate and start. Chat to propose. Confirm to mutate. Different jobs.
The loop we protect
Focus search. Type the work you are actually doing. Play if it exists. Create the missing Client / Project / Task from the same field if it does not. One timer runs. If you forgot to start it, do not invent a keystroke that guesses — use History or ask MinuteShark AI, edit the card, confirm.
Widgets stay optional: starred tasks, a private notes widget, to-do lists that can play a timer, Pomodoro as a focus clock. They are not the command line. Search is. Details live in the dashboard widgets guide.
What we refused to keyboard-accelerate
Deletes, moves, and bulk onboarding can be said to the assistant. They still land on a proposal card. A keyboard-first app that lets you destroy a client with an unconfirmed chord is not faster. It is reckless. The same rule applies to invoices and rounding: those are report and settings paths, not search toys. Rounding stays off by default. Original duration stays stored. Search play should never silently apply a 6-minute bump.
We also refused to make the web app a poor clone of a desktop IDE. Consultants already have too many palettes. Our job is a daily time OS: start the right leaf, see the day, generate a report, turn it into an invoice from a cost profile. Keyboard-first means that OS does not punish people who type. It does not mean we hid billing behind vim.
Mobile is the other half of the same product, not a different philosophy. Voice input on iOS and Android exists because your hands are not on a keyboard in a hallway. The web keyboard path and the mobile voice path are both answers to “the moment I did the work and the moment I can navigate the chrome rarely line up.” Same workspace. Same confirmation rule for AI writes. Different input.
If you are building a tracker, steal the constraint
Put a text field where a department product puts a board. Index names you can speak out loud. Create from the miss, do not lecture. Keep one clock. Do not let speed skip confirm on mutations. If you want the onboarding sequence in human language, it is still Add Client → Add Project → Add Task → Start Task — the getting started path, just reachable from keys.
MinuteShark is built for consultants, not departments. The keyboard-first Ionic app is how we keep that honest on the web: fewer clicks between “I’m on Homepage mockups” and a timer that will survive the next context switch. Feature list if you want the rest of the surface area: features.