| Age | Commit message (Collapse) | Author |
|
Tapping an item outside shopping mode now opens an edit sheet. User-added items
can be renamed, moved between stores and sections, and deleted. PlanToEat items
show why they cannot be edited — the client is read-only, so presenting fields
that silently would not save is worse than saying so — and offer removal, which
marks them checked, the same mechanism shopping mode already uses.
This needed a store registry first. Stores previously existed only because some
item referenced them by name, with Trello's list names quietly acting as the
registry; removing Trello as a source made the gap visible. Without a registry
you cannot move an item into an empty store, and moving the last item out of a
store makes it vanish mid-edit. Migration 034 adds shopping_stores and
shopping_sections, seeded from the stores currently in use, and gives items a
section column — sections previously existed only as PlanToEat category
strings, so a user item could not be filed under one at all.
Registered stores and sections now appear in the list even when empty, which is
the whole point of the registry.
Two deliberate choices about destructive edges:
* Renaming a store renames it and moves its items in one transaction. Items
reference the store by name, so doing either alone orphans them.
* Deleting a store or section keeps the items, moving them to Unassigned or
clearing the section. Losing the list is far worse than re-filing an item.
* An UPDATE matching no rows is an error, not a silent success, so a stale id
cannot look like a saved edit.
Section options are rebuilt per store in the edit sheet rather than shipped as
one flat list, so a Costco item cannot be filed under a Safeway aisle.
18 new store tests, 11 handler tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
doot reads Google Calendar through a service account, by calendar ID. That
cannot consume an .ics URL, and it cannot see a calendar subscribed to inside a
personal Google account either, because Google does not allow re-sharing a
subscribed calendar. Published schedules — sports fixtures, school terms, bin
collections — are distributed almost exclusively as .ics, so none of them could
be added at all.
Feeds are now fetched on the normal calendar refresh and merged into
calendar_events alongside Google events, so the timeline, widget and everything
downstream keep seeing one list and needed no changes.
Failure handling is deliberately asymmetric. A Google error is still returned as
an error, unchanged, so an outage there surfaces. A single failing feed is
recorded against that feed and skipped, because one dead URL should not take the
whole calendar down — and last_error is shown in settings, since a feed that has
quietly stopped resolving otherwise looks identical to a team with no games
left.
The parser handles what real feeds actually contain: line unfolding, CRLF and
LF, UTC / TZID / VALUE=DATE times, and escaped text. Two details worth naming:
a TZID time is wall-clock in that zone, and reading it as UTC would put a 1:15pm
Pacific kickoff on the timeline at 1:15pm local — wrong by the offset but
entirely plausible-looking. And non-calendar content is a hard error rather than
zero events, because an HTML error page from a moved feed URL is the common
failure and "no events" reads as success.
RRULE is deliberately unsupported: every schedule feed this targets expands
recurrence itself, one VEVENT per fixture, and a correct expansion is a large
amount of subtle code. A recurring event appears once rather than wrongly.
Settings gains an add/enable/disable/remove UI. webcal:// links are accepted and
rewritten, since that is how feeds are usually advertised.
16 parser tests, 5 store tests. Verified against the real Seattle Seahawks feed:
21 events, all with valid times.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
The Trello "Shopping" board had become a dumping ground: of 24 cards, 13 had no
list at all (rendering as "Uncategorized"), and the rest were spread across
Costco, Hardware Store, "Perennial " (trailing space, so a separate store from
"Perennial") and online. Its items were read-only in doot — no rename, no move,
no delete, only hide — and its list names were doubling as an accidental store
registry, which is the only reason stores like Hardware Store existed at all.
Migration 032 imports the two groups asked for, Hardware Store and the unlisted
cards, into user_shopping_items. Costco, Perennial and online cards are left
behind. Nothing is destroyed: the cards remain in Trello, this only stops doot
displaying them. Imported rows become ordinary user items, so they also become
editable, which Trello-sourced items never were.
Trello remains the source for the other eight boards; this is only the Shopping
board feeding the shopping list.
Also updated the quick-action modal's Shopping tab, which posted source=trello
with a Trello list_id. Left alone it would have kept creating cards that no
longer appear anywhere. It now posts source=shopping with a store name, handled
by a new case in HandleUnifiedAdd, and its picker reads from a new
/partials/shopping-stores endpoint. The Trello-lists endpoint it used to call
is deleted along with its route.
Note for the edit feature still to come: stores have no existence independent
of items, so a store with nothing in it cannot be chosen. That was previously
masked by Trello's lists persisting. "Move between stores and sections" needs a
real stores/sections table.
Migration tested against a seeded snapshot of the real board, including the
trailing-space store name, other boards, replay safety and the empty-cache
no-op. Two existing tests asserting Trello check-state in shopping mode were
updated to plantoeat, the only remaining external source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
The inline "Add to <store>..." forms submitted with a bare
hx-swap="innerHTML" against #shopping-items-list. Those forms live *inside*
that target, so the swap destroys the form that submitted it and the page ends
up scrolled to the bottom rather than staying on the store being added to. The
quick-add form at the top never had this because it sits outside the target and
already carried an explicit scroll: modifier.
Each store section now has a stable id and its inline form scrolls back to it,
so adding to a store keeps that store in view.
Adds a `slug` template function for the id: store names are user data
("Trader Joe's", "Hardware Store") going straight into element ids, so anything
outside [a-z0-9-] is collapsed to a dash and an empty result becomes "unnamed"
rather than an invalid, shared anchor.
Tests render the real template with the real func map, and assert every inline
add form has a scroll target — the bug is trivially reintroduced by copying a
section.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
The conditions grid's second cell showed the Kilauea East Rim YouTube
cam. Replace it with the YB Tracking race viewer used by the official
Golden Globe Race live-tracker page.
Embeds https://yb.tl/ggr2026 directly rather than
goldengloberace.com/live-tracker/ — the live-tracker page is only a
wrapper whose own markup iframes yb.tl/ggr2026, so pointing at the
wrapper would nest an iframe for no benefit. yb.tl sends no
X-Frame-Options and no CSP frame-ancestors, so it renders in-frame.
Uses the same bare-iframe form as the Windy map cells (no autoplay
permissions), so it inherits the grid's existing absolute-fill sizing
and the narrow-width column reflow unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
due_date had been carrying two incompatible meanings: "this has a real
deadline" (Bills, meds, a signup cutoff) and "this is when I intend to
work on it." Chains leaned entirely on the second -- every step was
stamped due_date = now the moment it unlocked -- so a five-minute call
and a six-month certification both arrived looking overdue, and the only
way to quiet them was to hand-reschedule. The list therefore always
contained work that could not be finished that day, which made ending a
day at zero impossible by construction rather than by effort.
Splits the two apart:
- due_date keeps only its real meaning: an externally-imposed deadline.
- committed_date (new, migration 031) means "I chose this for today."
Chain steps no longer get a due date on unlock (CreateChain, advanceChain,
and the delete-promotion path), and are excluded from the undated list so
they don't simply fall through to it instead. They reach the day only by
being committed, via a "+ today" control on the chain card. Bucket-active
items get the same control. BuildTimeline pulls in committed tasks,
deduped against tasks already present for a different reason (committed
and due-today are two reasons for one row, not two rows).
Migration 031 also clears the auto-stamped due dates from open chain
steps; completed steps keep theirs as historical record.
Two supporting changes made while in here:
- Extracted the native_tasks SELECT list into nativeTaskColumns. It had
been copy-pasted into nine queries that must each agree exactly with
scanNativeTasks' field order; adding committed_date meant editing all
nine correctly or silently breaking whichever was missed.
- Extracted templateFuncMap() and added TestTemplates_AllParse. New()
only logs a warning when template parsing fails, so a malformed
template shipped silently and surfaced as a broken page at runtime.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
Swipe-to-change-tab only ever compared horizontal touch delta against
a 50px threshold, with no check against vertical movement -- an
ordinary scroll through a long tab (the shopping list, in particular)
drifts that far horizontally from natural thumb motion alone, and was
getting misread as an intentional swipe. Since timeline sits right
before shopping in TAB_ORDER, that's specifically what a rightward
drift landed on: "shopping randomly jumps back to timeline." Now
requires the horizontal delta to be at least 2x the vertical delta
before treating it as a swipe instead of a scroll.
Also fixed the shopping tab's inline quick-add row: the store <select>
had no width cap, so a long store name could claim enough width to
push the Add button past the right edge of the screen -- not just
cramped, actually unreachable. Capped the select's width and let the
name input actually shrink (needs min-w-0 alongside flex-1, since flex
items don't shrink below their content size by default), with
flex-wrap as a backstop for anything that still doesn't fit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
DashboardActivity (the WebView-wrapped web dashboard) had no
windowSoftInputMode override, unlike QuickAddActivity which already sets
adjustResize|stateVisible for the same class of problem: without it,
Android WebViews default to adjustPan, which shifts the whole page up
behind the keyboard instead of resizing the viewport, pushing a centered
`position: fixed` modal's input out of reach when the keyboard opens.
shopping-mode.html's fixed-bottom quick-add bar called a plain .focus()
on the item-name input right after the item list above it grew by one
row. The browser's default scroll-into-view for that focus call was
computed against the now-taller document and dragged the whole page to
the bottom instead of leaving the always-visible fixed bar alone.
preventScroll: true stops that.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
|
|
From the sitemap audit: /tabs/meals (same dead-tab pattern as the
removed /tabs/conditions, only reachable via ?tab=meals with no nav
button), /partials/lists (superseded by inline .Lists rendering in
trello-board.html), /shopping/toggle and /shopping/mode/{store}/toggle
(superseded by the one-way complete/filter model), plus the orphaned
trello-boards.html and error-banner.html templates that nothing
rendered or included. Rewrote the meals grouping test to exercise
groupMeals() directly since that logic is still live via the timeline.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK
|
|
Only the standalone /conditions page was ever meant to exist; the
HTMX tab variant was dead weight, reachable only via an unlinked
?tab=conditions query param with no button in the tab bar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK
|
|
V1cam's YouTube video ID had gone stale; resolved the current one via
USGS's url.usgs.gov/v1cam shortener. V2cam was already current. Zoomed
the Windy embeds/links out 1-2 levels on both the standalone conditions
page and the in-app conditions tab.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK
|
|
Service-account auth structurally cannot see a regular user's personal
task lists (no equivalent of Calendar's per-item sharing model) --
confirmed via GetTaskLists returning exactly the service account's own
empty "My Tasks" list, never the real user's three lists. Zero rows
were ever cached in production as a result.
Adds a standard 3-legged OAuth flow: /settings/google-tasks/connect
redirects to Google's consent screen (AccessTypeOffline+ApprovalForce
so a refresh_token is always issued), /callback exchanges the code and
persists the token (new oauth_tokens table), /disconnect clears it.
GoogleTasksClient now takes an option.ClientOption instead of a
credentials file path; NewGoogleTasksOAuthClient wraps it with a
dbTokenSource that reloads/refreshes from the DB on each access-token
expiry and re-persists -- carefully preserving the original
refresh_token when Google's refresh response omits one (it usually
does), which would otherwise silently and permanently break future
refreshes.
Settings page shows connection status and a Connect/Disconnect
button. Calendar keeps using service-account auth (that one actually
works). Requires a one-time manual step: create an OAuth 2.0 Client ID
in Google Cloud Console and set GOOGLE_OAUTH_CLIENT_ID/SECRET in .env
-- documented in .env.example.
|
|
Task-detail modal was description-only with no delete affordance;
HandleUpdateTask now saves the title too and a Delete button hits a new
DELETE /tasks/{id} route backed by store.DeleteNativeTask, which repairs
chain_position/unlocks the successor when the deleted task belongs to a
chain. Timeline tab task/card/gtask rows now open the same detail modal
as the Tasks tab. Android widget's "TODAY" header is now a tap target
that launches DashboardActivity, since nothing previously opened the
full app from the widget.
|
|
The Tasks tab (/tabs/tasks) existed server-side and was tested, but
nothing in the nav linked to it -- it was pure dead weight in the other
direction. Wiring it up as the natural home for everything that was
either misplaced in Settings or missing a web UI entirely:
- Maintenance Buckets, Projects, and Labels moved out of Settings and
into the Tasks tab (restyled from Settings' opaque slate cards to the
glass/backdrop-blur look already used by the tab's chain/atom cards --
they're now embedded in index.html's page shell, not a standalone
page, so the shared bg-card/bg-input classes from that shell apply).
Settings keeps only what's actually settings: Passkeys, Trusted
Agents, Data Sources.
- Added a Recurrence section to the task-detail modal (freq/interval/
weekday form, posting to a new POST /tasks/recurrence -- the HTMX
counterpart to the widget API's HandleWidgetTaskRecurrence). Native
task recurrence previously had zero web UI at all, only reachable via
the Android widget's RecurrenceEditDialog.
Also fixed a real bug found while touching this code: HandleGetTaskDetail's
source switch only had a case for "trello" -- opening any native ("doot")
task's detail modal, which is most tasks in this tab, showed a blank
title and description. Factored both call sites (initial GET and the
re-render after a recurrence edit) through one loadTaskDetailData helper
and added the missing "doot" case. Also fixed task-detail.html's styling,
which was still using pre-dark-theme classes (text-gray-900 etc.) --
functionally invisible text on the modal's dark background.
Verified with a throwaway local server (real templates + real DB, not
the MockRenderer the unit tests use) seeded with a recurring task,
a bucket, a project, and a label -- confirmed all five touched routes
render 200 with the expected content, including the populated
Buckets/Projects/Labels sections and a real weekly-recurrence form
with the correct weekdays pre-checked. Caught and fixed a copy bug
this way too ("every 2 weeklys" -> "every 2 weeks"). Not committed;
deleted after use.
go build ./..., go vet ./..., and go test ./... all clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
Audited it (couldn't query the live DB directly -- auto-mode classifier
blocks direct production reads without prior approval -- so this is a
code-only audit): GetFeatureToggles/SetFeatureEnabled/IsFeatureEnabled/
CreateFeatureToggle/DeleteFeatureToggle had exactly one caller each, all
inside their own CRUD handlers. Nothing anywhere else in the codebase
read a toggle's Enabled state to gate any actual behavior -- confirmed
by grepping every remaining .Enabled/IsFeatureEnabled reference back to
either this dead code or its own tests. It was pure UI-managed CRUD with
no consumer, unlike Trusted Agents (wired into agent.go/websocket.go)
or Data Sources (wired into the sync pipeline) which stayed.
Removes the Settings page section, the three /settings/features* routes
and handlers, the five Store methods, the FeatureToggle model, and adds
028_drop_feature_toggles.sql (next free migration number, per this
repo's convention of never renumbering -- see 021_drop_tasks.sql for
the same drop-table-forward pattern) to drop the now-unused table.
Also removed the now-dead tests for all of the above.
go build ./... and go test ./... both clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
Icon: adaptive-icon vector launcher icon reusing web/static/favicon.svg's
brand mark (indigo->purple gradient square, white checkmark) so the app
and web dashboard visually match. minSdk 36 (per build.gradle.kts) means
mipmap-anydpi-v26 alone is sufficient, no legacy PNG fallback needed.
Double title bar: DashboardActivity inherited the app-wide
Theme.DeviceDefault.DayNight, which has a native ActionBar, stacked on
top of the new Compose TopAppBar from the last commit -- visibly two
bars, showing "Doot" (static ActionBar label) above "Personal Dashboard"
(the Compose bar tracking the web page's own <title>). Added
Theme.Dashboard (NoActionBar) for the activity, and stopped tracking
the WebView's document.title for the Compose bar's title text --
the dashboard is a single HTMX-swapped page (see DashboardActivity's
class doc), so the title never meaningfully changes, and it was
just producing a second, differently-branded piece of text.
Renamed the app from "Doot Widget" to "doot" throughout (application
label, widget-picker description, Settings screen heading) to match
the project's actual branding.
Also: the web Settings page's "Back to Dashboard" link was a plain
<a href="/">, which in the WebView pushes a NEW history entry for "/"
instead of reusing the one already on the stack -- so Settings <-> Home
round trips kept growing the WebView back-stack ("zigzag"), and the
in-app back arrow/hardware back key never actually unwound it. Now it
calls history.back() when there's stack to pop, falling back to a plain
navigation only if there isn't (e.g. Settings opened directly).
Verified on emulator-5556: rebuilt and reinstalled, confirmed a single
title bar (no native ActionBar behind the Compose one), confirmed the
launcher icon renders (checked via Settings > App info, since this
AVD's launcher doesn't expose an app drawer over adb), no crashes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
New "Maintenance Buckets" section: create a bucket, add a pool item by
title (creates the task and assigns it in one step), remove an item,
delete a bucket (unbuckets its tasks rather than deleting them).
New read-only Projects and Labels sections (name + color swatch) --
both are simple enough that read-only is the right call on web, per
user direction, rather than duplicating the Android popup's editing
UX.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
The flat Tasks-tab atom list was silently dumping every chain step
(locked and unlocked) and dormant bucket-pool items in as ordinary
undated cards, with no chain/project context and no protection against
completing a locked step out of order.
- CompleteNativeTask now rejects completing a locked chain task
(ErrChainTaskLocked), mapped to 400 in both the widget and web
complete-atom handlers.
- Chain tasks and dormant bucket items are excluded from the flat atom
list; a new "Chains" section shows one card per active/paused chain
with the current step and N/M progress.
- New chain checklist modal (GET /chains/{id}) lists every position in
order with pause/resume/abandon -- the web view originally deferred
as Android-only.
- Fixed a real bug this surfaced: resuming a paused chain only flipped
the status flag, never unlocking the deferred successor, so a chain
paused right after a completion stayed stuck forever. SetChainStatus
now catches up the deferred advancement on resume, idempotently.
- Atom cards gained a project-name chip for general visibility.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
Backend, web timeline, and Android widget wiring for the last two
unimplemented items from doot-future-task-scheduling-ideas.
Chains: task_chains table + chain_id/chain_position/chain_unlocked on
native_tasks (migration 026), WIP-limit-1 advancement hooked into
CompleteNativeTask, locked tasks excluded from all date-based queries,
5 new /api/widget/chains* endpoints, an N/M position badge on web and
Android widget rows.
Buckets: maintenance_buckets table + bucket_id/bucket_state/
bucket_last_active_at on native_tasks (migration 027),
staleness-then-priority selection scoring, a new RunBucketCycleCheck
scheduler loop, 5 new endpoints including the distinct Defer action, a
Defer button on web and Android widget rows.
Also corrected stale "not yet approved" status headers on the two
already-shipped specs this work depended on (labels/projects, budgets/
availability) -- their headers were never updated after implementation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
|
|
Task 11 of the task-budgets-and-availability plan: reuse the
computeBudgetStatus helper (Task 8) in HandleTimeline so the dashboard's
Today section header shows scheduled/available minutes when a
budget-tracked task exists.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
|
|
Renders docs/superpowers/{specs,plans}/*.md to HTML via goldmark,
served from doot's own web server behind the existing session auth
instead of as raw files. DOCS_DIR is configurable (defaults to
docs/superpowers relative to the working directory) so the deployed
server can point straight at the working repo and stay live-synced
with no separate copy/deploy step for new docs.
|
|
|
|
Native tasks (native_tasks table) fully replace Todoist. All Todoist
API code, store functions, handlers, routes, templates, and tests have
been removed. Migration 021 drops the now-unused tasks cache table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Calendar: fall back to GOOGLE_CALENDAR_ID config when no source_configs
synced yet (fixes blank calendar after fresh deploy)
- Meals: call fetchMeals in HandleTimeline so PlanToEat cache refreshes
on every timeline load, not just during manual refresh
- Tomorrow section: replace calendar-grid with flat chronological list
matching widget layout (time label | source bar | title)
- Add /health endpoint (no auth required) for deploy health checks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Widget now renders a TOMORROW block below the today grid: events with
inline time labels (slightly dimmed) and task rows. Separated by a
divider. Covers both explicit-start tomorrow items and slot-packed
fragments that overflow from today.
Web view: TODO comment to flatten the tomorrow section to match widget.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds GET /task?id=xxx&source=xxx route that renders a full mobile-friendly
task detail page (session-protected). Widget task rows now open this page
when tapped. HandleUpdateTask redirects back to the page after a non-HTMX
save. Android: threads serverUrl through composable chain to TaskRow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
V1cam and V2cam embed IDs updated to current live streams. Thumbnail
links now point to YouTube live pages instead of USGS static webcam pages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Server seeds bg URL from a 5-minute time bucket so all open sessions
show the same image simultaneously. Client-side JS rotates in sync and
prefetches the next image on the same interval.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Implement SQLite caching layer for Google Tasks
- Integrate Google Tasks into unified Atoms loop (showing in Tasks tab)
- Update Planning tab to include cached Google Tasks
- Enhance Quick Add form with Todoist project selector
- Remove orphaned HandleTasksTab/HandleRefreshTab methods
- Update tests to reflect new BuildTimeline signature and data structures
|
|
- Implement write operations (complete, uncomplete, update due date, update task)
- Implement create operations (create task, add shopping item)
- Add Trusted Agents management UI in Settings with revocation support
- Fix SQLite timestamp scanning bug for completed tasks
- Add comprehensive unit tests for all new agent endpoints
- Update worklog and feature documentation
|
|
Replace z-index:-1 overlay div (hidden behind body background) with a
CSS custom property --bg-url set inline on body, consumed by .bg-body
as a layered background-image with a dark gradient overlay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|
|
Embeds the build version as a data attribute on #last-updated and
derives an HSL hue from the first 6 hex chars, matching the
claudomator logo color technique.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Delete Bug struct, BugToAtom, SourceBug, TypeBug, TypeNote
- Remove bug store methods (SaveBug, GetBugs, ResolveBug, etc.)
- Remove HandleGetBugs, HandleReportBug, bug branches in handlers
- Remove bug routes, bugs.html template, bug UI from index.html
- Remove AddMealToPlanner stub + interface method
- Migration 018: DROP TABLE IF EXISTS bugs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
- migration 016: sync_log table
- store: AddSyncLogEntry, GetRecentSyncLog, InvalidateAllCaches, GetProjectsFromTasks
- settings: HandleClearCache (POST /settings/clear-cache), SyncLog in page data
- settings: use GetProjectsFromTasks instead of deprecated Todoist REST /projects
- handlers: populate atom projects from store
- agent: log warning on registration failure instead of silently swallowing
- google_tasks: simplify URL literal
- tests: sync log CRUD, clear cache handler, settings page includes sync log,
sync sources adds log entry, incremental sync paths, task completion
response/headers, calendar cache fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Root cause: WEBAUTHN_RP_ID and WEBAUTHN_ORIGIN env vars not set in
production, so WebAuthn is nil and all passkey endpoints return 404.
The settings page was unconditionally showing the passkey registration
card, leading to confusing "Failed to start registration" errors.
Fix: Pass WebAuthnEnabled flag from main.go through Handler to the
settings template, which now conditionally renders the passkey card
only when WebAuthn is properly configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
- Display build commit hash in unobtrusive footer overlay
- Inject buildCommit/buildTime via ldflags in deploy.sh
- Add assertTemplateContains test helper, refactor existing template tests
- Add scripts/logs for fetching production journalctl via SSH
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
- Fix checkboxes in timeline calendar grid targeting #tab-content (replaced
entire view). Now target closest .untimed-item/.calendar-event with outerHTML
- Fix passkey registration 403 by passing CSRFToken from settings handler
and exposing it via meta tag for JS to read
- Add TDD workflow requirement to CLAUDE.md
- Tests written first (red-green): template content assertions for checkbox
targets and CSRF token presence, handler data struct verification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
- Add settings gear icon link to dashboard header
- Fix GetTasksByDateRange/GetCardsByDateRange to include overdue items
(changed from BETWEEN to <= end, filter completed tasks)
- Fix refresh replacing active tab with tasks tab by using
htmx.trigger(body, 'refresh-tasks') instead of innerHTML+htmx.process
- Add refresh-tasks hx-trigger to meals, shopping, conditions tabs
- Add tests for overdue inclusion/exclusion, settings link, template data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Enable passwordless login via passkeys as an alternative to password auth.
Users register passkeys from Settings; the login page offers both options.
WebAuthn is optional — only active when WEBAUTHN_RP_ID and WEBAUTHN_ORIGIN
env vars are set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Session improvements:
- Extend session lifetime to 7 days for mobile convenience
- Add idle timeout to extend session on activity
- Use standard cookie name for better compatibility
Shopping model:
- Add FlattenItemsForStore helper for extracting store items
- Add StoreNames helper for store list
- Improve shopping-tab.html with inline add forms
Frontend:
- Add WebSocket reconnection and agent approval UI to app.js
- Simplify timeline calendar JS (move event positioning to CSS)
- Update login page styling
Deployment:
- Remove unused git checkout step from deploy.sh
- Update apache.conf WebSocket proxy settings
Documentation:
- Add Agent Context API feature spec to issues/
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Add Quick Add UX pattern to DESIGN.md documenting expected behaviors
for form submission, error handling, and completed item display
- Filter checked items from shopping-tab.html display (both grouped
and ungrouped views)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
Shopping mode:
- Click to complete items (deletes user items, hides external items)
- Add print button with compact two-column print layout
- Fix CSRF token for HTMX requests
- Fix input clearing with proper htmx:afterRequest handler
- Remove "Quick Add" store option, require valid store
Navigation:
- Replace dropdown menu with flat nav showing all tabs
- Remove unused dropdown JS
Tests:
- Add TestHandleShoppingModeComplete for user and external items
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
Delays the highlight/raise effect by 100ms, allowing users to move
their mouse across overlapping events without the first one blocking
access to others underneath.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Add dynamic calendar clipping: show 1 hour before/after events instead of hardcoded 6am-10pm
- Add "NOW" line indicator showing current time position
- Improve time label readability with larger font and better contrast
- Add overlap detection with column-based indentation for concurrent events
- Apply calendar view to Tomorrow section (matching Today's layout)
- Fix auto-refresh switching to tasks tab (default was 'tasks' instead of 'timeline')
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- #56: Add overflow-hidden to card/panel classes to prevent content overflow
- #65: Fix Google Tasks not showing by including tasks without due dates
- #66: Add no-cache headers to prevent stale template responses
- #67: Increase dropdown z-index to 100 for proper layering
- #69: Implement calendar-style Today section with hourly grid (6am-10pm),
duration-based event heights, and compact overdue/all-day section
- #70: Only reset shopping-mode form on successful submission
- #71: Remove checkboxes from shopping tab (only show in shopping mode)
- #72: Add inline add-item input at end of each store section
- #73: Add Grouped/Flat view toggle for shopping list
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- Add feature_toggles table (migration 012)
- Add source_config table for future source selection (migration 013)
- Create settings page at /settings with:
- Feature toggle management (enable/disable/create/delete)
- Data source configuration (sync and toggle boards/calendars)
- Add store methods for feature toggles and source config
- Add GetCalendarList and GetTaskLists to Google API clients
- Document feature toggle workflow in DESIGN.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|