docs: add MODULE_SPEC.md with permission model and capabilities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-17 12:30:14 -07:00
parent 2a14925b54
commit b98f09305b
1 changed files with 110 additions and 0 deletions

110
MODULE_SPEC.md Normal file
View File

@ -0,0 +1,110 @@
# rVote — Decision Engine
**Module ID:** `rvote`
**Domain:** `rvote.online`
**Version:** 0.1.0
**Framework:** Next.js 16 / React 19 / Prisma / PostgreSQL
**Status:** Active
## Purpose
Credit-weighted conviction voting engine for collaborative governance. Spaces can run ranked proposals with configurable parameters — daily credit allocation, promotion thresholds, voting periods — and binary final votes. Integrates with the r*.online ecosystem via EncryptID passkey authentication.
## Data Model
### Core Entities (Prisma)
| Model | Key Fields | Relationships |
|-------|-----------|---------------|
| **User** | id, did (EncryptID DID), username, totalCredits | has many SpaceMember, Proposal, Vote, FinalVote |
| **Space** | slug, name, visibility, promotionsThreshold, votingPeriodHours, dailyCredits, maxCredits, startingCredits | has many SpaceMember, SpaceInvite |
| **SpaceMember** | userId, spaceSlug, role (ADMIN/MEMBER), credits, lastCreditUpdate | belongs to User, Space |
| **SpaceInvite** | spaceSlug, email, token, role, expiresAt, maxUses, useCount | belongs to Space |
| **Proposal** | id, title, description, spaceSlug, authorId, status, voteCount, finalYes/No/Abstain | belongs to Space, User; has many Vote, FinalVote |
| **Vote** | userId, proposalId, weight, credits, decayTime | ranking phase vote |
| **FinalVote** | userId, proposalId, vote (YES/NO/ABSTAIN) | binary phase vote |
### Proposal Status Flow
```
RANKING → (crosses threshold) → VOTING → (period expires) → PASSED / FAILED
→ ARCHIVED (manual)
```
## Permission Model
### Space Integration
- **SpaceVisibility:** All four levels supported (public, public_read, authenticated, members_only)
- **Default role for open spaces:** PARTICIPANT (can view proposals and vote)
### Capabilities
| Capability | Required SpaceRole | AuthLevel | Description |
|-----------|-------------------|-----------|-------------|
| `view_proposals` | VIEWER | BASIC | See proposal list and details |
| `create_proposal` | PARTICIPANT | STANDARD | Submit new proposals |
| `cast_vote` | PARTICIPANT | STANDARD | Vote on ranking and final phases |
| `moderate_proposals` | MODERATOR | STANDARD | Edit/archive others' proposals |
| `configure_voting` | ADMIN | ELEVATED | Change space voting parameters |
### Module-Specific Overrides
Currently uses `SpaceRole { ADMIN, MEMBER }` in Prisma. Migration path:
- `MEMBER``PARTICIPANT`
- Add `VIEWER` and `MODERATOR` to the Prisma enum
- Replace `requireSpaceMembership()` / `requireSpaceAdmin()` with `hasCapability()` from SDK
### Current Auth Implementation
- NextAuth 5 (beta) + EncryptID session
- `requireSpaceMembership(slug, session)` checks SpaceMember table
- `requireSpaceAdmin(slug, session)` checks SpaceMember.role === ADMIN
## API Endpoints
| Method | Path | Auth Required | Capability | Description |
|--------|------|---------------|------------|-------------|
| GET | /api/spaces | No | — | List public spaces |
| POST | /api/spaces | Yes | — | Create a new space |
| GET | /api/spaces/[slug] | Depends | view_proposals | Get space info |
| PUT | /api/spaces/[slug] | Yes | configure_voting | Update space settings |
| GET | /api/spaces/[slug]/members | Yes | view_proposals | List space members |
| POST | /api/spaces/[slug]/members | Yes | configure_voting | Add member |
| GET | /api/proposals | Depends | view_proposals | List proposals in space |
| POST | /api/proposals | Yes | create_proposal | Create proposal |
| POST | /api/proposals/[id]/vote | Yes | cast_vote | Submit ranking vote |
| POST | /api/proposals/[id]/final-vote | Yes | cast_vote | Submit final vote |
| GET/POST | /api/spaces/[slug]/invites | Yes | configure_voting | Manage invites |
## Canvas Integration
rVote can embed as a `demo-poll` shape in the rSpace canvas:
- Shape type: `demo-poll`
- Displays question + vote counts inline on canvas
- Click to expand into full voting interface
- Real-time vote count sync via Automerge
## Cross-Module Dependencies
| Module | Integration |
|--------|------------|
| **rSpace** | Embedded poll shapes on canvas |
| **rFunds** | Proposals can trigger funding flows when passed |
| **rNetwork** | Voter graph visualization |
| **canvas-website** | Tldraw integration via shape system |
## Local-First / Offline Support
- Currently server-authoritative (Prisma/PostgreSQL)
- No offline vote caching
- Future: CRDT proposal state for offline draft proposals, sync on reconnect
## Migration Plan
1. Add `VIEWER` and `MODERATOR` to Prisma `SpaceRole` enum (migration)
2. Rename existing `MEMBER` data to `PARTICIPANT` (data migration)
3. Import `SpaceRole` from `@encryptid/sdk` types for client-side use
4. Replace `requireSpaceMembership()` with `hasCapability(role, cap, RVOTE_PERMISSIONS)`
5. Replace `requireSpaceAdmin()` with `hasCapability(role, 'configure_voting', RVOTE_PERMISSIONS)`
6. Add `resolveSpaceRole()` call in API route middleware