You can go back at any step and undo the final result.
There's also an option to clarify in a single step (sometimes things are clear from the start).
We used XState to design the state machine that manages the whole process.
You can go back at any step and undo the final result.
There's also an option to clarify in a single step (sometimes things are clear from the start).
We used XState to design the state machine that manages the whole process.
In #GTD, clarifying is the moment when you think, decide, and transform everything your personal inbox into specific, actionable items.
It's a mental process that gives you control by answering a series of questions.
We've implemented the entire process in the new version of FacileThings:
replicache's sync: In the PULL process you return 4 "put" keys for each database record. The PUSH one remains the same (client mutators need to update several local records at once for local consistency).
Of course, you only do this with certain critical tables (just 2 in our case).
you need more code to update/delete split records, but replicache executes mutations with atomic transactions. in return, you get much faster readings.
IndexedDB is slow at extracting thousands of records with tens of data points, and using spinners would ruin a local-first application. ๐
Itโs working for me
In our case, conflicts are managed by Replicache (replicache.dev), the library we use to sync with the external database.
Yes, each mutator updates all the keys involved (which depends on the fields updated). This ensures consistency in the app if itโs offline.
Yes, you need more space and there's data duplicated, but the speed might be unacceptable and the trade-off is well worth it.
This is one of those decisions that feels like over-engineering early on, but local-first apps live or die by how well you model your local store.
So we added two more keys for each task in the sync process:
- "tasks/s/:state/:id" โ tasks by state, with the needed fields is this case
- "tasks/p/:project_id/:id" โ tasks by project, with the needed fields
Need all the tasks of project 125? Just fetch "tasks/p/125/".
Getting all the records every time can be slow, even with local data (problem 2). Over the years, users accumulate thousands of tasks.
But you rarely need to get all the tasks. Now you need to think about how you access the data. In our case, it's usually by state, and by project.
- "tasks/c/:id" โ core fields (title, state, due date, projectโฆ) - "tasks/d/:id" โ detail fields (notes, attachments...)
Want to show cards? You only need to fetch "tasks/c/". Need to edit the whole task? Then you fetch both keys. Pay only for what you use.
When you're listing hundreds of tasks in a view, you're loading notes, descriptions, attachments, metadata... stuff you don't need yet. That's a fat row problem (problem 1).
Here's how we solved it in FacileThings: split each task into two canonical keys:
One of the first things you'll face building a local-first app is how to structure your key-value store so you're not pulling more data than you need.
The standard approach is one key per record ("tasks/:id"). It worked. Until it didn't.
We had to solve two problems. ๐งต
There's a moment in building a product where you stop adding features and start connecting them.
This week was one of those: no new concept, just making an existing flow available from every place the user might need it.
That's often the real work.
#bluidInPublic
I just developed a fairly complex feature using this workflow, and the experience was fantastic. I highly recommend it.
boristane.com/blog/how-i-u...
nice!
Thanks! Iโve also tried a few. Automerge is also strongly based on CRDTs, but Iโll take a look at Yjs. It looks interesting!
Which did you like the most?
Anthropic responds to Hegseth. www.anthropic.com/news/stateme...
Why learn to code when you can use an LLM and pay a subscription fee for the rest of your life.
youโre not alone. itโs crazy
Even if itโs $9 lol
thank you, Travis!
"David Allen taught us that you cannot manage time, you can only manage your actions. Cal Newport adds that not all possible actions deserve to be managed, and that fewer actions managed exceptionally well outperform many actions managed adequately."
facilethings.com/blog/en/doin...
More than enlightening - life changing ! Thank you @facilethings.com
facilethings.com/blog/en/doin...
We have managed to design a task editor in which all the information (text, notes, files, checklist, collaborators, due and start dates, tags, goal, project, focus area, choice criteria) fits on a screen as small as that of the iPhone SE.
#facilethings #gtd #apps
interesting -> waiting is the new interruption
jennywanger.com/articles/wai...
i do that every single time. is it prohibited?
The SaaS you intend to build iwith AI has countless details that it has accumulated over the years of experience that AI will not be able to replicate.