Calendar and client visibility
The Contractor Codex has a built-in calendar surface for project deadlines, work sessions, and (optionally) client-facing availability windows. It can also sync two-ways with your Google Calendar.
Two surfaces
- Admin calendar at /admin/calendar — your full project calendar with every event (project deadlines, work sessions, quote followups, invoice reminders, manual entries, imported Google events).
- Client calendar at
/dashboard/calendar— what your clients see. Off by default; opt-in per event.
Connecting Google Calendar
From Settings → Calendar:
- Click Connect Google Calendar.
- Sign in with Google and grant calendar access.
- Pick which of your Google calendars to sync with (default: your primary).
The connection stores an OAuth refresh token (encrypted at rest) and the calendar ID. Each admin in your org connects independently — no shared calendar accounts.
What syncs
Outbound — the portal pushes to Google:
- Work sessions you log (start/stop time, project name, duration)
- Project deadlines (as all-day events on the due date)
- Signed contracts (as a one-time milestone event)
- Quote acceptances (as a one-time milestone)
- Invoice due dates
Inbound — Google pushes to the portal:
- Manual events you create in Google Calendar that mention a project (the portal does best-effort parsing; not perfect)
You can disable any sync direction per-event-type in Settings → Calendar.
Picking a different sync calendar
If you don't want work sessions cluttering your main calendar, create a separate Google calendar (e.g., "Contractor Codex") and pick it in the settings page. Future syncs go to that calendar; existing events stay where they are.
Client-facing calendar
This is opt-in and off by default. When on, clients see a Calendar tab in their portal at /dashboard/calendar listing events you've marked client-visible.
Two locks
The portal uses two-step gating to make sure admin-internal events never leak to clients:
Lock 1: Per-event flag (clientVisible, default false)
Every calendar event has a clientVisible checkbox in the event editor. Off by default — existing events default to invisible. You opt events in one at a time.
Lock 2: Org-wide gate (customer_calendar_visible, default false)
In Settings → Calendar, the Client-facing calendar card has a pill toggle. Off by default — even when individual events are flagged client-visible, the entire client Calendar tab is hidden until you flip this toggle.
Defense in depth: even if the UI logic regressed, the customer-side Prisma query filters by clientVisible: true at the data layer.
What clients see when it's off
The Calendar tab in their portal shows a single muted card:
Calendar viewing isn't available
[Your Business Name] has the calendar turned off. If you need to schedule a call, reach out to them directly and they can switch it on or send you a time.
No DB query runs in that branch.
What clients see when it's on
The Calendar tab shows their visible events split into Upcoming and Past. Each event shows:
- Title, time, optional description, optional location
- A small icon if it's all-day
Privacy scope at the query layer: clients only see events that are:
- Marked client-visible AND
- Generic (no customer/project link), OR tied to this customer, OR tied to one of this customer's projects.
Another customer's scoped events never reach this client's query.
Typical use cases
- Availability windows — Mark slots in your calendar as "Open for calls" and flip them client-visible. Clients see when you're available and can email to book.
- Project milestones — Mark deliverable dates client-visible so clients know when things land.
- Kickoff meetings — Tied to a specific project, marked visible — only that client's portal shows them.
Admin-only events (work sessions, internal follow-ups, imported personal calendar items) stay private because their clientVisible defaults to false and the project-internal events are auto-created without the flag set.
Configuring per-event visibility
When you create or edit an event from /admin/calendar, the modal has a Visible to clients checkbox below "All day". Tick it to opt the event in.
The event's body description and location both show to clients — keep them client-appropriate. The portal doesn't sanitize the text.
Disconnecting Google Calendar
To stop syncing, go to Settings → Calendar and click Disconnect. Existing events stay in both places — the portal won't push new updates or pull new events.
