Member & Guest Architecture 8 FEB 2026

Role hierarchy, file sharing, activity tracking, payments, and the guest demo experience. Privacy-first analytics throughout.

Deployment Status

ComponentStatusEnvironmentCommit
Guest Activity Tracking LIVE dev + prod f5087e0 (BE) · e91decf (FE)
Member & Guest Roles (Phases 1–3) DEV dev only 2102f08
Guest Registration (Phase 4) DEV dev only ab73bb8 (BE) · 24d300f (FE)
Permission-Aware UI (Phase 5) DEV dev only b72fc12 (FE)
Email Integration (Phase 6) DEV dev only 5aaf1f1
Paddle Payments (Phase 7) DEV dev only 1f98ae8 (BE) · c7a4ddd (FE)
Reference Library (Phase 8) DEV dev only 6c58c8f (BE) · 722b991 (FE)
Audit Logging (Phase 9) DEV dev only 43f1a82
Discovery Pipeline Dashboard PUSHED dev FE only — dummy data, 3 view modes, 10 component files

Role Hierarchy

Super Admin
Everything + ops
Richard
Admin
Org management
Host
Member
Full platform access
£2,000/yr
Trial Member
Full access, time-limited
£99 / 30 days
Guest
View shared files only
Free

Demo recipients enter as Trial Members. Existing users have been backfilled as user_type='member'. The users table now includes user_type, trial_expires_at, invited_by, paddle_subscription_id, and paddle_customer_id columns.

Permission Middleware DEV

Located at backend/app/middleware/permissions.py. Three decorators applied across 28 write endpoints.

DecoratorWho Can AccessBehaviour
require_member member, trial_member, admin, super_admin Blocks guests. Auto-downgrades expired trials. 403 includes upgrade_url.
require_admin admin, super_admin Org-level management operations.
require_super_admin super_admin only Ops, analytics, system-wide admin.

Applied to: upload, search, export, create project, share files, push to reference library, and all admin endpoints. 403 responses include an upgrade_url field so the frontend can show contextual upgrade prompts.

Database Changes

New Tables

guest_activity LIVE
ColumnTypeDescription
idBIGSERIAL PKAuto-incrementing
tenant_idINTEGER FK→ tenants(id)
user_idINTEGER FK→ users(id)
action_typeVARCHAR(50)Specific action (structure_search, page_view, etc.)
action_categoryVARCHAR(30)search / view / interact / export
page_areaVARCHAR(50)search / patents / reactions / targets / pathways / bioactivity
metadataJSONBSafe metadata only — counts, types, modes
created_atTIMESTAMPTZEvent timestamp
session_idUUIDBrowser session grouping

Indexes: user_id+created_at DESC, tenant_id+created_at DESC, session_id, action_category

file_shares DEV
ColumnTypeDescription
idSERIAL PKAuto-incrementing
file_idINTEGER FK→ files(id)
shared_byINTEGER FK→ users(id) who shared
shared_with_emailVARCHARRecipient email
tokenUUID UNIQUEShare link token
permissionVARCHAR(20)view / edit / comment
expires_atTIMESTAMPTZOptional expiry
reference_library DEV
ColumnTypeDescription
idSERIAL PKAuto-incrementing
tenant_idINTEGER FK→ tenants(id)
file_idINTEGER FK→ files(id)
pushed_byINTEGER FKAdmin who pushed the file
created_atTIMESTAMPTZWhen pushed

Reference library files are read-only. Guests can duplicate to their own project to work with the data.

Modified Tables

TableNew Columns
usersuser_type (VARCHAR 20), trial_expires_at, invited_by, paddle_subscription_id, paddle_customer_id
rolesNew entries: member, trial_member, guest, super_admin
audit_loguser_agent column + 13 new action types

File Sharing DEV

Members can share files with anyone via token-based links. Recipients who don't have an account are prompted to register as a Guest (3-field inline form). Guests see only files shared with them.

EndpointMethodDescription
/api/v1/files/{id}/sharePOSTCreate share with token, permission level, optional expiry
/api/v1/files/shared-with-meGETList files shared with current user
/api/v1/files/{id}/share/{share_id}DELETERevoke a share
/api/v1/shared/{token}GETResolve share link (auth + unauth)
/api/v1/files/{id}/duplicatePOSTCopy file + molecules to another project

Sidebar Structure

The GuestGate component greys out member-only features with upgrade tooltips. Locked reference files show a "Duplicate to My Project" button. The ShareDialog modal handles email entry, permission selection, and link copying.

Guest Registration DEV

POST /api/v1/auth/register-guest — creates a guest account and links the share token. The share link landing page at /shared/{token} shows an inline 3-field registration form (name, email, password) and auto-redirects to the shared file after registration.

Paddle Integration DEV

Paddle.js loaded in index.html (sandbox mode). The UpgradePrompt component shows contextual upgrade overlays when guests or expired trial members hit member-only features.

Webhook Handler

POST /api/v1/webhooks/paddle — handles four event types:

Paddle EventPlatform Action
transaction.completedActivate subscription, upgrade user_type
subscription.activatedConfirm active subscription
subscription.canceledDowngrade to guest at period end
subscription.updatedUpdate subscription metadata

Webhook signature verification is enabled when PADDLE_WEBHOOK_SECRET is set. All payment features gracefully degrade if env vars aren't configured — no crashes, just "Contact us" fallbacks.

Email Integration DEV

Via Resend API. Two email templates:

EmailTrigger
Share invitationWhen a member shares a file
Trial expiry reminder5 days before trial_expires_at

Gracefully skips if RESEND_API_KEY is not configured — no errors, no crashes.

Reference Library DEV

Admin-curated locked files pushed to tenants. Guests and members can view but not edit. "Duplicate to My Project" copies the file and its molecules for the user to work with.

EndpointMethodAuthDescription
/api/v1/admin/reference-libraryPOSTAdminPush file to library
/api/v1/reference-libraryGETAnyList reference files for tenant
/api/v1/admin/reference-library/{id}DELETEAdminRemove from library

Guest Activity Tracking LIVE

Privacy by design: The system logs action categories and aggregate counts only. It does not log SMILES strings, compound names, target names, InChIKeys, patent numbers, or any search query text. Guests' research remains their own.

Architecture

Guest Browser ├── Page views, clicks, session events │ └──▶ activityTracker.ts ──▶ POST /api/v2/activity/track ├── API requests (search, view, export) │ └──▶ FastAPI backend │ └──▶ activity_tracking middleware (async fire-and-forget) guest_activity table (PostgreSQL) └──▶ Super Admin Analytics Dashboard

Action Classification — 14 Tracked Routes

MethodRouteaction_typecategorypage_area
POST/api/v2/search/structurestructure_searchsearchsearch
POST/api/v2/search/texttext_searchsearchsearch
POST/api/v2/patents/collisionpatent_collision_searchsearchpatents
GET/api/v2/reactionspage_viewviewreactions
GET/api/v2/reactions/{id}reaction_detail_viewviewreactions
GET/api/v2/compounds/{id}compound_detail_viewviewsearch
GET/api/v2/targets/{id}target_detail_viewviewtargets
GET/api/v2/pathways/{id}page_viewviewpathways
GET/api/v2/bioactivitypage_viewviewbioactivity
GET/api/v2/reactions/{id}/confidenceconfidence_toggleinteractreactions
GET/api/v2/reactions/{id}/routesroute_drawer_openedinteractreactions
GET/api/v2/export/csvdata_exportedexportsearch
GET/api/v2/export/rxndata_exportedexportreactions
GET/api/v2/export/sdfdata_exportedexportsearch

Safe Metadata

ActionMetadataExample
structure_searchSearch type + count{"search_type": "substructure", "result_count": 847}
patent_collision_searchResult count{"result_count": 47}
data_exportedFormat{"format": "csv"}
confidence_toggleMode{"mode": "strict"}

Analytics Dashboard LIVE

Admin API Endpoints

EndpointAuthReturns
GET /api/admin/guest-analyticsSuper AdminPer-guest engagement summaries, feature usage, session counts
GET /api/admin/guest-analytics/{user_id}Super AdminDetailed activity timeline for one guest
GET /api/admin/guest-analytics/aggregateSuper AdminTotals, feature popularity, path distribution

Dashboard Layout

Top Row — 4 Summary Cards
Active Guests
Total Sessions
Avg Duration
Unopened
Second Row — Features + Paths
Most Used Features
Structure Search ████████████
Patent Analysis ████████
Reactions ██████
Targets █████
Pathways ███
Bioactivity ████
Export ██
Path Chosen at Entry
🧪 I Make Molecules — medchem
🛡️ Protect My IP — patents
🔬 The Full Picture — integrated

Engagement Scoring

Follow-up Recommendations

LevelSuggested Action
HIGHReady for a conversation. Ask what they found most useful.
MEDIUMModerate interest. Gentle follow-up about specific features.
LOWBrief visit. Ask if they had time or if something was confusing.
NONEHaven't opened. Send a nudge — link expires soon.

Audit Logging DEV

13 distinct audit event types now logged, with the new user_agent column on audit_log:

Audit Event Types
file_shared file_share_accessed file_share_revoked file_duplicated guest_registered trial_started trial_expired trial_expiry_reminder subscription_created subscription_cancelled reference_library_push reference_library_remove + existing login/file events

Admin Panel Tabs

#TabStatusDescription
1UsersEXISTINGManage users, roles, status
2TenantsEXISTINGManage organisations
3AnalyticsNEWGuest/member engagement dashboard
4Audit LogEXTENDEDNow with 13 event types + user_agent

New Environment Variables

# Resend (email) RESEND_API_KEY=re_xxxxx # Paddle (payments) PADDLE_CLIENT_TOKEN=xxx PADDLE_TRIAL_PRICE_ID=pri_xxx PADDLE_ANNUAL_PRICE_ID=pri_xxx PADDLE_WEBHOOK_SECRET=pdl_xxx

All features gracefully degrade if these aren't set. No crashes — just "Contact us" fallbacks in the UI.

Git Commits

Backend
f5087e0 feat: guest activity tracking and analytics API LIVE
2102f08 feat: Member & Guest architecture (Phases 1–3)
ab73bb8 Phase 4: Guest registration
5aaf1f1 Phase 6: Email integration
1f98ae8 Phase 7: Paddle webhook handler
6c58c8f Phase 8: Reference Library endpoints
43f1a82 Phase 9: Audit logging
Frontend
e91decf feat: analytics dashboard in admin panel LIVE
24d300f Phase 4: Share link landing + auth context
b72fc12 Phase 5: Permission-aware UI, GuestGate, ShareDialog, Sidebar
c7a4ddd Phase 7: Paddle.js integration
722b991 Phase 8: Reference Library push + DuplicateDialog
——————— feat: Discovery Pipeline Dashboard — 3 view modes, detail panel, stage tracking

Discovery Pipeline Dashboard NEW

Top-level page at /pipeline for tracking drug discovery programs across stages. Added to the header nav between Quick Search and other items. Currently uses dummy data (7 programs) — backend API can be wired in later.

Three View Modes

ViewDescription
Pipeline (default)Horizontal swim-lane chart. 10 stage columns (IDE → Ph3). Coloured dot at current stage with progress %. Completed stages show trail line. Cancelled programs show grey X.
TableSortable table with Program, Target, Indication, Stage, Status, Lead, Compounds, Budget (burn bar), Progress (bar), Updated.
Stage Board (Kanban)Cards grouped by stage columns. Each card shows name, target, status badge, progress bar, compound count, budget spent. Horizontally scrollable.

Pipeline Stages

Drug Discovery Pipeline — 10 Stages
IDE · Ideation HIT · Hit Finding H2L · Hit-to-Lead LO · Lead Optimisation CS · Candidate Selection PC · Preclinical IND · IND Filing Ph1 · Phase I Ph2 · Phase II Ph3 · Phase III

Dummy Programs (7)

IDTargetIndicationStageStatusCompoundsBudget
EGFR-4801EGFR T790M/C797SNSCLCLOACTIVE847£2.4M (70%)
KRAS-7220KRAS G12DPancreaticH2LACTIVE312£1.8M (40%)
BRD4-1155BRD4 BD1AMLCSACTIVE1,240£3.2M (90%)
CDK9-0342CDK9Triple-neg breastHITAT RISK156£800K (80%)
PDE10A-6690PDE10ASchizophreniaPCON HOLD2,100£4.1M (90%)
SHP2-4401SHP2Solid tumoursIDEACTIVE0£400K (15%)
HDAC6-2201HDAC6MyelomaH2LCANCELLED450£1.2M (80%)

Detail Panel (right slide-out, 380px)

Click any program row/card to open: program name, target, indication, stage pill + status badge, overall progress bar, compound/hit/lead counts, budget spend bar, milestones list with checkmark circles, cancellation reason (red background for cancelled programs), latest notes, lead & team details, start date, last update. Buttons: "Edit Program" (placeholder) and "View Compounds" (links to files page). Smooth slide animation.

Component Files (10 files)

src/pages/pipeline/PipelineDashboard.tsx     — Main page, header, summary cards, toolbar
src/types/pipeline.ts                        — Types + PIPELINE_STAGES constant
src/data/dummyPipelineData.ts                — 7 dummy programs with milestones
src/components/pipeline/PipelineView.tsx     — Swim-lane view (default)
src/components/pipeline/StageBoard.tsx       — Kanban view
src/components/pipeline/PipelineTable.tsx    — Table view
src/components/pipeline/ProjectDetailPanel.tsx — Right slide-out detail
src/components/pipeline/StatusBadge.tsx      — Reusable status badge
src/components/pipeline/StagePill.tsx        — Reusable stage pill
src/components/pipeline/ProgressBar.tsx      — Reusable progress bar

Share Link Security COMPLETE

Risk identified by Don: A guest could forward their share link to a competitor or someone who shouldn't see the data. This is a known vulnerability in any link-based sharing system. The pharma data room industry (ShareVault, Tresorit, Intralinks) has well-established patterns for this. Discoverant implements a layered defence model — each layer adds protection, and layers 1–2 together make forwarded links essentially unusable.

Design principle: A forwarded link should be completely useless without access to the original recipient's email inbox. No exceptions.

Defence Layers

1
LIVE
Email-Pinned Access
Every share token is bound to a specific email address at creation time. When someone clicks the link, they must authenticate as that exact email before seeing anything. If the authenticated user's email doesn't match file_shares.shared_with_email, access is denied with: "This link was shared with dr.chen@vertex.com. Please ask them to share it with you directly."

The file_shares table already has shared_with_email — this layer enforces the match at the GET /api/v1/shared/{token} endpoint. Based on DocuSign's "Recipient Locking" pattern.
2
LIVE
Email OTP Verification (Don's "Double Sign")
When a guest clicks a share link, a 6-digit one-time code is sent to the pinned email address via Resend. The guest must enter this code before accessing any data. Even if someone has the link AND knows the target email, they still need access to that person's inbox.

Implementation: new share_otps table (token, code, email, expires_at, used_at). Codes expire after 10 minutes. 3 failed attempts locks the share for 1 hour. All OTP events logged to audit_log.
3
LIVE
Domain Restriction
Admins can restrict sharing to specific corporate email domains per tenant. If sharing with Vertex, only @vrtx.com addresses can be entered in the share dialog. Prevents sharing to personal Gmail, competitor domains, or disposable email services.

Implementation: new allowed_domains column on tenants table (JSONB array). Validated at share creation AND at share access. Share dialog shows domain restriction hint.
4
LIVE
Dynamic Watermarking
Guest's name, email, and timestamp stamped across all exported data (CSV, SDF, RXN), structure images, and any printable views. Watermark is visible but doesn't interfere with readability. Based on ShareVault's approach — acts as a powerful deterrent because any leaked document is instantly traceable to the source.

Implementation: server-side watermark injection on all export endpoints when user_type is guest or trial_member. Frontend overlay watermark on data views.
5
LIVE
Session Limits + Access Anomaly Detection
Time-limited sessions (configurable, default 4 hours). IP and user-agent logged on every share access. Analytics dashboard flags anomalies: unexpected geography, multiple IPs in short timeframe, access outside business hours. Admin receives alert for suspicious patterns.

Builds on existing guest_activity tracking — add IP/UA columns and anomaly scoring logic.
6
EXISTS
Confidentiality Agreement Gate
Every guest must accept a legally binding confidentiality agreement before accessing any platform data. Acceptance logged with timestamp, IP address, and user agent. Already built into the demo entry flow — the animated confidentiality screen with Mission Impossible timer. Creates legal paper trail if any data is leaked.

How the Layers Work Together

An attacker who receives a forwarded share link would need to defeat all of these in sequence:

Layer 1 — Email Pin
Must authenticate as the exact email the link was shared with. Blocks casual forwarding entirely.
Layer 2 — Email OTP
Must have access to that person's email inbox to receive the 6-digit code. Blocks even if they create a fake account with that email.
Layer 3 — Domain Lock
Email must be from an approved corporate domain. Blocks personal emails and competitor domains.
Layer 4 — Watermark
Everything is stamped with the guest's identity. Deters sharing because leaks are traceable.
Layer 5 — Anomaly Detection
Unusual access patterns trigger admin alerts. Catches anything that slips through.
Layer 6 — Legal
Signed confidentiality agreement on file. Legal recourse if all else fails.

Implementation Priority

LayerEffortImpactDependencies
1 Email-Pinned Access Half day Critical — blocks the entire forwarding problem None — shared_with_email already exists in schema
2 Email OTP Half day Critical — proves inbox ownership Resend API key configured
3 Domain Restriction 2–3 hours High — prevents sharing to personal/competitor emails Layer 1
4 Dynamic Watermark 1 day Medium — deterrent, traceable leaks None
5 Anomaly Detection 1 day Medium — catch edge cases Activity tracking (already live)
6 Confidentiality Gate Done Legal backstop Already in demo flow

Industry Precedent

This layered approach is standard in pharma data rooms and enterprise document sharing:

PlatformApproach
DocuSignRecipient locking + SMS/phone OTP + access codes + knowledge-based authentication
ShareVaultDynamic watermarking + domain restriction + granular permissions + full audit trail
TresoritZero-knowledge E2E encryption + time-limited access + domain pinning
IntralinksEmail verification + NDA gate + watermarking + DRM controls
DiscoverantEmail pin + OTP + domain lock + watermark + anomaly detection + confidentiality gate

Outstanding TODO

Still to do:
Privacy commitment: This platform tracks feature usage, session duration, and navigation patterns. It does not log specific compound structures, SMILES strings, target names, or search queries. Guests' research remains their own.