Skip to content
Open
Show file tree
Hide file tree
Changes from 128 commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
a01db6c
Increase height in repos page
rajashekar Jul 18, 2025
c36a801
Adding github urls
rajashekar Jul 18, 2025
0173158
fix github issue
rajashekar Jul 19, 2025
32e4738
capability to change the image url
rajashekar Jul 19, 2025
fd41751
Add edit hints
rajashekar Jul 19, 2025
5bd9e16
Add edit hints
rajashekar Jul 19, 2025
063f0d6
Adding drag and drop, rearrange posts
rajashekar Jul 19, 2025
edb8316
Adding drag and drop, rearrange posts
rajashekar Jul 19, 2025
b58f6cd
Allow delete of the repo from portfolio
rajashekar Jul 19, 2025
2fb5bc8
t pull Merge branch 'main' of github.com:matmulai/foliolab
rajashekar Jul 20, 2025
ec9640d
Add demo video
rajashekar Jul 20, 2025
c91c42b
Add demo video
rajashekar Jul 20, 2025
06f6223
Add demo video
rajashekar Jul 20, 2025
41743c3
Add demo video
rajashekar Jul 21, 2025
5b909fa
Add comprehensive code review with 20 improvement recommendations
claude Nov 5, 2025
438793a
Fix critical security and stability issues
claude Nov 5, 2025
67d083f
Implement high priority code quality improvements
claude Nov 5, 2025
afa4de9
Implement remaining medium and low priority improvements
claude Nov 5, 2025
f48f1f0
Fix security issues
rajashekar Nov 5, 2025
893c262
Add multi-source portfolio data support
claude Nov 5, 2025
a86f548
Fix: Replace react-router-dom with wouter in data-sources page
claude Nov 6, 2025
165eb24
Fix TypeScript compilation errors in multi-source feature
claude Nov 7, 2025
c6e6a12
Merge pull request #2 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 7, 2025
c30d310
Update home page to prominently feature multi-source portfolio options
claude Nov 7, 2025
a6ba1e9
Merge pull request #3 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 7, 2025
1c1359f
Fix navigation context on data-sources page
claude Nov 7, 2025
3cbe496
Merge pull request #4 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 8, 2025
4801082
Fix missing .js extensions in ES module imports for sources route
claude Nov 10, 2025
12ff1fb
Merge pull request #5 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
d1a2fa8
Fix missing .js extension in medium.ts RSS import
claude Nov 10, 2025
3c098c1
Merge pull request #6 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
d51faf3
Add documentation of portfolio selection flow analysis
claude Nov 10, 2025
0bd8682
Implement wizard-style portfolio creation flow
claude Nov 10, 2025
3dc5258
Merge pull request #7 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
b3e9107
Refactor server logging to use structured logger in server/index.ts
google-labs-jules[bot] Feb 17, 2026
91950dd
Refactor server logging and fix client type errors
google-labs-jules[bot] Feb 17, 2026
eef5da9
Merge pull request #11 from rajashekar/refactor/server-logging-184433…
rajashekar Feb 17, 2026
c471802
feat(ui): add empty state to repo selection and improve accessibility
google-labs-jules[bot] Feb 17, 2026
912c824
perf: move regex patterns to module scope in removeBadges
google-labs-jules[bot] Feb 17, 2026
aa5a394
Fix: Prevent Stored XSS in portfolio generation
google-labs-jules[bot] Feb 17, 2026
02646b5
Merge pull request #15 from rajashekar/sentinel/fix-xss-portfolio-154…
rajashekar Feb 17, 2026
02faa99
Merge pull request #14 from rajashekar/perf/optimize-readme-cleaner-r…
rajashekar Feb 17, 2026
9e24cb3
feat(perf): lazy load repository details in getRepositories
google-labs-jules[bot] Feb 17, 2026
0e0ba9c
Merge pull request #12 from rajashekar/palette-micro-ux-empty-state-1…
rajashekar Feb 17, 2026
e6e58f2
Merge pull request #16 from rajashekar/bolt-perf-lazy-load-repos-1600…
rajashekar Feb 17, 2026
616cdfa
Fix Medium username extraction and improve test coverage
google-labs-jules[bot] Feb 17, 2026
a041ba4
Merge pull request #17 from rajashekar/fix-medium-username-extraction…
rajashekar Feb 17, 2026
83dcc22
Refactor duplicate Vercel header logic into helper function
google-labs-jules[bot] Feb 17, 2026
0fbb0ca
feat(tests): add test coverage for generateProjectSummary in project-…
google-labs-jules[bot] Feb 17, 2026
7be2bbd
Merge pull request #19 from rajashekar/test/project-analyzer-summary-…
rajashekar Feb 17, 2026
3f95d78
Merge pull request #18 from rajashekar/refactor-vercel-headers-799580…
rajashekar Feb 17, 2026
dd4edbd
test: add tests for error response factory and codes
google-labs-jules[bot] Feb 17, 2026
79d5375
Merge pull request #20 from rajashekar/test/error-responses-factory-t…
rajashekar Feb 17, 2026
8ef680d
Refactor isOctokitError to use safer type guards
google-labs-jules[bot] Feb 17, 2026
ba8e9c9
test: add unit tests for RSS to BlogPost conversion
google-labs-jules[bot] Feb 17, 2026
9fab382
chore: improve type safety for request ID
google-labs-jules[bot] Feb 17, 2026
fafeaef
Merge pull request #25 from rajashekar/chore/improve-request-id-typin…
rajashekar Feb 17, 2026
1f5e8ac
Merge pull request #24 from rajashekar/test-rss-conversion-2491327490…
rajashekar Feb 17, 2026
6799f87
Refactor FRAMEWORK_PATTERNS to separate config file
google-labs-jules[bot] Feb 17, 2026
88de3b8
Merge pull request #26 from rajashekar/refactor/framework-patterns-co…
rajashekar Feb 17, 2026
9adfcf0
Merge pull request #23 from rajashekar/refactor-isOctokitError-type-g…
rajashekar Feb 17, 2026
97bde56
chore: replace console logging with logger utility in github lib
google-labs-jules[bot] Feb 17, 2026
27a62d5
fix(security): Redact sensitive data from request logs
google-labs-jules[bot] Feb 17, 2026
6cb6bdd
fix(security): Redact sensitive data from request logs
google-labs-jules[bot] Feb 17, 2026
4c3c71c
πŸ”’ security: fix stored XSS via repository URL and secure Vercel callback
google-labs-jules[bot] Feb 17, 2026
027dc06
πŸ”’ security: fix stored XSS via repository URL and secure Vercel callback
google-labs-jules[bot] Feb 17, 2026
b285ea8
Optimize Octokit instantiation in getReadmeContent
google-labs-jules[bot] Feb 17, 2026
395e7fa
Merge pull request #13 from rajashekar/fix-sensitive-data-logging-863…
rajashekar Feb 17, 2026
5bc681b
Merge pull request #27 from rajashekar/fix-xss-vulnerability-46079285…
rajashekar Feb 17, 2026
e5099a7
Merge pull request #22 from rajashekar/fix-console-logging-github-lib…
rajashekar Feb 17, 2026
56020a1
Refactor portfolio HTML generation to separate module
google-labs-jules[bot] Feb 17, 2026
6e60053
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
6177fd3
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
d9b7efe
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
51e598e
Fix CI failures in portfolio preview and routes
google-labs-jules[bot] Feb 17, 2026
1aec0a8
Merge pull request #28 from rajashekar/perf/optimize-octokit-instanti…
rajashekar Feb 17, 2026
6e42cdf
Merge pull request #21 from rajashekar/refactor-portfolio-generator-1…
rajashekar Feb 17, 2026
70ae65b
perf: Optimize GitHub organization repo fetching with Promise.all
google-labs-jules[bot] Feb 17, 2026
54dd6a3
perf: optimize string concatenation in generateRepoSummary
google-labs-jules[bot] Feb 17, 2026
1de52cb
perf: optimize string concat & resolve merge conflicts
google-labs-jules[bot] Feb 17, 2026
c8b2014
perf: optimize string concat, resolve conflicts & improve type safety
google-labs-jules[bot] Feb 17, 2026
507a1cb
perf: optimize string concat & resolve all conflicts
google-labs-jules[bot] Feb 17, 2026
174d335
Merge pull request #10 from rajashekar/perf-optimize-github-org-fetch…
rajashekar Feb 17, 2026
e881f8e
perf: optimize string concatenation and fix CI build failures
google-labs-jules[bot] Feb 18, 2026
a43846e
Merge pull request #9 from rajashekar/perf-string-concat-169982945445…
rajashekar Feb 18, 2026
5dc91be
πŸ§ͺ improve GitLab README title extraction and add tests
google-labs-jules[bot] Feb 18, 2026
4dafb0e
Merge pull request #29 from rajashekar/testing-improvement-gitlab-rea…
rajashekar Feb 18, 2026
fc09215
Merge branch 'main' of github.com:matmulai/foliolab
Feb 18, 2026
58b314e
fix(security): upgrade dependencies to fix vulnerabilities
Feb 18, 2026
b22a977
fix(ci): upgrade @types/node for vite 7.x compatibility
Feb 18, 2026
a12b7b7
fix(types): use const assertions for vite 7.x server options
Feb 18, 2026
1632a97
fix: address code review feedback from Copilot
Feb 18, 2026
04f9dbf
perf(github): reuse octokit instance when fetching readmes
google-labs-jules[bot] Feb 18, 2026
cbb843e
fix(security): prevent XSS in portfolio generation by sanitizing URLs
google-labs-jules[bot] Feb 18, 2026
0eeabb9
feat(ui): improve accessibility of item selection list
google-labs-jules[bot] Feb 18, 2026
1ed0ddf
Merge pull request #32 from rajashekar/palette-ux-item-selection-a11y…
rajashekar Feb 19, 2026
cc5439a
Merge pull request #31 from rajashekar/sentinel-fix-xss-portfolio-317…
rajashekar Feb 19, 2026
1b60d53
Merge pull request #30 from rajashekar/bolt-performance-octokit-reuse…
rajashekar Feb 19, 2026
a9b7dee
feat(ui): enhance accessibility of source selection page
google-labs-jules[bot] Feb 19, 2026
99697ec
Merge pull request #35 from rajashekar/palette-ux-improvements-100286…
rajashekar Feb 19, 2026
b6e1b56
feat(ui): enhance FAQ section with Accordion component
google-labs-jules[bot] Feb 20, 2026
a3b1da5
feat(security): fix XSS vulnerability in Vercel OAuth callback
google-labs-jules[bot] Feb 20, 2026
633d168
Merge pull request #38 from rajashekar/sentinel-fix-vercel-xss-388266…
rajashekar Feb 21, 2026
8bb7525
perf(client): optimize SelectItemsPage filtering and grouping
google-labs-jules[bot] Feb 25, 2026
4012042
⚑ Bolt: Optimize framework detection with O(1) file lookups
google-labs-jules[bot] Feb 26, 2026
db35fa2
feat(ux): improve accessibility and usability of repository selection
google-labs-jules[bot] Mar 3, 2026
d29a1d7
feat(ui): add aria-label to remove repository button
google-labs-jules[bot] Mar 11, 2026
7b37625
πŸ›‘οΈ Sentinel: [security improvement] Secure Request ID generation
google-labs-jules[bot] Mar 18, 2026
524f412
⚑ Bolt: Extract RegExps in readme-cleaner to reduce compilation overhead
google-labs-jules[bot] Apr 1, 2026
f94c98c
Add ARIA labels to icon-only buttons in DataSources page
google-labs-jules[bot] Apr 6, 2026
f1f11a3
πŸ›‘οΈ Sentinel: [MEDIUM] Fix sensitive data leak in request logging
google-labs-jules[bot] Apr 8, 2026
f8f01ac
πŸ›‘οΈ Sentinel: [CRITICAL] Fix SSRF vulnerability in rss-parser
google-labs-jules[bot] Apr 13, 2026
ebd8f7c
⚑ Bolt: Optimize project analyzer pattern matching
google-labs-jules[bot] Apr 13, 2026
fbc6e4d
🎨 Palette: Add ARIA labels to icon-only buttons in portfolio preview
google-labs-jules[bot] Apr 13, 2026
7cc2699
fix: resolve merge conflicts with origin/main, keeping local enhancem…
Apr 13, 2026
b81ae08
Merge pull request #175 from rajashekar/palette-aria-labels-505133617…
rajashekar Apr 13, 2026
2c07836
Merge pull request #174 from rajashekar/bolt-optimize-project-analyze…
rajashekar Apr 13, 2026
8abd0d5
Merge pull request #173 from rajashekar/sentinel-fix-rss-parser-ssrf-…
rajashekar Apr 13, 2026
672fc60
Merge pull request #162 from rajashekar/sentinel-fix-log-redaction-64…
rajashekar Apr 13, 2026
bd1e1f6
Merge pull request #156 from rajashekar/palette-add-aria-labels-10921…
rajashekar Apr 13, 2026
fc096fb
Merge pull request #142 from rajashekar/bolt/readme-cleaner-regex-opt…
rajashekar Apr 13, 2026
0824c20
Merge pull request #105 from rajashekar/sentinel-secure-request-id-13…
rajashekar Apr 13, 2026
7503214
Merge pull request #88 from rajashekar/palette-a11y-repo-select-aria-…
rajashekar Apr 13, 2026
c8d0c08
Merge pull request #65 from rajashekar/palette-repo-select-ux-1512932…
rajashekar Apr 13, 2026
65a423b
Merge pull request #55 from rajashekar/bolt-framework-detection-optim…
rajashekar Apr 13, 2026
68042a2
Merge pull request #52 from rajashekar/bolt-select-items-optimization…
rajashekar Apr 13, 2026
b33d553
Merge pull request #36 from rajashekar/palette-faq-accordion-51917671…
rajashekar Apr 13, 2026
65613b2
chore: remove unnecessary files and fix broken CONTRIBUTING.md
Apr 13, 2026
20770aa
fix: resolve merge conflicts with upstream/main
Apr 13, 2026
d30dc68
fix: address Copilot review comments
Apr 13, 2026
968b754
fix: make username required in getGitLabProjectsWithTitles to fix TS2345
Apr 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,25 @@ OPENAI_TIMEOUT=60000
# Optional: OpenAI max retries (defaults to 2)
OPENAI_MAX_RETRIES=2

# GitHub API Configuration
# Optional: Batch size for README fetching (defaults to 10)
GITHUB_BATCH_SIZE=10

# Optional: Delay between batches in milliseconds (defaults to 100)
GITHUB_BATCH_DELAY_MS=100

# Vercel Deployment Configuration (optional)
VERCEL_CLIENT_ID=your_vercel_client_id_here
VERCEL_CLIENT_SECRET=your_vercel_client_secret_here

# Application Configuration
APP_URL=http://localhost:5000
NODE_ENV=development
NODE_ENV=development

# Logging Configuration
# Optional: Log level (debug, info, warn, error) - defaults to info
LOG_LEVEL=info

# Server Configuration
# Optional: Request timeout in milliseconds (defaults to 30000)
REQUEST_TIMEOUT_MS=30000
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CI

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run TypeScript type check
run: npm run check

- name: Build project
run: npm run build

- name: Run tests
run: npm run test:run
continue-on-error: true

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7

lint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Check code formatting
run: |
echo "Note: Add prettier or eslint to package.json for formatting checks"
echo "Skipping formatting check for now"
continue-on-error: true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Dependencies
node_modules
pnpm-lock.yaml
yarn.lock

# Build outputs
dist
Expand Down
288 changes: 288 additions & 0 deletions ANALYSIS/EXECUTIVE_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
# Portfolio Selection & Storage - Executive Summary

## The Big Picture

The FolioLab application has **THREE LAYERS** for handling portfolio items from different sources:

1. **Fetching Layer** - Works for all sources (GitHub, Blog, Medium, GitLab, Bitbucket)
2. **Selection Layer** - Only works for GitHub
3. **Display Layer** - Only works for GitHub

## Current State

### What Works (GitHub)

Users can:
1. Connect GitHub account
2. Go to `/repos` page
3. See all their GitHub repositories with checkboxes
4. Search, filter, and select specific repositories
5. See selections saved in real-time to localStorage
6. Click "Generate Portfolio" button
7. See a beautiful portfolio preview with all selected repos

**Components involved:**
- `repo-select.tsx` - Selection UI
- `storage.ts` - Selection state management
- `portfolio-preview.tsx` - Display

### What's Broken (Everything Else)

Users can:
1. Go to `/data-sources` page
2. Enter RSS feed URL, Medium username, etc.
3. Click "Import"
4. Get a success message βœ“
5. But then... **NOTHING**
- No UI to see what was imported
- No way to select specific posts
- Posts are stored but invisible
- Portfolio preview doesn't show them

**Why it's broken:**
- `data-sources.tsx` fetches items but immediately stores them
- No selection UI exists for non-GitHub items
- `portfolio-preview.tsx` hardcoded to only display GitHub repos

## Data Flow Comparison

### GitHub Flow (Complete)

```
GitHub OAuth
↓
/repos page shows repositories βœ“
↓
User selects via checkboxes βœ“
↓
Selection stored in localStorage βœ“
↓
Click "Generate Portfolio" βœ“
↓
/preview shows selected repos βœ“
```

### Blog/RSS Flow (Incomplete)

```
User enters RSS URL
↓
Posts fetched from RSS
↓
Posts stored with selected: false ❌
↓
NO UI to browse/select posts ❌
↓
User goes to /preview (manually) ❌
↓
Portfolio shows only GitHub repos ❌
Posts are invisible ❌
```

## Storage - The Interesting Part

### Local Storage Structure

```javascript
// GitHub repos (legacy key)
localStorage.foliolab_repositories = [
{ id: 1, name: "repo", selected: true, source: "github" }
]

// ALL items (new unified key)
localStorage.foliolab_portfolio_items = [
{ id: 1, name: "repo", selected: true, source: "github" },
{ id: "post-1", title: "Blog", selected: false, source: "blog_rss" },
{ id: "med-1", title: "Medium", selected: false, source: "medium" }
]
```

**Key insight:** The `selected` flag exists for ALL item types, but users can only toggle it for GitHub repos.

### Storage Functions Available

```typescript
// Works for all sources
getPortfolioItems() // Get all items
addPortfolioItems([...]) // Add multiple items
getPortfolioItemsBySource("medium") // Filter by source
togglePortfolioItemSelection(id) // Toggle selected flag ← NOT USED!

// Works for GitHub only
getRepositories() // Legacy GitHub-only getter
saveRepositories([...]) // Legacy GitHub-only setter
toggleRepositorySelection(id) // Legacy GitHub-only toggle
```

## The Three Critical Gaps

### Gap #1: Missing Selection UI for Non-GitHub Sources

**Problem:**
- Blog posts, Medium articles, GitLab projects, Bitbucket repos are fetched and stored
- But users never see them or get to choose which ones to include
- Items are added with `selected: false` by default

**Impact:**
- User wastes time importing posts they didn't want
- Can't curate portfolio content from multiple sources
- Feature is incomplete for 5 out of 6 sources

**Example:**
```typescript
// data-sources.tsx line 76
addPortfolioItems(posts); // ← Directly added, no UI shown!
```

### Gap #2: Portfolio Preview Doesn't Render Non-GitHub Items

**Problem:**
- `portfolio-preview.tsx` is hardcoded to only query and display GitHub repos
- Even though blog posts are in localStorage, they're never displayed
- Code assumes only Repository objects exist

**Impact:**
- Multi-source portfolios don't work
- Users think their imports failed (they're just invisible)

**Code example:**
```typescript
// portfolio-preview.tsx line 72-75
const { data } = useQuery<{ repositories: Repository[] }>({
queryKey: ["/api/repositories"],
// ❌ Only queries GitHub repos, not portfolio items
})
```

### Gap #3: No Navigation Between Layers

**Problem:**
- After importing blog posts, there's no link to view/select them
- User must manually navigate to `/preview` to see anything
- No workflow that ties data sources to selection to preview

**Impact:**
- Confusing user experience
- Users don't know if their import worked
- No clear path from "add data" to "build portfolio"

## What's Actually Stored

After user imports blog posts and Medium articles, their localStorage contains:

```javascript
{
id: "rss-post-1",
title: "My Blog Post",
description: "...",
url: "...",
selected: false, // ← User cannot change this
source: "blog_rss",
publishedAt: "2024-01-15",
author: "John Doe",
tags: ["react", "javascript"]
}
```

The infrastructure to manage `selected` flag exists:
- `togglePortfolioItemSelection(id)` - Ready to use but never called
- Schema has `selected: boolean` for all types
- Storage layer handles it correctly

**But the UI that lets users toggle it is missing.**

## The Fix Strategy

Three components need to be created/updated:

### 1. Create `/portfolio-items` Selection Page
- Display all portfolio items grouped by source
- Show checkboxes for each item
- Allow search and filtering
- Use `togglePortfolioItemSelection()` to manage state
- Show count of selected items per source

**Template:** Copy from `repo-select.tsx`, adapt for multiple item types

### 2. Update `/data-sources` Page
- After fetching items, navigate to `/portfolio-items` page
- OR: Show selection UI inline on same page
- Give user feedback about what was imported

### 3. Update `/preview` Page
- Query all portfolio items (not just repos)
- Render items based on source type
- Show only items with `selected: true`
- Maintain existing editing capabilities

### 4. Update Navigation
- Add `/portfolio-items` route
- Add navigation buttons between pages
- Create logical workflow

## Technical Debt

1. **Dual storage keys:** Still maintaining both `foliolab_repositories` (legacy) and `foliolab_portfolio_items` (new)
- Migration logic in place but old code still used
- Could consolidate to single key

2. **Unused storage functions:** `togglePortfolioItemSelection()` and `getPortfolioItemsBySource()` exist but never called
- These are ready to use once UI is added

3. **Hardcoded GitHub-only rendering:** `portfolio-preview.tsx` assumes Repository[]
- Would need refactoring to support discriminated union rendering

## Files That Need Changes

```
client/src/
β”œβ”€β”€ pages/
β”‚ β”œβ”€β”€ data-sources.tsx [ADD: Navigate to /portfolio-items after import]
β”‚ β”œβ”€β”€ portfolio-items-select.tsx [NEW: Create this file]
β”‚ └── portfolio-preview.tsx [UPDATE: Query and render all sources]
└── App.tsx [ADD: Route for /portfolio-items]
```

## Summary

**The Good:**
- Storage layer supports multi-source items
- All schema types defined with selection support
- Data fetching works for all sources
- Infrastructure for managing selection exists

**The Bad:**
- UI for selecting non-GitHub items is completely missing
- Portfolio preview can't display non-GitHub items
- No workflow connecting the layers
- Users can't control portfolio composition from non-GitHub sources

**The Status:**
- GitHub: Feature complete and working
- Everything else: Feature 70% done (data layer works, UI missing)

---

## Quick Reference

| Aspect | Status | File | Key Function |
|--------|--------|------|--------------|
| GitHub Fetching | βœ“ Complete | `github.ts` | `fetchRepositories()` |
| GitHub Selection | βœ“ Complete | `repo-select.tsx` | `toggleRepo()` |
| GitHub Display | βœ“ Complete | `portfolio-preview.tsx` | `renderPortfolioContent()` |
| Blog Fetching | βœ“ Complete | `sources.ts` | POST `/api/sources/rss` |
| Blog Selection | βœ— Missing | N/A | Should use `togglePortfolioItemSelection()` |
| Blog Display | βœ— Missing | N/A | Not queried or rendered |
| Medium Fetching | βœ“ Complete | `sources.ts` | POST `/api/sources/medium` |
| Medium Selection | βœ— Missing | N/A | Should use `togglePortfolioItemSelection()` |
| Medium Display | βœ— Missing | N/A | Not queried or rendered |
| GitLab Fetching | βœ“ Complete | `sources.ts` | POST `/api/sources/gitlab` |
| GitLab Selection | βœ— Missing | N/A | Should use `togglePortfolioItemSelection()` |
| GitLab Display | βœ— Missing | N/A | Not queried or rendered |
| Bitbucket Fetching | βœ“ Complete | `sources.ts` | POST `/api/sources/bitbucket` |
| Bitbucket Selection | βœ— Missing | N/A | Should use `togglePortfolioItemSelection()` |
| Bitbucket Display | βœ— Missing | N/A | Not queried or rendered |
| Freeform Creation | βœ“ Complete | `sources.ts` | POST `/api/sources/freeform` |
| Freeform Selection | βœ— Missing | N/A | Should use `togglePortfolioItemSelection()` |
| Freeform Display | βœ— Missing | N/A | Not queried or rendered |

Loading