Skip to main content

Codebase TODO Audit

This document catalogs all TODO, FIXME, HACK, NOTE, and unimplemented code in the Broadford Living codebase, organized by priority and category.

Last Updated: 14 September 2026

Executive Summary​

Counts below cover open items and informational notes; resolved items are retained separately for reference.

PriorityBackendFrontendTotal
Critical000
High000
Medium112
Informational516

Medium Priority​

1. Apple Push Notification Entitlement​

File: crates/bf_user/src/fcm.rs:459,464

// TODO: Change to ApnsSound::Critical once entitlement is approved
sound: Some(ApnsSound::Simple("alarm.caf".to_string())),
...
// TODO: Change to "critical" once Apple approves the entitlement
interruption_level: Some("time-sensitive".to_string()),

Context: iOS push notification payload for critical alerts (alarms, security events).

Impact: Critical alerts use "time-sensitive" interruption level instead of "critical". This means:

  • Alerts don't bypass Do Not Disturb as aggressively
  • No haptic feedback for critical alerts

Status: Waiting for Apple to approve Critical Alerts entitlement.

Workaround: Using "time-sensitive" which still bypasses notification summary and scheduled delivery.


3. Floor Plan Upload Delay​

File: apps/web/src/api/floorPlans.ts:308

// FUT-TODO
// improve this upload L
await new Promise((resolve) => setTimeout(resolve, 2000));

Impact: Hardcoded 2-second delay after file upload. Poor UX and unnecessary wait time.

Recommendation: Replace with proper upload status polling or progress tracking.


Resolved​

2. Activity Timeline User Lookup​

Status: Resolved on 14 September 2026; independently reviewed, including D1 efficiency and cache maintenance.

Files: crates/bf_resident/src/services/activity_actors.rs, crates/bf_resident/src/handlers/activity.rs, crates/bf_resident/src/models/activity.rs, and apps/web/src/lib/components/ActivityTimeline.svelte.

Activity list responses now include an optional user_display_name. The API resolves Clerk IDs to a current full or partial name, then a primary/nonempty email, then the stored ID. The timeline uses that label and retains the stored identity in its hover text. Existing email actors remain as recorded, avoiding attribution to a different person if an email is reassigned. Automated system actors display System; empty actors display Unknown user. Stored audit records and actor filters are unchanged. These labels reflect current profiles, not names captured at the time of an event.

D1 efficiency: Enrichment adds no database queries, writes, joins, or migrations. The existing filtered activity SELECT finishes before Clerk lookups begin, without an open transaction or database cursor during enrichment. Existing property/timestamp and portfolio/timestamp indexes in migration 018_list_query_indexes.sql support timeline reads. Local SQLite query-plan inspection confirmed their use; deployed D1 latency was not benchmarked. Existing uncapped caller-supplied page limits, large offsets, and actor/action sorting costs are separate from this fix.

Cache maintenance: Display labels use the named Cloudflare Workers Cache API cache activity-actor-labels-v1, not an isolate-local label map. Cached JSON contains only the label and its expiry; the actual cached response carries Cache-Control: max-age=300, and reads also reject expired or malformed entries. Synthetic keys use the Worker's configured BF_RESIDENT_URL, a hash of its Clerk credentials, and a hash of the actor ID. The synthetic URL is never fetched or exposed as a public cache endpoint. This cache adds no D1 traffic.

Entries can survive Worker-isolate recycling within a Cloudflare data centre. Cache API contents are local to that data centre, are not globally replicated, and may be evicted early by Cloudflare. There is no application-enforced 256-entry limit. Profile updates/deletions can leave a cached label visible for up to five minutes on subsequent reads; there is no push invalidation or automatic refresh of an already open timeline. This cache is used only for display, never authorization. Missing users receive a cached ID fallback; lookup failures are not cached. Cache read/parse errors behave as misses, and cache write failures preserve the resolved label.

Lookup limits: A response considers at most 100 distinct Clerk actors, covering the default 100-record page. Cache hits do not consume the separate budget of 20 Clerk fetch attempts. Up to four resolution futures run per request within a two-second total budget, including cache open/read/write. Each miss rechecks the cache after acquiring an isolate-local reservation, so the upper bound is 200 cache reads, 20 Clerk attempts, and 20 cache writes; these are Cache API/external operations, not D1 queries. Larger pages may retain raw IDs after the first 100 distinct actors.

Only the small in-flight reservation set remains in process memory. It caps active resolutions at 20 per isolate, suppresses overlapping resolutions for the same actor, and releases on completion, error, or timeout. It does not coordinate separate isolates. Resolved labels are applied before cache persistence. Cache writes then run best-effort using the remaining overall budget and a 100ms per-write deadline; persistence may be skipped when resolution uses up the budget. A later request can repeat a lookup between reservation release and persistence. Missing credentials, limits, ongoing lookups, Clerk failures, or deadline expiry leave unresolved records with their stored identity. Labels already applied remain visible even if cache writes time out. Dropping a future stops waiting, but does not guarantee cancellation of the upstream Clerk HTTP request or Cache API operation.

Access: Existing activity-route authorization remains in place. Property managers do not need access to the admin user directory.

Validation: All 64 resident-library tests passed, including 12 actor-label/cache tests. Production WebAssembly checking passed; the unchanged API/UI passed the earlier web typecheck. A separate reviewer checked the Cache API adapter, efficiency, coherence, and follow-up fixes, with no actionable findings remaining. Tests cover cache reuse with recreated reservation state, expiry/key isolation, cache failures, warm-hit budget handling, and cancellation during persistence. Cache orchestration tests use a fake adapter; live Cache API, Clerk, and deployed Workers/browser verification remain deployment checks.


Informational Notes​

These are architectural notes and documented limitations, not action items.

1. Notification System Architecture Change​

File: crates/bf_notify/src/lib.rs:80

// NOTE: Scheduled cron jobs have been removed.
// Energy aggregation, backups, and device refresh are now handled by each
// property's Durable Object using the alarm API for distributed scheduling.
// See bf_user::scheduling module for details.
//
// Manual trigger endpoints are retained for admin testing:
// - POST /admin/trigger/energy-aggregation
// - POST /admin/trigger/backup
// - POST /admin/trigger/status-check

Context: Documents architectural shift from centralized cron jobs to distributed DO alarm scheduling.


2. Seeding Limitations in Staging/Production​

File: crates/bf_types/src/resident/seed.rs:34

/// NOTE: This will fail with 522 in staging/production due to Worker self-call limits
/// Use Setup + service endpoints from Python instead
Full,

Context: SeedScope::Full enum variant documentation.

Implication: Full database seeding must use the Python orchestrator in non-local environments.


3. Document Storage Path Assumption​

File: crates/bf_resident/src/handlers/properties.rs:77

// NOTE: this requires we have the documents initial folder structure ...
// URL format: S3_ENDPOINT/BUCKET_NAME/documents/library/{portfolio_id}/{file_id}?...

Implication: Code assumes specific S3 bucket folder structure. Changes to bucket organization could break document retrieval.


4. Mock Behavior Difference​

File: crates/bf_resident/src/handlers/it_setup/handlers.rs:2506

// NOTE this is not what it should be, but it is ok for mock
if is_not_applicable_device_type_for_st(device_type) {

Context: Device external ID setup during IT provisioning.

Implication: Mock mode behavior differs from production for SmartThings device mapping.


5. OTA CSP Hash Non-Exhaustive Enum​

File: crates/bf_mobile/src/ota.rs:208

let csp_hashes: Vec<RuntimeCspHash> = value
.csp_hashes(&asset_key)
.map(|hash| match hash {
CspHash::Script(x) => RuntimeCspHash::Script(x.to_owned()),
CspHash::Style(x) => RuntimeCspHash::Style(x.to_owned()),
_ => unimplemented!(),
})

Context: The CspHash enum is non-exhaustive, requiring the wildcard arm for compilation. Only Script and Style variants are used in practice.

Implication: The unimplemented!() arm should never be reached in the current codebase. If the upstream library adds new variants that are actually emitted, this would panic.


6. Settings Profile Update​

File: apps/web/src/lib/pages/Settings.svelte:17

/** This whole page is for the future can remove now */
function handleSaveProfile() {
// TODO: Implement profile update via Clerk
console.log("Update profile:", { name, email });
}

Context: The Settings page component is not currently used in the app. It is retained in the codebase as a reference for future implementation.

Implication: No user-facing impact. When this page is activated, Clerk profile update integration will need to be implemented.


Summary by Location​

Backend (crates)​

CrateCountItems
bf_user1FCM entitlements
bf_mobile1OTA CSP hash note
bf_notify1Architecture note
bf_types1Seeding limitations
bf_resident2Document storage note, mock behavior note

Frontend (apps)​

AppCountItems
apps/web2Floor plan upload, settings (unused)

Recommendations​

Backlog​

  1. Apply for Apple critical alerts entitlement (external dependency)
  2. Improve floor plan upload flow