← Back to OlaTime

OlaTime™

Honor your time.

A personal appointment intelligence PWA — a calm, premium app that helps you become more reliable and intentional with your time, with optional Family and Workspace modes for sharing that reliability with the people around you.

Built by Afolaola.


This is the Landing Page package — deployed separately from the App package

This zip contains only the marketing site (index.html) plus what it needs to be self-contained: shared branding, icons, manifest, robots.txt, sitemap.xml, and the Privacy/Terms/documentation pages it links to.

Cross-package links are handled automatically, not just documented. Every "Install OlaTime" and "Try Insights" call-to-action on this page links to app.html and olatime-insights.html — those live in the separate App package. branding/peer-check.js checks at page load whether those pages are actually reachable — if the App package isn't deployed alongside this one, those specific links are automatically disabled (dimmed, aria-disabled) and show a short friendly message instead of ever letting anyone click through to a real 404. Deploy both packages together in the same directory and this becomes a non-issue — the links just work.

One known inconsistency if you deploy both packages together

Both packages ship a manifest.webmanifest with the same filename, but different start_url values (this package's points at ./, the App package's points at app.html). If you deploy both together in the same directory, whichever file gets copied last silently wins. Keep this package's manifest (start_url: "./") for a combined deployment — it's the correct one, since index.html genuinely exists at that root here.

File structure — read this first if you're used to the old layout

GitHub Pages always serves index.html as a directory's default page — there's no way to configure a different default document on static hosting. To make the Overview/Insights landing experience load first (not the app), file roles were swapped:

Every internal link was updated to match (the landing page's "Open app" buttons point to app.html; the app's own home icon and Settings link point back to index.html; the insights dashboard's Home button too).

What's new in this pass

Bugs fixed:

Features added:

Deliberately not done — and why: full personal analytics/habits/achievements *per workspace member* (the real ask is closer to replicating the whole personal app once per teammate — a much bigger effort than a polish pass); scheduled future emails (EmailJS is client-triggered only, can't fire itself later with nothing open — what's real is an *immediate* assignment email); a ground-up visual redesign (already substantially in place; redoing it risks the exact kind of regression this project has been actively avoiding).

What it does

Tech

Still a deliberate no-build progressive web app — plain HTML, CSS, and JavaScript. No framework, no bundler, no dependencies to install.

Setup for the new optional integrations

Everything below is optional — the app works fully without any of it.

OneSignal (real background push): free account at onesignal.com → new Web Push app → paste your App ID and REST API Key into the two blank ONESIGNAL_* values near the top of app.html's script.

EmailJS (workspace invite/assignment emails): free account at emailjs.com (200 emails/month, 2 templates) → connect an email provider → one template with {{to_email}} {{subject}} {{message}} {{workspace_name}} → paste your Service ID, Template ID, and Public Key into the EMAILJS_* values in app.html.

Firestore security rules (required before trusting Workspace Mode with real data):

npm install -g firebase-tools
firebase login
firebase init firestore   # point it at the existing firestore.rules file
firebase deploy --only firestore:rules

Test with the Firebase Local Emulator Suite before using real data — these rules were reasoned through carefully but not run against a live project from where they were written.

Run locally

npx serve .
# or
python3 -m http.server 8000

Then open the URL it prints. To test install + offline, use Chrome DevTools → Application → Service Workers.

> Opening files directly via file:// won't register the service worker. Serve it over http(s)://.

Deploy (free)

GitHub Pages — push to GitHub, then Settings → Pages → deploy from the main branch, root folder.

Netlify — drag this folder onto app.netlify.com, or connect the GitHub repo. No build command; publish directory is the repo root.

Both serve over HTTPS, which is required for PWA install and notifications.

Reminders

Four layers, in order of reliability: in-app (Smart Reminder Engine, always works), browser Notification API (while the tab/installed app is open), real background push via OneSignal (works even fully closed, needs setup above), and email via EmailJS (needs setup above). On iPhone, add OlaTime to your Home Screen (Share → Add to Home Screen) for the most reliable in-app/browser reminders — iOS restricts web notifications for uninstalled sites regardless of the above.

License

MIT © Afolaola

Shared AFOLAOLA branding

branding/ contains the actual shared AFOLAOLA branding package (company

identity JSON + the AFOLAOLA company mark), copied in from

afolaola-shared-package/branding/, plus brand-loader.js, a small

runtime loader written for this integration.

How it works: brand-loader.js fetches company.json,

social-links.json, contact-information.json, and urls.json directly

at runtime and builds window.AFOLAOLA from them. There is no generated

or hand-copied duplicate of this data anywhere — the JSON files themselves

are the only source of truth, so editing one takes effect immediately with

nothing to keep in sync and nothing that can silently drift.

Any page that needs the resolved values awaits window.AFOLAOLA_READY

(a promise); window.AFOLAOLA itself holds safe, generic fallback values

until that resolves, so nothing breaks or shows "undefined" if the fetch

is slow or the JSON is briefly unreachable. All three pages (index.html,

app.html, olatime-insights.html) load it the same way:

<script src="branding/brand-loader.js"></script>

The JSON files and the loader script are precached by the service worker,

so this keeps working offline after the first successful load — consistent

with the rest of the app.

Deliberately not changed: OlaTime's own app icons, favicons, manifest,

and color theme. The shared package's own README is explicit that the

AFOLAOLA mark is for ecosystem attribution, not a replacement for a

product's own visual identity — so OlaTime's PWA icon, installed home

screen identity, and brand colors are untouched.

Not integrated: feedback-module/ (a Supabase-backed feedback +

testimonials widget) is a real, separate feature, not a branding asset —

it wasn't added here since that's a product decision (new external

dependency, needs its own Supabase credentials) rather than something

implied by a branding refactor.

Adopting future shared assets

The shared package today only contains company-identity JSON and one mark

image. When it eventually gains real shared favicons, PWA icons, OG/Twitter

images, splash screens, shared CSS, or shared components, here is exactly

what adopting each looks like — deliberately small, one-time, mechanical

changes rather than another refactor:

contact info, and similarly any future data-only addition): add it to

the relevant JSON file, or add a new key to a new

branding/assets-manifest.json (this file doesn't exist yet — creating

it is itself the "adoption" step for asset *paths* like a favicon file

location). brand-loader.js already fetches assets-manifest.json if

present and exposes its contents as window.AFOLAOLA.assets — no

loader code changes needed when that day comes.

these directly from each HTML file's <head>, before and independent of

our JavaScript running, so they can't be made dynamic through the loader.

Once real shared files exist at e.g. branding/icons/..., update the

<link> tags in each HTML file's <head> to point there — one line per

file, no logic changes.

installability check reads this file as static JSON, not through our

JS. Update the icons array's src values directly if/when shared PWA

icons replace OlaTime's own.

execute JavaScript, so <meta property="og:image"> must be a static tag

in each page's <head>, not injected at runtime. Add the tag once a

real shared OG image exists.

product-agnostic (not the case today — see the shared package's own

branding README on why product-specific styling isn't shared), the

cleanest fit for this codebase would be an additional branding/shared.css

loaded the same way as brand-loader.js, scoped to whatever it exports

(custom properties, utility classes) so it can be adopted incrementally

without touching OlaTime's own stylesheet.

None of this exists yet, and nothing here should be built ahead of time

against assets that don't exist — this section exists so the *next* person

touching this doesn't have to rediscover the shape of the problem.