Changelog - 2025-12-25 (#3)
Dark Matter Site: Temporary Email Access with NocoDB Session Capture
Overview
Implemented a streamlined "side door" for temporary access to confidential content. Users click a subtle link, enter their email in a modal, and are immediately granted access. No email verification required - the email and session start time are captured to NocoDB for tracking.
Key deliverables:
- Temporary Access Modal: Clean popup triggered by subtle link
- Instant Access: No verification - submit email, get access
- NocoDB Session Logging: Email + timestamp saved to database
- Mode-Responsive Design: Modal adapts to light/dark/vibrant themes
User Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ Temporary Access Flow │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ /portfolio-gate │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Passcode │ │ Email │ ← Main auth tabs │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ "Get temporary access here" ← Subtle link │ │
│ │ │ │ │
│ └────────────────────┼─────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Modal Popup │ │
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ Temporary Access [X] │ │ │
│ │ │ │ │ │
│ │ │ Enter your email to request temporary access │ │ │
│ │ │ to confidential content. │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ you@company.com │ │ │ │
│ │ │ └─────────────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ [ Get Temporary Access in a brief moment ] │ │ │
│ │ │ │ │ │
│ │ └───────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ POST /api/verify-temp-access │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ Save to NocoDB Set auth cookie │
│ emailAccess table (24 hours) │
│ │ │ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ /portfolio/confidential │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Changes by Area
1. Temporary Access Trigger
Added a subtle link below the auth tabs:
<!-- Temporary Access Link -->
<p class="text-center">
<button
type="button"
id="temp-access-trigger"
class="text-xs text-foreground/40 hover:text-primary transition-colors underline underline-offset-2"
>
Get temporary access here
</button>
</p>
2. Modal Component
Full modal with backdrop blur, close button, and email form:
<div id="temp-access-modal" class="modal-overlay hidden">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content">
<button id="modal-close" class="modal-close">×</button>
<h2>Temporary Access</h2>
<p>Enter your email to request temporary access...</p>
<form method="POST" action="/api/verify-temp-access">
<input type="hidden" name="redirect" value="/portfolio/confidential" />
<input type="email" name="email" placeholder="you@company.com" required />
<button type="submit">Get Temporary Access in a brief moment</button>
</form>
</div>
</div>
</div>
Modal Features:
- Backdrop click to close
- Escape key to close
- Auto-focus on email input
- Form submits on Enter
- Body scroll lock when open
3. Simplified API Endpoint
Created /api/verify-temp-access.ts - much simpler than the full email verification:
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
const formData = await request.formData();
const email = formData.get('email');
// Log to NocoDB (fire and forget)
createEmailAccessSession(email);
// Set auth cookie
cookies.set('universal_portfolio_access', sessionToken, {
httpOnly: true,
secure: import.meta.env.PROD,
maxAge: 60 * 60 * 24, // 24 hours
});
// Redirect to confidential content
return redirect('/portfolio/confidential');
};
Key Differences from verify-email.ts:
| verify-email.ts | verify-temp-access.ts |
|---|---|
| Checks domain allowlist | No domain checking |
| Checks previous sessions | No session lookup |
| May show "pending" message | Always grants access |
| Complex access logic | Simple capture + grant |
4. NocoDB v3 API Fix
Fixed the POST body format for creating records:
Before (broken):
body: JSON.stringify({
emailOfAccessor: email,
sessionStartTime: timestamp,
})
After (working):
body: JSON.stringify([
{
fields: {
emailOfAccessor: email,
sessionStartTime: timestamp,
},
},
])
The v3 API requires:
- Array of records (even for single record)
- Each record wrapped in
{ fields: {...} }
5. Mode-Responsive Modal Styling
/* Light mode */
:global([data-mode="light"]) .modal-content {
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* Dark mode */
:global([data-mode="dark"]) .modal-backdrop {
background: rgba(0, 0, 0, 0.7);
}
:global([data-mode="dark"]) .modal-content {
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
}
/* Vibrant mode - signature purple glow */
:global([data-mode="vibrant"]) .modal-content {
background: rgba(15, 9, 35, 0.95);
border-color: rgba(102, 67, 226, 0.4);
box-shadow:
0 0 40px rgba(102, 67, 226, 0.2),
0 0 80px rgba(102, 67, 226, 0.1);
}
Files Changed Summary
New
| File | Purpose |
|---|---|
src/pages/api/verify-temp-access.ts |
Simple email capture + instant access endpoint |
Modified
| File | Changes |
|---|---|
src/pages/portfolio-gate.astro |
Added trigger link, modal HTML, modal JS, modal CSS |
src/lib/nocodb.ts |
Fixed v3 API POST body format for createEmailAccessSession |
NocoDB Record Format
Each temporary access creates a record:
{
"id": 1,
"fields": {
"emailOfAccessor": "investor@example.com",
"sessionStartTime": "2025-12-25T18:30:00.000Z",
"sessionEndTime": null
}
}
Design Decisions
Why a "Side Door"?
The main auth flow (tabs with Passcode/Email) is for users who have credentials or are from known domains. The temporary access link is for:
- Quick demos to potential investors
- Users who just want to peek at confidential content
- Situations where sharing a passcode is inconvenient
Why No Verification?
For this phase, we prioritized:
- Low friction - Don't scare away interested users
- Data capture - We still get their email for follow-up
- Simplicity - Can add verification later if needed
Future iterations could add:
- Email verification (magic link)
- Time-limited access tokens
- Rate limiting on submissions
Notes / Follow-Ups
-
Session End Tracking: Could add
beforeunloadevent to callendEmailAccessSession()and populatesessionEndTime. -
Duplicate Handling: Currently creates new record for each submission. Could check for existing email first.
-
Rate Limiting: No protection against spam submissions yet.
-
Analytics Dashboard: Could build admin view to see who's accessing content.
-
Access at:
/portfolio-gate→ click "Get temporary access here"