WGU Extension Development
This skill helps you develop and maintain the WGU Extension monorepo, an unofficial browser extension that adds utilities to the WGU website for students.
Project Overview
The monorepo contains three main workspaces:
**extension/**: Browser extension built with WXT framework**functions/**: Firebase Cloud Functions for backend GraphQL API**site/**: React Router website for public documentation**data/**: Community data collection and processing pipelineCore Architecture
Monorepo Structure
**Build tool**: pnpm workspaces**Language**: TypeScript 5.8+ (strict mode enabled)**Extension framework**: WXT (Vite-based)**UI components**: React 19 + Radix UI + Tailwind CSS 4**Backend**: Firebase Cloud Functions + Firestore**API**: GraphQL Yoga with persisted queries**Data processing**: Zod schemas, JSON validation, DVC for large filesKey Configuration Files
`@package.json`: Root workspace scripts`@firebase.json`: Dual database configuration`@extension/manifest.json`: Extension permissions`@extension/wxt.config.ts`: WXT configuration`@flake.nix`: Nix development environment`@functions/src/graphql/allowlist.json`: Whitelisted GraphQL queriesProject Governance
Follow [GitHub Spec Kit](https://github.com/github/spec-kit) principlesConsult `.specify/memory/constitution.md` before significant changesCreate specifications in `specs/` for new featuresUse templates from `.specify/templates/`Development Workflow
Setup Environment
1. **Prerequisites**: Nix with flakes and direnv (automatically provides Node.js 22, pnpm, Firebase CLI, Poppler, Git, DVC, jq, ripgrep)
2. **Allow direnv**: `direnv allow` (loads environment automatically)
3. **Install dependencies**: `pnpm install`
4. **Prepare extension**: `pnpm run postinstall --workspace=extension`
Development Commands
```bash
Start development servers
pnpm run dev:extension # Extension with hot reload
pnpm run dev:functions # Firebase emulator
pnpm run dev:site # Website dev server
pnpm run dev # All workspaces
Build for production
pnpm run build # All workspaces
pnpm run build:extension # Extension only
pnpm run build:prod:with-data --workspace=extension # Production with data
Quality checks
pnpm run typecheck # Type check all workspaces
pnpm run lint # Lint all workspaces
```
Code Style Conventions
**Components**: PascalCase (`SearchPanel.tsx`)**Utilities**: kebab-case (`course-utils.ts`)**React patterns**: Functional components with hooks, context for global state**No `any` types**: Use explicit types always**File organization**: Dedicated `types/` directories for interfacesWorking with Different Workspaces
Extension Development
**Entry points**: `extension/entrypoints/` (content scripts, background worker)**Components**: `extension/components/` (React + Radix UI)**Static assets**: `extension/public/` (includes generated community data)**Storage**: Use `@wxt-dev/storage` for persistent data**Test locally**: Load unpacked extension from `.output/` directoryFirebase Functions
**Source**: `functions/src/`**GraphQL schema**: `functions/src/graphql/schema.ts`**Endpoints**: Public API (`publicApi`) and Admin API (`adminApi`)**Local testing**: `pnpm run serve --workspace=functions`**Deployment**: `pnpm run deploy --workspace=functions`**Security**: Persisted queries only (whitelist in `allowlist.json`)Data Processing
**Directory structure**: `data/{source}/raw/` for raw data, `data/{source}/types/` for schemas**Sources**: WGU catalogs (PDF), Discord servers, Reddit communities, WGU Connect**Validation**: `pnpm run validate:{source} --workspace=data`**Shared types**: `data/types/` published to npm as `@wgu-extension/data`**Pipeline**: Collection → Validation → Processing → Firestore uploadWebsite
**Framework**: React Router**Routes**: `site/app/routes/`**Hosting**: Firebase Hosting**Build**: `pnpm run build --workspace=site`Common Development Tasks
Adding New Features
1. **Check constitution**: Review `.specify/memory/constitution.md` for standards
2. **Create spec**: Use templates in `.specify/templates/` to document feature
3. **Implement**: Follow React patterns (functional components, custom hooks)
4. **Validate**: Run `pnpm run typecheck` and `pnpm run lint`
5. **Test**: Load extension or use emulators for functions
Updating Community Data
1. **Add raw data**: Place in `data/{source}/raw/`
2. **Update schema**: Modify Zod schemas in `data/{source}/types/`
3. **Validate**: `pnpm run validate:{source} --workspace=data`
4. **Transform**: `pnpm run transform --workspace=data`
5. **Ingest**: `pnpm run data:ingest --workspace=extension`
Modifying GraphQL API
1. **Update schema**: Edit `functions/src/graphql/schema.ts`
2. **Add to allowlist**: Update `functions/src/graphql/allowlist.json` with query hash
3. **Test locally**: Use Firebase emulator with `pnpm run serve --workspace=functions`
4. **Deploy**: `firebase deploy --only functions:publicApi`
5. **Update client**: Regenerate types in `graphql-client/` if needed
Working with Catalog PDFs
1. **Ensure Poppler available**: `which pdftotext` (provided by Nix environment)
2. **Validate PDF**: `pdfinfo data/catalogs/pdfs/catalog-YYYY-MM.pdf`
3. **Run parser**: `pnpm run catalog:check --workspace=extension`
4. **Process in batches**: Avoid memory issues with large catalogs
Testing & Validation
Extension Testing
**Manual testing**: `pnpm run dev:extension` → Load in browser**Check manifest**: Build and inspect for errors at `chrome://extensions`**Debug**: Use browser DevTools console for content scriptsData Validation
```bash
pnpm run validate:discord --workspace=data
pnpm run validate:reddit --workspace=data
pnpm run catalog:check --workspace=extension
```
Firebase Testing
```bash
firebase functions:log # View logs
pnpm run test:rules --workspace=functions # Test Firestore rules
```
Performance Checks
```bash
pnpm run analyze --workspace=extension # Bundle size analysis
```
Deployment
Extension Release
**Development**: Automatic builds on feature branches (download from GitHub Actions artifacts)
**Production**:
1. Merge to main
2. Create tag: `git tag v1.2.3`
3. Push tag: `git push origin v1.2.3`
4. GitHub Actions creates release
5. Upload to Chrome Web Store / Firefox Add-ons
Firebase Deployment
```bash
All functions
pnpm run deploy --workspace=functions
Specific function
firebase deploy --only functions:publicApi
Firestore rules
firebase deploy --only firestore:rules
```
Website Deployment
```bash
pnpm run build --workspace=site
firebase deploy --only hosting
```
Troubleshooting
Extension not loading
```bash
pnpm run build:extension
Check chrome://extensions for errors
```
TypeScript errors
```bash
pnpm run clean --workspaces
pnpm install
pnpm run typecheck
```
Firebase functions failing
```bash
firebase functions:log
pnpm run serve --workspace=functions
```
PDF parsing issues
```bash
which pdftotext # Should show path from Nix
pdfinfo <pdf-file> # Validate PDF
```
Security & Privacy
Data Privacy
Only collect public community informationNo personal data from Discord or RedditExtract metadata only, not user contentExtension Permissions
Minimal permissions (WGU domains only)Strict CSP in manifestUse extension storage API, not web storageAPI Security
Firebase security rules enforcedCORS restrictions on function endpointsRate limiting implementedPersisted queries for GraphQL (whitelist only)Performance Guidelines
**Extension bundle**: Keep under 5MB**Content scripts**: Minimize DOM mutations, efficient React rendering**Data processing**: Stream large files, process in batches**Firestore queries**: Use proper indexes (see `firestore.indexes.json`)Important Notes
**Status tracking**: Check `functions/STATUS.md` for GraphQL implementation progress**Archived features**: Legacy documentation in `.specify-archive/features/`**Rate limits**: Discord (10 req/min), Reddit (follow API limits), Firebase (custom limits)**Environment**: Nix provides all tools automatically when entering directory**DVC**: Use for large files (PDFs, large JSON datasets)Resources
**Project Constitution**: `.specify/memory/constitution.md`**Feature Specs**: `specs/`**Functions Status**: `functions/STATUS.md`**GraphQL Client**: `graphql-client/` (npm package with caching)**Shared Types**: `data/types/` (published to npm)