3.5 KiB
Dealspace (muskepo.com)
M&A deal workflow platform for investment banking data rooms. Built for Misha (Michael Muskepo / Johan's son). Primary builder: Mira (James assists).
Ground Rules
Johan is the architect. You are the collaborator.
- Discussion first. Default is conversation. No code until asked.
- Minimal diffs. Change only what's requested.
- Less code, better architecture. Flag opportunities to consolidate.
- Ask, don't assume. Ambiguous → ask first.
- No unsolicited files.
- Mention concerns once, then execute.
Architecture
cmd/server/ — main binary entry point (embeds website/)
api/ — REST API handlers
lib/ — shared: auth, crypto, db, rbac, types
mcp/ — MCP server (planned v2.0)
portal/ — deal room UI (Go templates)
website/ — muskepo.com marketing site (go:embed)
migrations/ — SQLite migrations
docs/ — specs and design docs
Build:
make build # local build
make build-linux # linux/amd64 with CGO + fts5
make deploy # build-linux + deploy to Shannon (root@82.24.174.112)
make test # run tests (CGO + fts5)
Environments
| Environment | Host | URL |
|---|---|---|
| Production | root@82.24.174.112 (Shannon) | dealspace.jongsma.me |
| Local | forge (192.168.1.16) | - |
Deploy path on Shannon: /opt/dealspace/
Key Design Docs
MVP.md— v1.0 scope (what ships, what doesn't)API-SPEC.yaml— REST API specEMBED-SPEC.md— embedded portal specMCP-SPEC.md— MCP server spec (v2.0)ONBOARDING-SPEC.md— invite/onboarding flow
RBAC Roles
7 roles: ib_admin, ib_member, seller_admin, seller_member, buyer_admin, buyer_member, observer. Workstream-scoped permissions. All enforced at DB level — not just UI.
Data Model
Project → Workstream → Request List → Request → Answer
Key fields on requests: assignee_id, return_to_id, origin_id (routing chain).
Security Non-Negotiables
- Pre-dataroom content is DB-level invisible to buyers — not a UI filter
- PDF watermarking at serve time:
{user_name} · {org_name} · {datetime} · CONFIDENTIAL - Audit log on every access grant, file download, status change, login — never disabled
- File storage: compressed + encrypted
- TOTP required for admin roles
Data Access Architecture
Three choke points in lib/dbcore.go — ALL entry data goes through these:
EntryRead(db, cfg, actorID, projectID, filter)— all readsEntryWrite(db, cfg, actorID, entries...)— all writesEntryDelete(db, actorID, projectID, entryIDs...)— all deletes
RBAC: Every choke point calls CheckAccess() before touching data. actorID="" = system/internal (always granted).
No stubs, no wrappers for writes/deletes. Callers use EntryWrite/EntryDelete directly. Read-path convenience helpers are acceptable — they must delegate to EntryRead.
FORBIDDEN:
db.Exec(),db.Query(),db.QueryRow()outside dbcore.go- New wrapper functions that bypass choke points
- Any modification to
lib/dbcore.gowithout Johan's explicit approval
Encryption/compression: Files stored via the designated path in dbcore.go only. Never handle file crypto inline in handlers.
Current Status (Mar 2026)
- Mira is primary builder (Misha's AI)
- Portal templates and layouts in progress
- Invite flow, auto-assign UI (spec 3.b.2) pending
- SMTP not yet configured
- v1.0 target: 6 sprints, demoable to Misha after Sprint 2