No User Accounts — workspace as the collaboration unit
CareerVector deliberately has zero authentication. There is no login, no registration, no profile, no admin role, and no per-user permission. This is a product decision — not a missing feature — and every architectural choice downstream of it depends on the choice surviving.
The contract
- The workspace slug IS the access credential. Anyone with the link can read and write the workspace.
- All participants are equal: human collaborators, friends invited by link, AI agents (browser-bound or MCP-bound), and scheduled scrapers all share one permission level.
- Settings are stored per workspace, not per user. Browser localStorage is only used for cosmetic preferences that do not affect other peers.
- No row in any table carries
user_id,created_by, orowned_by. The workspace is the only identity scope.
The slug is a 16-character nanoid. Guessing it is computationally infeasible at the rate the service can be probed. Treat the URL exactly the way the user already treats it: as a secret bearer token that doubles as the address.
Why the contract holds
- Maximum simplicity. There is no auth middleware, no permission check, no session refresh, no password recovery, no GDPR consent layer wrapped around the application.
- Zero friction to start using the tool. Open a fresh tab and you are inside a workspace.
- Sharing the link is sharing the work. CareerVector exists because looking for a job is a social activity — friends, family, mentors, and recruiters help evaluate offers. Forcing them through a signup flow kills that collaboration before it starts.
Read-only derivative
A planned but narrowly scoped variant of the contract is a read-only view of any workspace. Implementation must satisfy three properties:
- Different URL pattern (
/view/[slug]/dashboard|kanban|cv), so the read and write surfaces never overlap by accident. - All write paths globally disabled — buttons hidden, not just visually disabled. The realtime channel sends sync frames in one direction only.
- Same underlying data. The read-only mode is a projection of the workspace, not a fork.
This is the only sanctioned exception to "link = full access." Anything else (view-only links per collaborator, expiring tokens, RBAC) is out of scope and would betray the contract.
What this rules out
Implementers and AI agents must not, under any circumstance, introduce:
- Sign-in flows or password fields.
- Permission checks of the form "if user is owner, allow X."
- Per-user state. A user preference must either be a workspace-global setting or a non-persistent cosmetic preference in that browser's localStorage.
- "Created by" or "modified by" user identity. The graph already carries
actor identity (
actor_class,actor_id) at the op level via cell origins — that is the right surface for "who wrote this cell." - Recovery, migration, or admin flows that assume an account ladder exists.
The administrative surfaces that DO exist (status, ops, QA) sit outside the product surface and authenticate via shared bearer tokens or admin gates, not user accounts. Those gates are not generalisable into product auth.
Implications for agents and scrapers
Because every link grants the same access, MCP-attached agents, headless scrapers, and human collaborators are interchangeable participants. There is no "agent mode" with reduced privileges; if an agent should not be able to do something, the workspace should not be able to do it either.
This is why cell origin tracking (§13 of CLAUDE.md) is structured by
actor_class and a structured actor_id: it is the only way to tell humans,
system writes, and named agents apart after they have all written through
the same equal access path.