richardkeep/nova-timenow
A Laravel Nova field that shows the current time and updates live in your resources and dashboards. Configure timezone and display format to add a real-time clock wherever you need it.
Architecture fit. richardkeep/nova-timenow is a Laravel Nova card — a dashboard widget, not infrastructure. It occupies a narrow slot in the Nova admin tier and touches nothing in the application domain: no routes, no controllers, no models, no migrations, no service providers that mutate the container in unusual ways. For a TPM this is the best possible architectural profile for a third-party addition: blast radius is bounded to one card render on one (or a few) dashboards, and it can be removed without leaving state behind. The relevant architectural question is not "does it fit" — it does, if you run Nova — but "is a per-request clock render worth a dependency inside our most privileged UI surface."
Integration feasibility. Low effort, single-digit engineer-hours. composer require plus card registration in a Dashboard::cards() method. There is a documented precondition that must be surfaced early: this package does nothing outside Laravel Nova. If the team is on Filament, Blade-based admin, or a custom React SPA, stop — there is nothing to evaluate.
Primary technical risk: artifact ambiguity. The package metadata, the description, and the prior technical assessments disagree about what the package is. The description describes a field that pre-fills the current timestamp into date/time inputs; the repo name, tagline, and card-shaped write-ups describe a dashboard card that renders clocks across timezones. These are different products with different value propositions (data-entry hygiene vs. at-a-glance situational awareness) and different integration paths. No estimate or ticket should be written until 15 minutes of source-reading resolves this — src/ and resources/js/ are authoritative; the README and description are not. This ambiguity is itself a documentation-quality signal, and it should be logged as such.
Secondary technical risks.
| Risk | Severity | Mitigation |
|---|---|---|
| Supply-chain: 9 stars, 0 dependents, single maintainer, last release Dec 2024 | Medium | Pin exact tag; register maintainer in dependency log; do not treat as load-bearing |
Silent failure on invalid IANA identifiers (EST, PST, US/Eastern) |
Low–Medium | Validate against timezone_identifiers_list() before passing to card meta |
| Client-side vs. server-side time computation | Medium if used for evidence | Determine whether Vue reads browser clock; if so, screenshot trust is compromised |
| Stale compiled assets after a Nova major upgrade | Medium | Add card re-verification to Nova upgrade runbook |
| Locale/12–24h formatting hardcoded | Low | Fork trigger if team spans locales |
Key questions to answer before approving a spike.
Card or a Field? Read src/.composer.json constraints on laravel/nova, laravel/framework, and php? Does the pin match our versions?withMeta, published config, or hardcoded in Vue?Stack fit. Requires Laravel Nova with a version satisfied by the package's composer.json constraint. Everything else — Laravel version, PHP version, database, queue driver — is irrelevant to this package. The integration is one composer entry and one array element in a dashboard class.
Migration path (there is effectively none — by design). Because the package ships no migrations and persists no data, "migration" is really "registration." The recommended path is to install into a staging branch, register on a non-default scratch dashboard, validate for a week with real operators, and only then promote to the ops dashboard the team actually uses. Do not register in NovaServiceProvider::cards() on the main dashboard — that imposes an unrequested change on every Nova user in the org.
// app/Nova/Dashboards/OpsOverview.php — staging first
public function cards(Request $request)
{
$zones = array_values(array_filter(
$request->user()->team_timezones ?: ['UTC'],
fn ($tz) => in_array($tz, timezone_identifiers_list())
));
return [
(new \Richardkeep\TimeNow\TimeNow())->withMeta(['timezones' => $zones])->width('1/2'),
];
}
Compatibility posture. With 0 dependents and 9 stars, we are the compatibility test suite. Every Nova major upgrade is a potential break, and no upstream signal will tell us first. Pin the exact tag (^1.0 is acceptable only if a lockfile pins the resolution), and treat Nova upgrades as requiring explicit card re-verification — php artisan nova:publish and, in a fork, npm run prod.
Sequencing.
src/ and resources/js/, resolve card-vs-field, inspect constraints. Output: a one-page decision note. Gate: do not proceed if the artifact is a field and no resource needs timestamp stamping.composer require pinned, register on scratch dashboard, verify render at 1/3 / 1/2 / full width, light and dark mode, on our exact Nova version. Verify all configured zones resolve without silent blanks.php artisan nova:card and own the ~50 lines rather than subclassing the vendor card.Recommended long-term shape. Given the ~50-line functional surface, the strategic recommendation is to fork into nova-components/ on adoption rather than carry the dependency indefinitely. This eliminates the supply-chain risk, gives us Intl.DateTimeFormat DST correctness and locale formatting for free, and makes the card upgrade-proof. The vendor package is best used as the one-week trial that justifies (or kills) that ½-day fork.
Maintenance burden. Near-zero during steady state, but not zero — and the nonzero parts are the ones teams forget. The card carries two recurring maintenance triggers: (1) Nova major upgrades require asset re-publish and render verification, and (2) timezone config drift as teams reorganize across regions. Neither is large, but both are invisible until something breaks — the failure mode is a blank card, not an alert. Adding "verify timezone card renders" to the Nova upgrade runbook is the entire maintenance story.
Support model. No upstream support relationship exists in any meaningful sense. The maintainer is one person, the repo has 9 stars and 0 dependents, and the last release was December 2024. Recent is not the same as maintained. Operational posture toward this package should be the same as toward vendored code we wrote ourselves: we own the breakage. If it becomes load-bearing for on-call procedures, that is the signal to fork, not to file an upstream issue and wait.
Scaling characteristics. Rendering cost is negligible — one card, one Vue component, a tick interval. The scaling concern is not compute; it is dashboard ergonomics. A single card with eight timezone rows is unscannable; grouped regional cards at 1/3 width are the pattern that scales. At org scale, also consider per-user timezone derivation from a team_timezones attribute so each operator sees their relevant regions rather than a fixed global list — this is the difference between a useful card and one everyone learns to ignore.
Failure modes (ordered by likelihood).
| Failure mode | Symptom | Detection | Response |
|---|---|---|---|
| Stale compiled assets after Nova bump | Blank card or [Vue warn]: Unknown custom element |
Visual + browser console | nova:publish, rebuild fork assets |
| Invalid IANA identifier in config | Blank row or InvalidTimeZoneException |
Manual config review | Guard with timezone_identifiers_list() filter |
| Viewer's browser clock is skewed | Card displays wrong time, screenshot evidence is wrong | Manual comparison to server | Fork to render from server-supplied now()->timestamp |
| Upstream abandonment | No breakage until Nova bump | Calendar checkpoint | Already-forked posture preempts this |
| Hardcoded 12/24h formatting | Locale mismatch for some operators | Operator feedback | Fork trigger |
Critical operational guardrail. Do not derive business rules from what the card displays. No SLA windows, on-call routing, shift boundaries, or incident timeline evidence should be computed from or attested by a widget that may be rendering the viewer's local browser clock. It is a clock for humans, not a time service for systems. Every consumer that matters must read its own Carbon::now($tz). This is the single most important thing to communicate in the adoption announcement, because the failure is silent and only surfaces during an incident review.
Ramp-up. Effectively zero for engineers — composer require and one array element. The real ramp-up cost is policy, not skills: establishing that admin-tier third-party packages of this signal level require an explicit pin-and-fork-or-remove decision, rather than ad-hoc approval. One adoption of this package is a cheap trigger to write that policy. Ten ad-hoc adoptions of packages like it is how admin panels become unmaintainable.
Rollback. Free. Deregister the card, composer remove richardkeep/nova-timenow, php artisan view:clear, php artisan nova:publish. No migrations, no data loss, no coordinated deploy. Use this. Because the exit cost is one hour, the correct decision procedure is trial-with-real-users rather than analysis-heavy approval — the experiment is cheaper than the meeting that would debate it.
How can I help you explore Laravel packages today?