Skip to main content

current-state

Stripe Client Billing Foundation

  • Added backend runtime config for a dedicated Stripe-powered client billing provider without changing Polar SaaS billing.
  • Added Convex schema, connection state, webhook event tracking, Connect callback routing, Stripe Node actions, and webhook sync scaffolding for org-operated client billing.
  • Added app wiring for org billing to connect/reconnect Stripe, refresh connection state, provision and sync Stripe customers from client accounts, and open connected-account billing portal sessions.
  • Added first Stripe-native invoice and subscription operations on top of that foundation, including draft invoice creation, invoice finalize/send/void flows, subscription create/update, and subscription cancel/reactivate actions from the org billing workspace, invoice/subscription detail routes, and client billing tab entry points.
  • Remaining follow-up is the next delivery slice: remaining collaboration closeout depth, richer time reporting polish on top of the now-landed approval and lock workflow, and smaller residue cleanup on top of this live Stripe layer.

Current State

Repo Reality

This repo is already beyond the first real org client-work phase.

The product shape in code today is:

  • org is the live agency staff workspace
  • portal is the live client-facing workspace for account context, delivery visibility, billing visibility, files, activity, and support
  • platform already has operator and directory infrastructure, but full multi-agency operations are still a later phase

The monorepo and route boundaries are no longer just starter scaffolding. The app and backend already carry a real client-work slice.

What Has Shipped

Backend data model

packages/backend/convex/schema.ts now includes the first agency client-work tables:

  • clientAccounts
  • clientContacts
  • projects
  • projectUpdates
  • timeEntries
  • clientBillingProfiles
  • invoiceRecords
  • quoteRecords
  • subscriptionRecords
  • driveItems
  • fileAssets
  • richDocuments
  • contracts
  • fileRequests
  • clientAccessAssignments
  • portalAccessGrants

The repo also includes demo-seeding for this slice under packages/backend/convex/dev/seed/clientWork.ts.

Stripe client-billing foundation is now present in the backend too:

  • organizationStripeConnections
  • stripeConnectStates
  • stripeBillingWebhookEvents

Those tables back the first real agency-operated Stripe layer for:

  • agency Stripe account connection state
  • OAuth callback state for safe reconnect/return handling
  • webhook receipt tracking and idempotent billing sync diagnostics

Org surface

The org dashboard now has live pages for:

  • clients as the live client-accounts surface
  • projects
  • time
  • quotes
  • billing
  • contracts
  • drive
  • portals

Those routes are backed by real Convex functions, not placeholders:

  • org/clientAccounts.ts
  • org/projects.ts
  • org/time.ts
  • org/clientBilling.ts
  • org/clientBillingNodeActions.ts
  • org/clientBillingWebhooks.ts
  • org/clientBillingHttp.ts
  • org/contracts.ts
  • org/drive.ts

Current org functionality is now workspace-first, not just list-first:

  • client accounts can be listed, created, edited, and assigned
  • client create and edit flows now keep the company-level client account as the owning record and automatically seed or re-activate the primary person's portal access when portal access is enabled
  • projects can be listed, created, opened in a detail workspace, and moved through draft and published client-update flows
  • time entries can be listed, logged, summarized, moved through approval states, and locked after approval so finalized entries stop drifting before billing follow-through
  • client billing now runs through the client account model: rich billing identity/defaults can be edited from client create/edit and client detail overview, invoices, quotes, and subscriptions can be authored from the billing workspace and client detail billing tab, and client billing summaries reconcile tracked time with invoice and subscription state
  • invoice, subscription, quote, and contract detail surfaces now expose explicit commercial provenance blocks so client, project, quote, contract, invoice, and subscription handoffs only appear when the relationship is real
  • subscription detail now exposes a richer derived lifecycle view with plan-history and billing-timeline sections based on explicit quote, invoice, and subscription timestamps already in the commercial model
  • the backend now supports agency Stripe connection setup, callback completion, billing-portal session generation, and webhook-first Stripe mirror updates for invoices and subscriptions
  • the visible agency-facing file surface is now Drive, with the current org route acting as a global drive finder on top of driveItems, fileAssets, and richDocuments
  • drive folders, uploads, and docs now run through the drive model instead of the legacy documents table
  • the client drive workspace now supports nested folders on the live drive backend, richer rich-doc authoring via starter structures and live preview/word-count feedback, and a request backlog that can route upload/doc responses into request-targeted folders
  • the drive backend now ships the stronger contributor-upload baseline through driveAccessLinks, driveExternalUploadSubmissions, org-side create/list/revoke link management, portal-side create/list/copy/revoke link management inside visible shared destinations, explicit external provenance on drive items, portal-hosted upload-link resolution, email-OTP verification, and upload-only outside-contributor submission flow
  • quotes and contracts now exist as client-account-scoped commercial records and should stay attached to the same client-account commercial spine instead of drifting into separate relationship models; contracts are no longer Drive-backed, own their own authored content, and now carry their own contract-attachment surface for signed PDFs and supporting files
  • Drive storage metrics are now explicitly Drive-only and roll up file asset bytes without mixing in contract attachments
  • the org overview route is now a real operations dashboard backed by org/workspace:getOrgWorkspaceSummary
  • the org analytics route is now a real reporting drill-in for delivery, finance, and collaboration, including view pills for each reporting slice, drive-storage rankings, richer open file-request backlog reporting, and a client-operating-trends drill-in that reuses the same 30-day trend model shown in client overview
  • org job-switching routes now use real page paths instead of query-param main navigation: time vs time/timer, invoices vs subscriptions, clients/[clientId]/*, and projects/[projectId]/*
  • the client detail workspace now uses real detail subpaths across overview, people, projects, time, drive, contracts, billing, and activity instead of query-param tabs
  • the client detail overview now surfaces cross-track next actions plus compact 30-day operating trends across access, commercial, delivery, and collaboration instead of acting as a static profile sheet
  • the client detail People tab is now the canonical human directory for a client company: clientContacts are the people inside the company and each person now carries unified portal access state (none, invited, active, disabled, suspended) plus their portal role where applicable
  • the client detail People, Projects, and Activity tabs now render as denser operational collections instead of repeated grouped stacks, keeping the client workspace aligned with the rest of the org collection baseline
  • the org-facing company and people ownership model is correct, and the portal runtime now resolves company access through portalAccessGrants so one portal identity can hold multiple client-company grants inside one agency organization
  • the cross-feature ownership audit is now complete: delivery, commercial, collaboration, access, and portal projection still anchor on clientAccount, with remaining drift limited to stable registered naming carryover and legacy presentation residue instead of live ownership regressions
  • org authorization enforcement is now capability-first across org settings and client-work core routes; role checks remain only for ownership invariants and role-transition safeguards
  • org staff access now has an explicit client visibility mode on orgUsers memberships (all vs assigned), so client-company access is no longer an owner-only special case hidden behind assignments alone
  • the org sidebar now exposes Invoices and Subscriptions as first-class top-level destinations instead of nesting them under /billing
  • the org sidebar keeps a single time-records destination that now reads as Entries, while the timer remains a shell and utility route instead of a peer sidebar workspace
  • the invoices workspace now uses the secondary bar for fixed invoice-status queues (All invoices, Draft, Open, Past due, Paid) while search and client filters stay in the local collection toolbar
  • the entries workspace now uses the secondary bar for fixed approval queues (All approvals, Draft, Submitted, Approved) while search stays in the local collection toolbar
  • the entries workspace no longer uses drag-and-drop approval lanes; it now renders as a dense records table with an inline approval dropdown per row
  • the clients workspace now keeps List and Organize as separate secondary-bar modes: List is the default dense table with assigned-member summaries and local status filtering, while Organize is the drag-and-drop status board with search only
  • row-level quick actions are now consistently exposed across the main org collections: clients, projects, time entries, invoices, subscriptions, contracts, and drive finder rows all use the same menu pattern for primary open plus adjacent client/project/billing follow-through where that relationship is real
  • the org sidebar now includes a dedicated Portals workspace for agency-side client portal operations, with fixed secondary-bar queues (All portals, Live, Unlinked, Disabled, Attention) and per-client portal detail sections for overview, access, workspace, and activity
  • the org Portals workspace and per-client portal detail now read from the same unified client-account and client-contact access model as the People tab instead of inferring portal state from a separate primary-contact-only heuristic
  • org shell search is now split into two surfaces: the launchpad remains the fast command-palette layer, while a dedicated topbar Spotlight modal now handles higher-limit operational search with pagination, type filters, and result routing across clients, projects, contracts, invoices, quotes, subscriptions, notes, drive items, time entries, and portal access
  • org search freshness now resyncs dependent search documents when client-facing names change, so related search results do not drift behind renamed client and portal records
  • portal settings now include a company-local People section so client managers can invite portal people, pause or restore access, and revoke pending invites without reopening a second contact-management model
  • docs/app/development/org-workspace-collection-ux.md now defines the org collection taxonomy, including the new client-first drive finder rule: queue-switched record lists for entries and invoices, hybrid list/organize collections for clients, pure record lists for subscriptions and detail-adjacent collections, and a global drive finder for cross-client retrieval
  • docs/app/product/client-drive-spec.md is now the source of truth for the client drive product
  • docs/app/development/client-drive-implementation-plan.md is now the source of truth for the backend schema and migration from documents to driveItems

Core system relationship check

The product spine is now clear enough to treat as a hard expansion guardrail:

  • clientAccount is the company-level anchor across org and portal
  • clientContact is the company-local human record
  • portalUser is the org-scoped external identity, and portalAccessGrant is the company-specific access layer the product is moving toward
  • delivery records (projects, projectUpdates, timeEntries), commercial records (clientBillingProfiles, invoiceRecords, quoteRecords, subscriptionRecords, contracts), and collaboration records (driveItems, fileRequests) all attach to the client account first and only optionally to a project
  • the portal should remain a distilled projection of that same client-account truth, not a second operations model with its own parallel business records
  • the emerging operating doctrine is now explicit in docs/app/product/client-operating-model.md, docs/app/product/cross-feature-link-matrix.md, and docs/app/development/cross-feature-surface-audit.md
  • the client detail workspace is the intended simple home for one client's world, while top-level sidebar workspaces are the advanced operational projections across the same client-root records
  • Drive is explicitly the advanced file-operations surface for general collaboration and retrieval, not the universal owner or required entrypoint for every file action in the product

Org visibility and role assumptions

The current org role model is implemented in orgUsers membership records and uses these base roles:

  • owner
  • admin
  • account_manager
  • staff

Client visibility is already scoped in code:

  • owners have global client visibility inside the organization
  • non-owners now carry an explicit clientAccessMode on orgUsers: all grants global visibility and assigned resolves through active clientAccessAssignments
  • if an assigned non-owner has no active assignments, they have no visible clients in the client-work slice

Current enforcement is intentionally uneven and should be documented as such:

  • client-account create/edit and project create are still allowed for non-staff roles
  • client-access assignment management is now capability-gated through the org team-access policy instead of being owner-only
  • time entry creation and document upload are available to any active org member inside their visible client scope
  • billing access is the one area already gated by the broader org capability system

Portal surface

The portal is now a real client-facing workspace, not just the earlier account shell.

Current portal dashboard areas are:

  • overview
  • projects
  • billing
  • files
  • activity
  • settings
  • support

Portal client-work is now live through workspace-backed views:

  • projects shows client-visible project status, published updates, approved billable time, and shared file counts
  • projects/[projectId] gives a project drill-in with published updates, shared files, and recent activity
  • billing exposes the current client billing snapshot
  • files exposes shared client-visible files
  • active portal sessions are now also gated by the linked client account's portalEnabled flag, so company-level portal disablement turns into real authorization loss instead of just an org-side display toggle

What Is Partial

  • clientContacts is now a live workflow in the client detail workspace and now owns unified portal access state, while portal-side self-service people management now exists as a company-local access settings surface on top of the multi-company portal grant model.
  • Client-level billing detail now lives in the client detail billing tab plus invoice/subscription/quote detail routes; there is intentionally no separate billing-profile detail route.
  • Billing is now a live operational summary plus Stripe-backed write flows for Stripe customer mapping, catalog sync, invoices, quotes, and subscriptions, and subscription detail now includes derived lifecycle context; reporting depth and post-send lifecycle polish are still incomplete.
  • Commercial provenance is now visible in the main detail routes, and project detail plus client/project time surfaces now expose explicit commercial context and billing-readiness cues; broader reporting depth beyond the now-landed analytics drill-in is still incomplete.
  • Time tracking is live, backend approval transitions feed billing rollups, and approved entries can now be locked from the org entries and detail surfaces so finalized records stop being edited accidentally; broader reporting polish and richer team-vs-own workflow depth are still incomplete.
  • Portal files now surface a request inbox, and clients can answer agency file requests with either uploads or docs that route into the requested destination, then acknowledge reviewed requests with actor and timestamp metadata preserved inside the grant-aware portal scope.
  • The visible org drive language, finder layout, row-level quick actions, request backlog, request-aware destination handling, and request lifecycle now have an explicit lightweight terminal rule: org reviews, portal acknowledges, org closes when no further follow-up is needed.
  • Contributor upload is now live in its stronger form: authenticated org users and authenticated portal clients can mint scoped upload links, portal clients can copy and manage those links from first-class portal UI inside visible shared destinations, outside contributors fulfill them without portal accounts through email OTP, and every submission remains destination-scoped and provenance-labeled.
  • Org drive link management now shows whether each contributor link came from agency staff or a portal client, and both org and portal surfaces support copy or reissue handling for any legacy tokenless link state.
  • Deeper collaboration affordances are still incomplete.
  • Quotes and contracts are already part of the client-work spine, but their future depth should stay attached to billing and legal/commercial workflow instead of becoming parallel CRM or document-management systems; contract attachments should stay on the contract surface rather than falling back into Drive.

Validation Status

Current repo-health validation is materially better than the older planning docs suggested:

  • focused backend workspace validation is green, including tests/org/workspace-summary.test.ts, tests/org/overview-summary.test.ts, and tests/portal/workspace-delivery.test.ts
  • app package typecheck is green
  • backend package typecheck is green
  • workspace-wide pnpm typecheck is green
  • backend post-wipe smoke validation is green
  • app i18n guard and inlang validation were previously green and no recent work reopened those surfaces

One environment caveat is still worth noting:

  • in this macOS workspace, the backend premium-operations suite can exceed Vitest's default 5 second timeout, so focused or full backend validation should use a higher timeout (for example --test-timeout=20000) to avoid false negatives

What This Phase Actually Proved

This phase is no longer about deciding whether the agency product should exist. It already exists as a working org-side and portal-side client-work spine.

What it proved:

  • the repo can support real agency client accounts and scoped staff visibility
  • the first billing, time, and collaboration surfaces fit cleanly inside the org workspace
  • the portal can now expose project, billing, and file state in a believable client-facing way
  • the time-to-billing spine can now derive client billing state from tracked work plus invoice and subscription records
  • the org billing workspace can now perform the first real Stripe invoice, quote, subscription, and catalog operations without dropping back to manual mirrored records
  • org project delivery can now move through draft and published update states without reopening the model
  • the schema and seed data are broad enough to support the next detail-layer work without reopening the model

Immediate Constraint

The next work should finish the remaining operational detail and cleanup layer of the existing client-work slice, not invent new product areas.

The repo already has the right first-wave tables. The main gap now is finishing the remaining project, billing-detail, portal-facing, and language/IA coherence work on top of the live client workspace and billing spine.

Current Completion Gate

Use org-workspace-completion-milestone.md as the move-on gate for the current baton.

The short version is:

  • finish the org drive transition from flat documents to a client-first drive model
  • finish org workspace consistency and detail-route IA
  • add the analytics drill-in route
  • polish and deepen the first real Stripe invoice and subscription workflows already in the app
  • keep quotes and contracts anchored as client-account-scoped commercial artifacts inside the same billing and drive model
  • keep company, people, and portal access ownership coherent around the model clientAccount = company, clientContact = person, portal access = state on person, and evolve the access layer to portal identity = org-scoped person, portal access grant = company-specific access
  • keep portal follow-through coherent with what the org workspace already promises

Do not treat another major product expansion as the next step until that gate is materially clear.