Skip to main content

Owner Dogfooding Issue Inventory

Captured: 2026-07-28
Source: first-hand use of the organization app
Status: reported friction; not yet a code-verified implementation plan

Purpose

This document turns raw dogfooding notes into a set of problems that can be investigated and resolved one at a time.

The original notes contain a mix of:

  • reproducible-looking defects
  • unclear or excessive workflows
  • missing or inconsistent interactions
  • product-direction concerns
  • codebase and architecture concerns

Those categories should not be handed to an implementation agent as one large request. Each issue below is intentionally separable. A future pass should investigate the current behavior, confirm the desired product decision, define the affected surfaces, implement the change, and verify it before moving to the next issue.

This inventory preserves the force of the original feedback without treating frustration as a substitute for diagnosis. Reported behavior is not marked as a confirmed root cause until the relevant implementation has been inspected.

Product Standard Expressed By The Notes

The app is intended to be the daily operating system for a freelancer or small agency, not merely a collection of administrative features.

The primary experience should support the work that occupies most of the operator's day:

  • knowing what matters today
  • moving between clients and projects without reconstructing context
  • capturing notes and time without ceremony
  • creating and linking follow-up work naturally
  • collaborating with a team when one exists
  • keeping client context close without exposing internal work accidentally

Billing, contracts, and invoicing matter, but they occupy a smaller portion of the working day. The product will not earn daily use merely by reproducing administrative capabilities that already exist elsewhere. Its advantage must come from making the operator's actual work calmer, faster, more coherent, and easier to resume.

The standard for the first public beta is therefore not just feature presence. The features must form one understandable system:

  • one concept should not behave like several unrelated mini-features
  • common actions should have consistent behavior across surfaces
  • the interface should hide unnecessary internal complexity
  • routine work should require the fewest meaningful decisions and actions
  • the user should be able to trust that the state shown in one place is the same state shown everywhere else

How To Use This Inventory

For each implementation session:

  1. Select one issue ID.
  2. Reproduce and inspect the current behavior before proposing a fix.
  3. Read the linked product and implementation docs.
  4. Separate the observed symptom from its technical root cause.
  5. Confirm any unresolved product decision.
  6. Define a bounded acceptance contract.
  7. Implement and test the issue across every surface named in that contract.
  8. Update this document with the result before selecting another issue.

Issues may be combined only after investigation proves they share the same root cause and can be verified with one coherent acceptance contract.

Triage Summary

IDIssueTypeInitial urgency
NOTE-01Notes show stale or duplicated state across surfacesTrust and consistency defectCritical
NOTE-02Notes should have one clear autosave modelProduct behavior and consistencyHigh
NOTE-03New-note dialog is too short for its editing jobInteraction and layoutMedium
NOTE-04Starred and recent notes cannot be pinned from the topbar listMissing interactionMedium
TIME-01Personal time capture has an excessive approval loopWorkflow designHigh
REM-01Timed reminder date selection does not preserve the chosen dateFunctional defectHigh
REM-02Reminder creation does not make client and project context easy to addWorkflow and linkingHigh
REM-03Opening a reminder from the topbar produces an awkward dialog flowInformation architectureMedium
NAV-01Today may deserve priority over Overview in the sidebarNavigation and product emphasisMedium
TOP-01Pinned projects in the topbar are not actionableWorking-context designMedium
I18N-01Billing notification copy appears untranslated or developer-facingLocalization and product copyHigh
PROD-01The app lacks a consistently obvious, low-friction operating flowProduct-system concernFoundational
PROD-02Personal, linked, internal, and client-visible concepts are too exposedProduct-model and vocabulary concernFoundational
ARCH-01UX inconsistency is reinforced by god files and fragmented state ownershipArchitecture and sequencingFoundational

The urgency labels are an initial reading of the reported impact, not a final delivery order. Trust-breaking data presentation and functional defects should generally be investigated before interaction polish. Foundational product questions should be discussed before a broad refactor, but they should not delay bounded fixes for confirmed defects.


NOTE-01 — Notes Show Stale Or Duplicated State Across Surfaces

Reported behavior

The same note can appear more than once in the topbar, and one copy may show an older editing state while the Notes page shows the current content. Unpinning the stale copy and pinning the note again appears to refresh it.

The Notes page is currently perceived as the only reliable place to edit a note.

Why this matters

This is a trust failure, not merely visual duplication. A user cannot safely use notes as working memory if two views of the same record disagree. The user is forced to reason about which surface owns the real note and to perform manual recovery steps.

Intended outcome

A note is one canonical record that can be viewed or edited through several surfaces. The Notes page, topbar quick view, pinned-note view, recent-note view, and any dialog or full-screen editor must converge on the same saved state.

Opening the same note in more than one presentation must not create competing copies, independent edit histories, or stale pinned snapshots.

Investigation questions

  • Are duplicate topbar items separate working-tab and pinned-record instances, or is one record being assigned multiple non-canonical IDs?
  • Does any surface retain a note snapshot instead of subscribing to the canonical record?
  • Do quick-note drafts and saved notes cross the draft-to-record boundary cleanly?
  • Can delayed saves, optimistic updates, or subscription revisions overwrite newer content?
  • Do rich-text changes and plain-text changes pass through the same persistence path?

Resolution boundary

Do not close this issue after removing a duplicate chip visually. Resolution requires proving canonical identity, state ownership, persistence, and cross-surface synchronization for the same note.

Implementation result — 2026-07-28

The stale-state path was confirmed and repaired.

Root causes:

  • a saved note opened from the topbar was copied into a durable local quick-note session
  • reopening that note reused the local snapshot without reconciling it against the current Convex record
  • pinned-record labels were synchronized only from the selected Notes-page record, not centrally from canonical note data
  • delayed autosave completion targeted the currently active session rather than the exact session that initiated the request

The repaired contract is:

  • clean saved-note sessions refresh from the canonical subscribed note record
  • genuinely unsaved local edits are not overwritten by subscription refresh
  • reopening a saved note reconciles the session before presenting it
  • pinned-note labels and context synchronize from canonical note data
  • legacy plain-text notes pass through the same canonical rich-text hydration used by the Notes page
  • save completion and session cleanup target the initiating session ID, even if the user switches notes while the request is pending
  • the topbar keeps one saved-note tab when a pinned or temporary record item already represents that note

Automated verification:

  • apps/app/tests/org/quick-note-context.test.ts
  • apps/app/tests/org/working-quick-view-strip.test.ts
  • apps/app/tests/org/note-quick-access-popover-content.test.tsx
  • focused result: 32 tests passed
  • app TypeScript validation passed
  • ESLint passed for all changed app and test files

Owner dogfood confirmation remains pending because no controllable signed-in browser session was available during implementation.


NOTE-02 — Notes Should Have One Clear Autosave Model

Reported behavior

The note editor presents a Save action, but its state is confusing. It may temporarily appear muted as though work is being saved and then become actionable again. Some editor operations, such as applying a bullet list, do not appear to mark the note as changed.

An older observation questioned whether quick notes saved automatically. The current product decision expressed in the notes is stronger: all note editing should save automatically, including durable backend persistence rather than only local draft recovery.

Why this matters

A visible save button makes the user monitor persistence instead of writing. If the button does not recognize every meaningful editor change, it also gives unreliable feedback. Different save rules across the Notes page, quick notes, topbar views, and expanded editors make Notes feel like several features.

Intended outcome

Saved notes autosave after the user pauses editing. Every meaningful editor change participates in the same dirty-state and persistence model, including format-only changes.

Local draft recovery may protect unsaved work, but it must not be confused with durable server persistence. The UI should communicate exceptional states such as an active save or failed save without requiring a routine Save button.

Decisions required

  • What debounce or idle behavior should trigger durable persistence?
  • What minimal saving, saved, offline, and failed-save feedback is necessary?
  • When does a quick-note draft become a saved note record?
  • What happens when the editor closes while a save is pending?
  • How are concurrent edits or stale revisions handled?

Resolution boundary

This issue applies to every editor surface for the same note model. It should not be solved by hiding the button while leaving inconsistent or local-only persistence underneath.

Owner reconfirmation — 2026-07-28

After the NOTE-01 consistency repair, the owner reconfirmed that routine Save buttons still feel wrong for Notes. Treat their removal as part of this dedicated autosave contract pass, not as a cosmetic follow-up to NOTE-01.

Implementation result — 2026-07-28

The Notes page, topbar quick-note editor, and shared new-note compose dialog now use one durable autosave contract:

  • a valid note persists after a 900 ms editing pause
  • closing, minimizing, switching notes, or unmounting flushes the latest valid draft instead of depending on the debounce
  • new quick notes and compose-dialog drafts become durable note records automatically and remain open for continued editing
  • incomplete new drafts remain in organization- and user-scoped local recovery without being presented as server-saved notes
  • all rich-text payload fields participate in dirty detection, so format-only changes persist
  • routine Save and Save and link actions are removed; the surfaces show only quiet Saving, Saved, or failure state, while explicit follow-through actions such as Link to timer remain available
  • updates carry the last observed server revision; the backend rejects stale writers instead of silently overwriting a newer edit
  • backend no-op updates return the existing revision without rewriting the note
  • queued edits made while a new note is being created attach to that first record rather than creating duplicates

Automated verification:

  • packages/backend/tests/org/note-autosave.test.ts
  • apps/app/tests/org/note-drafts.test.ts
  • apps/app/tests/org/note-compose-dialog.test.tsx
  • apps/app/tests/org/note-quick-access-popover-content.test.tsx
  • apps/app/tests/org/quick-note-context.test.ts
  • focused app result: 32 tests passed
  • backend autosave result: 1 test passed
  • app and backend TypeScript validation passed
  • locale, action-copy, copy, and targeted ESLint checks passed

Owner dogfood confirmation remains pending. The next hands-on check should cover creating and continuing a note from each surface, closing before the debounce completes, applying format-only changes, and opening the same note in two browser sessions to confirm that a stale writer is stopped visibly.


NOTE-03 — New-Note Dialog Is Too Short For Its Editing Job

Reported behavior

The editor in the dedicated new-note flow is vertically cramped.

Why this matters

The available writing area does not match the scope of the task. It makes a normal note feel constrained before the user has written meaningful content.

Intended outcome

The creation surface should provide enough room for comfortable note composition at common viewport sizes while remaining consistent with the chosen editor-scale rule.

Decisions required

  • Is note creation still a bounded dialog job, or has it become a route-backed workspace?
  • Should the editor have a larger fixed minimum, responsive height, or an explicit expansion path?
  • Should new-note and existing-note editors use the same size behavior?

Resolution boundary

Test the result on small laptop, common desktop, and constrained-height viewports. Do not solve the desktop complaint by making the dialog unusable on smaller screens.

Scope clarification — 2026-07-28

The owner clarified that the cramped presentation occurs specifically when creating a note from the Notes page. Client, project, timer, and other quick-capture entry points should retain their existing compact presentation.

Implementation result — 2026-07-28

The owner chose a workspace-native interaction instead of enlarging the modal. The Notes-page New note action now:

  • inserts a selected draft row into the existing note list immediately
  • opens that draft in the same full Notes-page editor used for existing notes and focuses the title
  • inherits the current project or client context when the page was opened in that context
  • keeps an incomplete draft in scoped local recovery without creating an empty backend record
  • promotes the draft to one durable note after meaningful body content is entered, then autosaves later edits to that same record
  • quietly discards a completely empty draft when another note is selected
  • withholds pin, archive, delete, timer-link, and promotion actions until the draft has a durable note identity

Client, project, timer, topbar, and other quick-capture note entry points keep the compact shared composer because those entry points are deliberately brief contextual capture flows. This makes the dedicated Notes route behave like a real notes workspace without forcing every create surface into a full-page interaction.

Automated verification covers contextual draft defaults, inline selection, create-once behavior, follow-up revision-aware autosave, and empty-draft discarding in:

  • apps/app/tests/org/note-drafts.test.ts
  • apps/app/tests/org/notes-page-inline-create.test.tsx
  • apps/app/tests/org/note-compose-dialog.test.tsx

Focused result: 7 tests passed. App TypeScript and targeted ESLint validation passed. Owner visual confirmation remains pending.


NOTE-04 — Starred And Recent Notes Cannot Be Pinned From The Topbar List

Reported behavior

Hovering a note in the topbar's starred or recent sections does not offer the expected pin action.

Why this matters

The topbar is meant to manage a working set. Discovering a note there but having to leave that context to pin it breaks the purpose of the surface.

Intended outcome

Eligible notes shown in starred and recent lists expose a consistent, accessible pin or unpin action without requiring navigation to the Notes page.

Investigation questions

  • Is starred a separate durable concept from pinned, and is that distinction clear enough to keep?
  • Are the same note actions intentionally available in recent, starred, search, and pinned sections?
  • How should the action remain discoverable for keyboard and touch users, where hover is unavailable?

Implementation result — 2026-07-28

Starred and Pinned are now explicit independent states:

  • Starred remains the note-level organization state backed by the existing note fields
  • Pinned is the durable shell working set backed by workspace preferences
  • Starred and Recent topbar rows expose the same note-specific pin/unpin action without navigating away or closing the launcher
  • the action uses a visible touch target plus localized aria-label, title, and aria-pressed state
  • the note's Starred state is represented with a Star indicator and is never mutated by the shell action
  • when one note appears in both Starred and Recent, both controls resolve from the same shell state and cannot create duplicate pins

Focused interaction coverage verifies the independent state combinations, canonical pin payload, unpin behavior, duplicate-row synchronization, and action/link isolation. App locale validation and focused linting pass. Owner dogfood confirmation remains pending.


TIME-01 — Personal Time Capture Has An Excessive Approval Loop

Reported behavior

Stopping a timer creates a draft entry. The user must then submit the entry for review, open the review queue, and approve their own time. A small block of personal work therefore requires several administrative actions after the time has already been captured.

Why this matters

Frequent time capture must be nearly effortless. A workflow that may make sense for team oversight becomes unreasonable when an owner or independent operator must approve their own routine work. Users will forget the steps, allow drafts to accumulate, or stop using the timer.

Intended outcome

The workflow should preserve review and billing integrity where they are actually needed without forcing every user and every entry through the same state ceremony.

Decisions required

  • Should an organization owner's own entry be approved automatically?
  • Should organizations without a team default to a simpler flow?
  • Is approval policy based on role, authorship, billing status, organization settings, or a combination?
  • When is a draft genuinely useful rather than an implementation artifact?
  • Which corrections must remain possible after an entry becomes billable or approved?

Resolution boundary

Do not merely add a bulk-approve button to the existing loop. First decide which users and entries need approval at all. Preserve auditability and invoice locking without making routine capture serve the most complex case.

Implementation result — 2026-07-28

Time capture is now a single completed action rather than the start of a mandatory self-approval loop:

  • routine time is tracked immediately for every role by default
  • an organization can opt into Require review for staff time from General settings; the switch persists immediately without a separate Save action
  • when review is enabled, staff time goes directly to Needs review while owners and members with time-review authority continue tracking directly
  • correcting a returned staff entry sends it straight back to review
  • correcting an unlocked entry as a reviewer keeps it tracked
  • the timer and manual-entry confirmations now say Time tracked

The UI no longer exposes Submit actions or treats approval as the primary language for routine capture. The visible states are Saved for legacy drafts, Needs review, Changes requested, and Tracked. Draft remains in the stored enum only for compatibility with older records and the legacy submission mutation remains available to recover those records.

Tracked time is also no longer treated as an overdue billing task. It does not create an overview attention signal or force a billing profile merely because it is unbilled. Client and project time views may show unbilled tracked hours as useful context. Selecting a client in the invoice composer now produces one optional Ready to bill recommendation with total hours, value, project count, and date range. Add to invoice selects the exact entries; Review reveals the separate project/rate groups, exact entries, custom periods, and overrides. A client-wide invoice may combine multiple separately priced scopes, while a project invoice accepts only that project's time. Manual invoice lines remain first-class. Currency, service label, tax, PDF, memo, footer, and custom fields remain available behind Additional options instead of crowding the default path.

The active timer is now durable server state with a local instant-response mirror. It survives refresh, browser-data loss, and device handoff; repeated or concurrent starts for one member and organization resolve to one timer. The global timer chip offers one-action stop-and-track while opening the timer retains client, project, task, note, billable, work-log, pause, resume, and discard controls.

The first owner retest exposed two shell regressions in that implementation. Independent timer-hook instances could calibrate from different cached server timestamps, causing the dialog and topbar to disagree, and a separate discard X was layered over the topbar's stop control. The shell now owns one shared timer controller and clock. The timer chip exposes only its open action and one outline Stop and track control; discard remains in the timer dialog behind confirmation. Active timer buttons use semantic success styling rather than a black selected state.

New time entries snapshot their billing mode, hourly rate, rate source, and currency at capture. Later project or client default changes therefore split older and newer work into accurate internal billing groups rather than repricing old work. Pre-snapshot entries use the current configuration as a compatibility fallback because historical prices cannot be reconstructed safely.

The review state is no longer reused as a client-visibility decision. Projects have an explicit Show tracked time in the client portal setting, off by default, which gates project, task, update, and portal-billing time totals. Invoice eligibility remains internal and independent.

Team behaviour is explicit rather than inherited from broad client-record management:

  • time.view_team exposes teammate time metadata and totals
  • time.review adds review authority and private detail
  • time.manage adds edit, delete, and lock authority over team entries
  • default staff see only their own entries and summaries

The standalone Entries page now defaults to the current month, supports week/month/quarter/year/custom ranges, calculates totals across the complete selected range, and automatically estimates hourly value from project overrides and client defaults for invoice-authorized members. Retainer, non-billable, and subscription-covered time is excluded; missing rates remain visible as unpriced time and currencies remain separate.

Invoice integrity is unchanged: only internally approved, billable entries can be allocated, reservation locks the exact entries, and reserved or invoiced entries cannot be unlocked or deleted. Uninvoiced, unlocked entries can still be corrected, archived, or deleted so an automatically ready owner entry does not become permanent merely because it was captured.

Regression coverage verifies direct staff tracking by default, opt-in staff review, automatic resubmission after a requested change, deletion of uninvoiced time, single-instance durable timers, capture-time pricing, historical-rate grouping, and unchanged exact-allocation integrity. TIME-01 remains open only for owner dogfood confirmation of the revised interaction.


REM-01 — Timed Reminder Date Selection Does Not Preserve The Chosen Date

Reported behavior

The reminder date picker appears to work when All day is selected. When a specific time is used, the saved reminder does not retain the intended date.

Why this matters

Incorrect reminder scheduling defeats the feature's primary purpose and can cause real work to be missed.

Intended outcome

All-day and timed reminders save the exact date intended by the user. Timezone, date, and time controls must form one predictable value across create, edit, display, and notification behavior.

Investigation questions

  • Is the defect caused by local/UTC conversion, stale form state, parsing, or serialization?
  • Does it reproduce in create and edit flows?
  • Does the displayed date differ immediately or only after reload?
  • Does the behavior vary by timezone, daylight-saving boundary, or locale?
  • Do other date-time controls share the same implementation?

Resolution boundary

After fixing Reminders, audit other consumers of the same date-time primitive. The issue is complete only when timed and all-day cases have regression coverage.

Implementation result — 2026-07-28

The defect was in the reminder dialog's local date-time composition:

  • single-digit minutes were formatted as invalid time-input values such as 08:5 instead of 08:05
  • changing the date or time derived its replacement value from render-time draft state, so closely sequenced changes could restore the previous value

The reminder dialog now uses one tested local date-time helper for formatting and replacing date, time, and all-day values. Every update derives from the latest functional draft state. The backend already persisted dueAt unchanged, so no schema or data migration was required.

Regression coverage now verifies:

  • a date change preserves a timed reminder's time
  • a time change preserves the selected date
  • single-digit minutes round-trip through valid HH:mm input formatting
  • all-day reminders retain the documented local 09:00 convention
  • invalid partial inputs do not corrupt the existing timestamp
  • dialog submission sends the selected local date and time with allDay: false

A narrow audit found no other instance of the malformed minute-formatting pattern. The calendar date-time formatter pads minutes correctly.

Owner confirmation — 2026-07-28

The owner verified that timed reminder date and time selection now persists correctly. REM-01 is closed.


REM-02 — Reminder Creation Does Not Make Context Easy To Add

Reported behavior

The reminder Add control is not useful enough. While creating a reminder to add tasks for a particular client project, it was not easy to link the reminder through client → project, so the attempt was abandoned.

The flow also does not appear to participate adequately in client-focus mode.

Why this matters

A reminder without the context needed to act on it becomes another isolated item the user must interpret later. If adding that context requires hunting through generic record types or leaving the current client, the linking model adds work instead of preserving context.

Intended outcome

Reminder creation should inherit known client or project context and make related records easy to find. Starting in client-focus mode, from a client, or from a project should materially narrow and improve the flow.

The Add interaction should represent the useful things a reminder can refer to in language and grouping that match the user's current job.

Decisions required

  • Which contexts should prefill automatically?
  • Should project choices be filtered by the selected or focused client?
  • Which record types are genuinely useful reminder targets?
  • Should the flow support creating a missing related item, such as a project task, or only link to existing records?
  • Is Add the right label for this job?

Resolution boundary

Do not treat this as a larger picker alone. Success means a user can express “remind me to add tasks for this client's project” without reconstructing the relationship manually.

Implementation result — 2026-07-28

Reminder creation now treats client and project as primary structured context instead of burying them inside a generic record picker:

  • the dialog exposes one compact client → project context control
  • projects are scoped to the selected client, and choosing another client clears incompatible project context
  • client focus prefills a brand-new generic reminder
  • explicit client and project detail actions prefill their owning context
  • a persisted dirty create draft wins when resumed, so a later focus change does not overwrite user work
  • notes, files, time entries, commercial records, and resources remain optional under Add related item
  • existing reminders with additional legacy client/project links keep those records visible as related items rather than silently hiding them

Reminder writes now re-resolve visible client and project records, reject inaccessible or mismatched context, and store canonical titles, routes, and client/project IDs instead of trusting browser-provided snapshots. Focused UI coverage verifies inherited context, exact mutation payloads, client-scoped project choices, and incompatible-project reset. Backend coverage verifies the context authorization and canonicalization boundary. Owner dogfood confirmation remains pending.


REM-03 — Opening A Reminder From The Topbar Produces An Awkward Dialog Flow

Reported behavior

Clicking a reminder in the topbar opens a dialog. The result feels like another mini-feature embedded in the topbar rather than a coherent way to inspect and act on a reminder.

Why this matters

The topbar already carries several utilities and working records. If every type opens through a different ad hoc interaction, the shell becomes difficult to predict and maintain.

Intended outcome

Opening a reminder from the topbar should follow a deliberate, consistent working-record model. The user should be able to inspect the reminder, act on its linked context, and open a durable destination when deeper work is needed.

Decisions required

  • Is a bounded preview/edit dialog appropriate for reminders, or does a reminder need a detail route?
  • What should a topbar click do versus an explicit Open reminder action?
  • Which reminder actions belong in the quick view?
  • How should the behavior align with Notes, Projects, and other working tabs?

Resolution boundary

Do not create a detail page solely to avoid examining the shell interaction model. Choose the correct destination based on the reminder's work scope, then make topbar behavior consistent with that choice.

Implementation result

REM-03 is implemented as a two-level reminder model:

  • selecting a reminder in the topbar stays in the shell and opens a compact non-blocking quick view without creating a working tab
  • pinning from the quick view is the explicit action that adds the reminder to Working
  • pinned reminder tabs use the same quick view, including completed reminders
  • the quick view exposes due/status, priority, details, assignees, linked context, Complete/Reopen, permission-gated Edit, pin/unpin, and an explicit Open reminder action
  • Open reminder, reminder-list rows, Today, Calendar, and new notification links use /reminders?reminderId=… to open the full reminder drawer without leaving the workspace
  • the detail drawer separates client/project context from other related records, honors client focus, permission-gates edit/delete, and safely handles unavailable or deleted reminders
  • legacy /reminders/[reminderId] links redirect to the canonical drawer route
  • pinned reminder visibility now mirrors reminder visibility exactly: creator or current assignee, never every member merely because the audience is team
  • one-day snooze advances from the later of now or the existing due time and preserves the local 09:00 all-day convention

Focused UI, route-registry, date-time, notification, backend visibility, and project-workflow coverage protects the new contract. Owner dogfood confirmation remains pending.


Reported preference

Today should appear before Overview.

Product rationale

The first thing an operator needs is a calm answer to “what do I need to do today?” Broader agency reporting and exploration should remain available, but the navigation hierarchy should reflect the app's daily-use promise.

Intended outcome

The default entry and navigation order reduce startup stress and foreground the user's immediate work.

Decisions required

  • Should Today merely appear first, or should it become the default landing route?
  • Is the answer the same for owners, members, and users with different responsibilities?
  • Does Today currently contain enough reliable, actionable information to deserve that priority?
  • How should Today and Overview differ so they do not become competing dashboards?

Resolution boundary

Treat this as an information-architecture decision, not a one-line reorder. Validate the role and content of both destinations before changing the default experience.

Implementation result

Today is now the role-neutral organization home:

  • the Home navigation order is Today, Overview, then Analytics
  • authenticated app-root visits, org login without a requested destination, completed MFA, completed onboarding, organization creation, organization switching, signup, and verification now land on Today
  • valid requested destinations are still honored, so the new default does not force people away from intentional deep links or from Overview
  • all active organization roles share the same default; Today already adapts task and workflow scope, available actions, client focus, and team controls through the existing access model
  • Today remains the daily execution surface: immediate workflow, tasks, timer, agenda, reminders, and pinned notes
  • Overview remains the organization-health surface: cross-client attention, delivery risk, billing coverage, project load, and intervention signals
  • the open Today page now refreshes its date boundary and overdue calculations each minute so it does not retain yesterday's state across midnight

Focused navigation, redirect-policy, login, and proxy coverage protects the new default while explicitly confirming that intentional deep links remain intact. Owner dogfood confirmation remains pending.


TOP-01 — Pinned Projects In The Topbar Are Not Actionable

Reported behavior

Pinned projects currently provide too little useful information to justify their place in the topbar.

Why this matters

A pinned project should help the user resume work. A shortcut that exposes only identity or basic metadata does not reduce context reconstruction.

Intended outcome

A pinned project quick view should make the next useful work visible, with project tasks identified as an important candidate. It should help the operator understand current state and take a relevant action without turning the topbar into a duplicate project page.

Decisions required

  • Which project information is essential in a quick view?
  • Should open, assigned, due, or blocked tasks be prioritized?
  • Which actions belong in the topbar and which should open the project route?
  • How does the view behave when a project has many tasks or no next action?
  • Can the same actionable-preview pattern serve other pinned record types?

Implementation result

Pinned projects now open a compact, non-blocking resume view instead of a reporting-heavy modal:

  • the preview loads only when opened through a dedicated access-scoped project quick-view query rather than subscribing every pin to the full project detail, commercial, update, file, and time payloads
  • the project client, status, concise summary, target date, due-now count, viewer-assigned count, and total open-task count establish enough context without recreating the project page
  • an open blocker leads the preview and exposes its exact next action plus the durable project-blockers destination
  • tasks are deliberately ranked: viewer-assigned work first, then unassigned work, then other team work; within each group, overdue/due work leads future or unscheduled work, followed by priority and project order
  • the first four tasks are shown, while Open tasks handles larger projects
  • task rows can complete work in place, start a timer with exact client/project/task context, or open the canonical task route
  • project-level actions can start project time, add a task, or open the full project; archived projects remain readable without offering invalid writes
  • unavailable or newly inaccessible projects fail safely rather than exposing stale pinned metadata

The interaction anatomy—small status context, a prioritized next-action preview, bounded inline actions, and one explicit durable destination—can guide other pinned record improvements, but no premature shared abstraction was added before a second record type proves the same behavior.

Focused shell interaction, project ranking, authorization, localization, and project-workflow coverage protects the new contract. Owner dogfood confirmation remains pending.


I18N-01 — Billing Notification Copy Appears Untranslated Or Developer-Facing

Reported example

Billing update

Panther and cub recorded customer.subscription.created. Tier: basic. Status: active.

Why this matters

The message reads like an internal event log rather than intentional product copy. Raw event identifiers and lowercase enum values suggest that localization or user-facing formatting is missing. The concern may extend beyond this one notification.

Intended outcome

Notifications use localized, human-readable copy appropriate to their audience. Internal provider event names, raw enum values, and diagnostic language should appear only where an operator genuinely needs technical detail.

Investigation questions

  • Is this a missing locale key, a fallback string, or intentionally generated backend copy?
  • Who is the intended recipient and what action should the notification support?
  • Are organization name, event name, tier, and status localized at render time or persisted as final prose?
  • Which other notification families contain raw technical vocabulary or missing translations?

Resolution boundary

Audit the notification catalog and fallback behavior rather than patching only the reported sentence. Preserve technical detail in audit logs where useful, but do not make notification copy read like a webhook payload.

Implementation result — 2026-07-28

The reported sentence came from a split and incomplete localization contract:

  • billing notification metadata was created by delivery code but silently discarded during inbox insertion
  • the client attempted to localize billing copy while still rendering raw Stripe event names and raw plan/status enums
  • inbox action labels were persisted as final English prose
  • deterministic organization and portal notification families persisted final English sentences rather than structured template data

The repaired notification contract now:

  • persists structured notification metadata end to end
  • renders billing events as subscription-started, changed, or ended product copy without exposing provider event identifiers
  • localizes plan names, subscription statuses, and notification actions in English, Spanish, French, and Italian
  • uses structured templates for organization security, webhook failure, portal access, portal account security/activity, portal support, and default reminder copy
  • preserves user-authored reminder titles, reminder details, and support subjects as written
  • treats platform-operator notices as the intentional technical exception because their operational detail is the product content
  • replaces raw billing event and enum values in the English billing email with human-readable subscription copy
  • renders legacy billing rows without metadata through safe localized generic copy, so existing inbox entries do not continue exposing provider language

Automated verification covers localized Italian billing output, legacy billing fallbacks, structured portal notifications, reminder copy ownership, destination-derived localized actions, metadata persistence, and billing email copy. App and backend typechecks, changed-file lint, and the full four-locale guard and validator pass.


PROD-01 — The App Lacks A Consistently Obvious, Low-Friction Operating Flow

Concern

The app has many of the necessary building blocks, but day-to-day use still feels like clicking around and adjusting controls until the correct path is found. The product does not yet have the “smartness” or flow expected of a modern operating tool.

This is not a request to add more explanatory copy, more settings, or more steps. It is a request to make the product infer and preserve context, present the next useful action, and remove decisions that do not benefit the user.

Why this matters

Feature completeness is not product coherence. A freelancer or agency operator spends most of the day doing client work, making notes, coordinating projects, tracking follow-through, communicating, and switching contexts. If those activities remain cumbersome, billing and administrative breadth will not make the app worth adopting.

Product outcome

The product should behave as a connected operating layer:

  • current client and project context follows the user where appropriate
  • create flows prefill what the app already knows
  • saved records lead naturally to the next useful action
  • daily priorities are more prominent than passive reporting
  • related work is visible without forcing the user through feature silos
  • interruptions do not require the user to reconstruct their working context
  • common behavior is consistent enough to become instinctive

Required product exercise

Review the app feature by feature and job by job, beginning with the operator's daily work rather than the existing route map.

For each job, document:

  • the trigger that brings the user into the app
  • the context the app already knows
  • the smallest successful path
  • the state or handoff produced by success
  • the next likely action
  • where the current flow asks the user to repeat, classify, approve, link, or navigate unnecessarily

Resolution boundary

This concern cannot be closed by one feature or a cosmetic redesign. It should produce explicit product principles and a sequenced set of bounded workflow changes. It must also remain grounded in real dogfooding rather than speculative automation.

Code-grounded operating-flow audit — 2026-07-28

The first full pass is captured in ../development/operator-job-flow-audit.md.

The audit confirms that aegi should not introduce one mandatory agency funnel. The client account remains the anchor while projects, time, billing, files, portal access, and commercial records stay optional and interoperable. The experience direction is “quietly prepared”: surface what genuinely needs the viewer, what is committed today, and what they can continue, without declaring one correct next move.

The repeated friction is concentrated in seven bounded seams:

  • visible record context is not yet a shared shell-level create contract
  • genuine attention is mixed with prompts to adopt optional features
  • a few high-frequency completion paths still end without an actionable handoff
  • Today has the right work but no bounded cross-queue Start here ordering
  • billing readiness needs owner dogfooding now that one optional period loop exists in Invoices
  • exact portal spotlight routing now needs owner dogfooding
  • the quick-action dock cannot become safely state-aware until context and recommendation truth are stable

The product direction is confirmed. The first implementation slice is safe working-scope inheritance, followed by separating state-driven client attention from optional client-scoped creation.

PROD-01A implementation result — 2026-07-28

The first system-contract slice is now implemented:

  • client and project detail routes publish temporary visible working context to one shell-owned contract
  • global creation consistently resolves explicit context, then visible route context, then persistent client focus
  • project context now reaches global task, timer, note, reminder, drive, link, and contract entrypoints where those records support it
  • client context reaches the related delivery, capture, commercial, file, link, and portal entrypoints
  • changing visible route context does not change persistent client focus
  • explicit mismatched context drops unsafe inherited project/task context instead of composing an invalid relationship

This establishes a reusable product-law layer rather than adding another page convention. PROD-01B can now remove absent optional features from client attention and leave them available as quiet client-scoped creation choices.

PROD-01B implementation result — 2026-07-28

Client overview attention now represents current operational truth:

  • an enabled portal without the person/access context it needs remains actionable
  • an existing billing profile in attention or past_due remains actionable
  • missing projects, invoices, subscriptions, files, and unused billing setup no longer appear as recommendations merely because the feature has not been adopted
  • permission-valid person, project, invoice, and subscription actions remain nearby in a separate Create group

This preserves flexible freelancer and agency workflows while keeping the client page useful. The user can adopt any supported structure without aegi describing the absence of that structure as a problem.

PROD-01C implementation result — 2026-07-28

High-frequency completion paths now preserve momentum while exposing the exact durable result:

  • topbar timer quick-stop offers Open entry for the saved time entry
  • reminder creation offers Open reminder while retaining the existing pinned working-record promotion
  • portal support and project request creation offer Open request without forcing the user away from the current page
  • exact portal request routes preserve the selected client workspace and focus the created request inside its existing history
  • the actionable-success helper now belongs to the shared locale surface rather than the organization route tree

The request and portal response audit also established a restraint rule: replies, owner changes, resolutions, approvals, acknowledgements, and uploads remain confirmation-only when the user is already inside the exact causal record or the success already exposes the submitted file. Action links are for lost context, not decoration.

PROD-01D implementation result — 2026-07-28

Today now orients the workday without choosing the user's work for them:

  • Needs you defaults to actionable operational records owned by the viewer or available in an unassigned shared queue
  • Today holds overdue and due-today tasks, due reminders, and commitments on the viewer's local calendar date
  • Continue holds the active timer, pinned notes, and every remaining open task
  • one page-wide task scope switches between viewer/unassigned tasks and all team tasks
  • the operational lane retains its separate explicit team-queue view
  • calendar, reminder, project, note, timer, and exact working-record destinations remain directly available

The old numeric task-focus score was removed. Tasks keep their backend-defined ordering within deterministic due and continue partitions, so unlike work is no longer presented as one speculative universal ranking.

PROD-01E implementation result — 2026-07-28

Invoices now provides an optional, period-based billing-readiness loop without turning tracked time into required work:

  • All invoices shows readiness only when the viewer may invoice, Stripe is ready, and eligible time exists
  • the period defaults to the current month and supports shared week, month, quarter, year, and custom range controls
  • results are grouped by client and currency and summarize duration, accurately calculated value, project/general-work scope, and period
  • Prepare invoice carries the client, currency, and exact period into a separate draft; it never overwrites an unrelated manual invoice draft
  • the invoice composer still requires an explicit Add to invoice confirmation before reserving exact time entries
  • historical hourly rates and currencies are preserved, while current non-billable and subscription coverage still exclude work correctly
  • pending-review, retainer, non-billable, reserved, invoiced, and subscription-covered time never contributes to readiness
  • missing rates and oversized periods fail visibly and safely instead of producing a plausible but incomplete amount

Manual invoices, manual lines, project-specific invoices, and organizations that do not track time retain their existing direct path. Readiness is a shortcut for available billing input, not an obligation or a new work queue.

PROD-01F implementation result — 2026-07-28

Portal follow-through now preserves the causal record whenever the authorized workspace already has its identity:

  • recent project spotlights open project detail rather than Projects
  • recent shared files and featured resources open their exact artifact when a direct URL exists; URL-less file records are focused inside Files
  • submitted support requests and agency replies focus the exact request thread
  • file-request attention focuses the exact request and its current next step
  • project-update attention opens the project and focuses the exact update
  • contract attention opens the exact agreement review dialog, quote attention focuses the exact quote, and invoice attention opens invoice detail
  • exact handoffs scroll, focus, and visibly mark only records present in the viewer's authorized result set

Request response and acknowledgment success stays quiet when the user is already on the causal request. Generic Open Files toast actions were removed from those cases, while standalone uploads still offer the exact created file. Portal relationship attention also no longer exposes draft quotes that the Agreements workspace correctly keeps internal.

PROD-01G implementation result — 2026-07-28

The quick-action dock is now subtly state-aware without becoming a second sidebar, overview, or pinned-work surface:

  • the attention source is the existing viewer-specific operational workflow truth used by Today
  • one actionable record opens its exact blocker, time entry, file request, support request, or client-feedback destination
  • two or more unrelated records open the anchored Needs you lane rather than receiving a speculative universal priority
  • teammate-owned and view-only records never create a personal cue
  • persistent client focus scopes the cue and destination
  • the collapsed dock uses only a small attention dot; the expanded action shows a truthful count and contextual accessible label
  • configured create actions retain their order, shortcuts, permissions, and behavior, and the attention action is not mixed into customization
  • optional billing readiness remains in Invoices and does not masquerade as an interruption

PROD-02 — Personal, Linked, Internal, And Client-Visible Concepts Are Too Exposed

Concern

The interface asks users to understand distinctions such as:

  • personal versus organizational
  • linked versus unlinked
  • client-associated versus project-associated
  • internal versus client-visible
  • viewable versus not viewable to a client

Some of these distinctions are necessary for permissions and data safety, but the current experience makes the user carry too much of the underlying product model.

Why this matters

Users should not need training in the app's storage and visibility model to capture ordinary work. Repeated classification increases hesitation and creates the risk of accidental disclosure or incorrectly isolated records.

Intended outcome

The system should choose safe, useful defaults from the current context. The UI should expose a distinction only when changing it is meaningful for the user's job.

Technical capabilities may remain in the data model while being:

  • inferred from context
  • defaulted safely
  • progressively disclosed
  • grouped under clearer user-facing language
  • removed from routine flows when they do not affect the outcome

Decisions required

  • What is the simplest user-facing vocabulary for ownership, relationship, and visibility?
  • Which distinctions are required for authorization or disclosure safety?
  • Which distinctions can be derived from the owning surface?
  • Which controls should be exceptional rather than always visible?
  • Does linking a record change ownership, visibility, discoverability, or only context?
  • What defaults should apply in personal, client, project, and client-focus contexts?

Resolution boundary

Do not simplify this only by renaming labels. First define the canonical product model and safety invariants, then decide which parts the interface must reveal.


ARCH-01 — UX Inconsistency Is Reinforced By God Files And Fragmented State Ownership

Concern

The codebase contains large files, accumulated “slush,” and parallel implementations of behavior that should be identical. Notes and topbar state are the clearest reported example, but the same risk applies to linking, visibility, creation, date-time inputs, record previews, and other shared UX contracts.

The open sequencing question is whether to define the deep product model first or refactor the existing code first.

Why this matters

A broad structural cleanup without settled product contracts may preserve the wrong abstractions more neatly. A broad UX redesign on top of fragmented state ownership may deepen duplication and make behavior harder to align.

Intended outcome

Refactoring should follow confirmed product invariants and make those invariants hard to violate:

  • one canonical record identity across presentations
  • one owner for each class of state
  • one shared contract for repeated behavior
  • clear feature and route boundaries
  • small adapters for presentation differences
  • tests that cover cross-surface behavior, not only individual components

Use alternating product and architecture slices:

  1. Confirm one deep product invariant.
  2. Trace every current implementation of that invariant.
  3. Refactor only the ownership and shared boundary needed to enforce it.
  4. implement the improved UX on that boundary.
  5. Add cross-surface regression coverage.
  6. Repeat with the next invariant.

This avoids both an unbounded cleanup project and continued patching of contradictory behavior.

Candidate first invariant

“A note is one canonical record viewable and editable through multiple surfaces” is a strong first slice because NOTE-01 is already trust-breaking and the desired product model is explicit.

Shared shell ownership slice — 2026-07-28

The active-timer retest exposed a broader version of ARCH-01: independent stateful hook instances and parent-owned overlay controls could make two shell surfaces disagree or make one action intercept another. The app-wide audit found and removed a second organization SessionAccessProvider, centralized the persistent organization shell providers, and gave calendar consumers and minute-based urgency displays one controller/clock each.

The timer and client-focus split controls now use the shared ButtonGroup primitive in normal document flow. Numeric z-index utilities were removed from the app surface in favor of the semantic stack. architecture:guard now blocks duplicate org shell state owners, nested rendered controls, undeclared absolute/fixed controls, and numeric or arbitrary z-index utilities during lint.

Resolution boundary

Do not turn this inventory into authorization for an application-wide rewrite. Produce a separate, code-grounded refactor plan after the product invariants and affected ownership boundaries have been inspected.


Suggested Investigation Order

This is a discussion order, not permission to implement the entire list:

  1. NOTE-01: restore trust in canonical note state.
  2. REM-01: correct reminder date-time persistence.
  3. I18N-01: audit user-facing notification localization and raw event copy.
  4. TIME-01: confirm the automatic capture and review-routing policy.
  5. NOTE-02: define and implement the universal Notes autosave contract.
  6. PROD-02: simplify ownership, linking, and visibility vocabulary and defaults.
  7. REM-02: rebuild reminder context selection against that clearer model.
  8. NAV-01: decide the roles and priority of Today versus Overview.
  9. TOP-01: define actionable pinned-project behavior.
  10. REM-03: align reminder opening with the working-record shell model.
  11. NOTE-03: right-size note creation after the note surface model is clear.
  12. NOTE-04: complete topbar note actions under the canonical note model.
  13. PROD-01: continue the broader job-by-job operating-flow review.
  14. ARCH-01: run architecture slices alongside the confirmed product work.

The first five items address immediate trust, correctness, confusing product copy, and repeated daily friction. The foundational reviews continue in parallel as product work, but should be converted into bounded implementation issues before code changes begin.

Issue Status Log

Update this table as individual passes are completed.

IDStatusEvidence or decision link
NOTE-01Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
NOTE-02Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
NOTE-03Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
NOTE-04Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
TIME-01Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
REM-01Closed; owner confirmedOwner confirmation in this document
REM-02Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
REM-03Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
NAV-01Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
TOP-01Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
I18N-01Implemented; automated checks passed; owner dogfood confirmation pendingImplementation result in this document
PROD-01In progress; doctrine confirmed, PROD-01A through PROD-01F implemented../development/operator-job-flow-audit.md
PROD-02Foundational concern captured
ARCH-01In progress; shell ownership slice and automated guards implementedShared shell ownership result above