← Corpus / astro-knots / spec
Dynamic Webpage to Display Portfolio w Authentication
Dynamically display portfolio information on a branded webpage, with certain types of information only displayed for certain privileges connected to authentication.
- Path
- specs/Dynamic-Webpage-to-Display-Portfolio-w-Authentication.md
- Authors
- Michael Staton, Tugce Ergul
- Tags
- Content-Automation · Digital-Footprint · Social-Media · API-Integration
Context
Context on the Astro-Knots monorepo
We develop and maintain multiple sites for multiple clients. Each site needs to be independently deployed with no dependencies on the Astro-Knots monorepo. However, we have developed patterns and boilerplate code, etc.
Preferred Stack
- [[Tooling/Software Development/Frameworks/Web Frameworks/Astro|Astro]] for [[Vocabulary/Static Site Generators|Static Site Generation]]
- [[Tooling/Software Development/Frameworks/Web Frameworks/Svelte|Svelte]] for dynamic UI.
- [[Tooling/Software Development/Lego-Kit Engineering Tools/ImageKit|ImageKit]] for scalable image CDN.
- [[Tooling/Software Development/Frameworks/Frontend/UI Frameworks/Tailwind|Tailwind]] with tokens edited for the brand we are building for, using our [[lost-in-public/to-hero/Customizing Tailwind|Customizing Tailwind]] best practices.
- Preference for using documents in Markdown or in JSON in the repository over any database use.
- Avoidance of anything React/JSX or React patterns. HTML, CSS, Astro, and Svelte only.
Responsive Design
Most people will be viewing it initially from Mobile. However, analysts will usually want to “dive in” so we need laptop and large screen variants, and a clinically responsive layout.
Current Task & Prompt
astro-knots/sites/hypernova-site/src/content/page-content currently has the portfolio.json file, we should created a new dir and move it, as well as rename the file to lpcommits-portfolio.json. We will need to update imports in various places to assure it works.
Imagined Features / Approach
Clickable Levels of Detail
Logo Clouds. Cards of various sizes and various level of detail, expandable to more detail. Convenient collapse detail. Full pages.
Levels and Interactions
- Level 1: Logo-only grid
- Displays crisp brand marks in a responsive grid
- Clicking a card opens the external site (if available) or a details panel
- Alt text uses
conventionalNameorofficialName
- Level 2: Expandable card (progressive disclosure)
- New component:
LogoCardExpanded--Detail-1.astro - Reveals
blurbShortTxt, key facts, and team members- Team members:
name,role,image,linkedInProfile - May expand the grid object to take up two columns or two rows.
- Team members:
- Sensitive fields (e.g., amounts) are hidden by default and shown only after a passcode is entered
- Close via a visible control or
Esc; maintain keyboard focus for accessibility
- New component:
- Level 3: Detail page per organization (optional)
- Route:
src/pages/portfolio/[slug].astro - Sections: Summary, Metrics (gated), Team, Links
- SEO: unique title/description, OG image
- Route:
Layout Detail Toggler
- For every Portfolio grid, add a toggle button to switch the entire grid between Level 1 and Level 2.
- Include the logo/trademark in the Level 2 cards, refactor the design for elegant layout.
Component Mapping
- Grid:
src/components/basics/grids/LogoGrid--LogoOnly.astro - Card:
src/components/basics/grids/grid-cards/LogoOnlyContainer.astro - Theme-aware image:
src/components/ui/ThemeImage.astro(light/dark assets) - Optional expandable card:
LogoCardExpandable.astro(Astro island with Svelte for toggling)
Data Requirements
- JSON records include: names, logo paths (light/dark), external URL, optional blurb/team
- Sensitive fields are stored in separate JSON fetched only after client-side gate unlock
- Assets live under
public/trademarks; prefer true SVG paths over raster-in-SVG
Accessibility
- Focus rings on cards/buttons;
Enter/Spaceactivate;Esccollapses - Screen-reader friendly labels:
aria-labelon links and controls
Acceptance Criteria
- Two titled sections render: LP Commits and Direct Investments
- Logo grid loads with correct assets in light/dark mode
- Expandable cards display non-sensitive details; sensitive fields require passcode
- No broken links or missing assets during build; alt text present for all logos
Branded Exports and Downloads
It’s common for potential investors and their analysts to want to download a PDF, and download CSV exports.
Approach
- CSV: generate on client from visible fields in grid
- PDF (Phase 2): render a templated Astro page via serverless headless browser
Multiple Layouts & Arrangements
Because it’s so important for analysts to browse and find the information they need, it would be good for them to toggle different layouts with different types of cards and different levels of detail.
Layout Toggles (Phase 2)
- Logo cloud vs card grid
- Filters: sector, stage, region; quick search
Connection to a Google Sheet for Data Variables
When displaying a portfolio, it’s often helpful to have “facts” or “metrics” about any portfolio company. I want to be able to access a Google Sheet through the Google Workspace API, and point to specific numbers or tables.
Implementation Notes (Phase 2)
- Use Google Workspace API to fetch selected cells/rows at runtime
- Protect sensitive values: fetch only after auth; do not embed in static HTML
Strategy for Sensitive Data & Content
When displaying a portfolio, it’s common to have certain financial information like “share price” or “amount invested” hidden in a layer that is only accessible to potential [[Limited Partners]].
I can already imagine there being multiple levels of access requested by the investing partners, so it’s best to think about this system smartly. At base, we should have an accepted passwords list and put sensitive content behind a simple password authentication (note, we should avoid User Accounts unless it’s a Google/Microsoft OAuth that just matches a list of authorized users or organization emails)
Authentication Model
- Phase 1: Simple passcode gate (client-side)
- Env var:
PUBLIC_PORTFOLIO_PASSCODE(non-secret display gate) - Gate unlocks sensitive fields, fetched from a separate JSON
- Env var:
- Phase 2: OAuth allowlist (Google/Microsoft)
- Unlocks the same fields via Astro islands; no backend dependency
Data Separation
- Public JSON: names, logos, links, non-sensitive blurbs
- Private JSON: sensitive fields loaded only after unlock; excluded from static build
Asset Standards
- Prefer SVG logos; avoid raster-in-SVG (causes blurriness on scale)
- Raster formats for photos only; when converting AVIF → PNG/WebP, preserve RGBA and correct stream mapping
Performance & Accessibility
- Lazy-load images; preload above-the-fold logos
- Keyboard and screen-reader support for all interactive elements