Marvia-06
Workspace first. Nothing exists outside one.
The Identity & Workspace Engine is the dependency foundation for every later module. Authentication is one entry point into it, never the whole of it.
Providers
3 / 8
Roles
6
Permissions
33
Identity events
18
User → Membership → Workspace → Role → Permissions → Context
Principles
Four rules the engine never breaks
Workspace first
Every resource belongs to a workspace. Nothing exists outside one, so isolation is structural rather than a rule people remember.
Identity is not authentication
Authentication is one entry point into the identity system. Providers are data; adding Passkeys or SAML changes a table, not the kernel.
Permission awareness
Every operation validates workspace membership and a named permission before it touches a repository.
Guest conversion by design
A guest reaches real value first. Sign-in claims the work already done instead of discarding it.
Authentication
Providers are data, not branches
Google and GitHub are live. Everything else is already modelled, hidden until it is switched on.
| Provider | Kind | Status | In auth UI |
|---|---|---|---|
| oauth | active | visible | |
| github | oauth | active | visible |
| email-invite | active | hidden | |
| magic-link | planned | hidden | |
| email-password | planned | hidden | |
| passkey | webauthn | planned | hidden |
| sso-oidc | oidc | planned | hidden |
| sso-saml | saml | planned | hidden |
Guest mode
Value before the sign-in wall
A guest can analyse, preview and browse. Anything that persists, spends or connects asks for an account at the moment it matters.
Allowed
- analyze-website
- preview-report
- browse-marketplace
- read-learning-content
- preview-documentation
Requires an account
- save-report
- create-workspace
- install-extension
- purchase-credits
- connect-service
- generate-ai-action
- access-history
Workspace lifecycle
Six operations, each with a permission and an event
A transition that is not in this table cannot happen. Deletion is soft; purging belongs to retention, not to a feature.
| Operation | From | To | Permission | Event |
|---|---|---|---|---|
| create | — | active | workspace.read | workspace.created |
| rename | active | active | workspace.update | workspace.updated |
| archive | active | archived | workspace.archive | workspace.archived |
| restore | archived | active | workspace.restore | workspace.restored |
| transferOwnership | active | active | workspace.transfer | workspace.ownership.transferred |
| softDelete | active, archived | deleted | workspace.delete | workspace.deleted |
Creation flow
- 1. Workspace name — One field. A slug is derived and can change later.
- 2. Workspace icon — Optional. Defaults to a generated monogram.
- 3. Done — Members, theme, locale and AI providers are settings, not blockers.
Empty state
- Analyze a website — Runs a snapshot and a preview report in one step.
- Connect Search Console — Brings real query data into the workspace.
- Browse extensions — Adds surfaces without touching the kernel.
RBAC
Roles live on the membership, never on the user
A user holds a different role in every workspace. Permissions are granular and named; features ask for a permission, not for a role.
owner
33Full control, including deletion and ownership transfer.
admin
31Manages members, permissions, connectors and extensions.
editor
17Creates and modifies content, projects and reports.
member
15Works inside the workspace and spends credits.
viewer
9Read-only across every workspace surface.
guest
3Scoped, time-boxed read access. Reserved for future use.
Invitations
Email and link invites with a bounded lifetime
Tokens are single use and hashed at rest. Expiry, revocation and resend are part of the contract, not follow-up work.
Policy
- expiryDays: 7
- maxPendingPerWorkspace: 50
- resendCooldownMinutes: 10
- singleUse: true
Lifecycle
issued → delivered → opened → accepted
Sessions & security
Cookies the browser cannot read
Sessions rotate, devices are listable and revocable, and every security event lands in the tamper-evident audit chain.
Session policy
- cookieName: marvia_session
- httpOnly: true
- sameSite: lax
- secure: true
- idleMinutes: 10080
- absoluteDays: 30
- rememberMeDays: 90
- rotateEveryMinutes: 60
Threat controls
- csrf — State-changing requests carry a double-submit CSRF token bound to the session.
- oauth-state — OAuth state and PKCE verifier are generated server side and validated on callback.
- rate-limit — Sign-in, invitation and callback routes are rate limited per IP and per identity.
- rotation — Session identifiers rotate on sign-in, role change and workspace transfer.
- no-browser-secrets — Provider secrets and tokens live server side only; the browser sees a cookie.
- audit — Every security event appends an audit_logs row: sign-in, revoke, role change, invite.
Services & events
Nine services, nine repositories, one event contract
Services own behaviour, repositories own persistence, and the event bus is how everything else finds out.
Services
- IdentityService
- SessionService
- ProfileService
- WorkspaceService
- MembershipService
- PermissionService
- RoleService
- InvitationService
- ContextService
Repositories
- UserRepository
- ProfileRepository
- ConnectedAccountRepository
- SessionRepository
- WorkspaceRepository
- MemberRepository
- RoleRepository
- PermissionRepository
- InvitationRepository
Events
- workspace.created
- workspace.updated
- workspace.archived
- workspace.restored
- workspace.deleted
- workspace.ownership.transferred
- workspace.member.joined
- workspace.member.role.updated
- workspace.member.removed
- workspace.invitation.sent
- workspace.invitation.accepted
- user.created
- user.updated
- user.deleted
- session.created
- session.revoked
- permission.updated
- guest.converted
Constraints
Permanent, non-negotiable
- Identity isolation — no report, credit or billing logic ever lives in the identity layer.
- Workspace context — every operation validates membership and permission, never ambient state.
- Provider agnosticism — no vendor auth. Better Auth is an adapter behind AuthAdapter.
- Guest conversion — the guest-to-user transition preserves snapshots and reports.