Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 23 additions & 16 deletions .claude/skills/work-on-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,13 @@ Use the appropriate type: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `c

```markdown
## Summary

- <1-3 bullet points describing the changes>

Closes #$ARGUMENTS

## Test plan

- [ ] `npm run build` passes
- [ ] `npm run lint` passes
- [ ] Manual verification of <specific things to check>
Expand All @@ -130,6 +132,7 @@ Generated with [Claude Code](https://claude.com/claude-code)
After the PR is created, wait for CI checks to complete and fix any failures.

1. Watch for CI completion:

```
gh pr checks <PR-number> --repo The-Read-Onlys/cscs.dev --watch
```
Expand All @@ -138,13 +141,17 @@ After the PR is created, wait for CI checks to complete and fix any failures.

3. **If any check fails** (max 3 fix attempts):
a. Identify failures:
```
gh pr checks <PR-number> --repo The-Read-Onlys/cscs.dev --json name,state,bucket
```

```
gh pr checks <PR-number> --repo The-Read-Onlys/cscs.dev --json name,state,bucket
```

b. Get failure logs:
```
gh run view <run-id> --repo The-Read-Onlys/cscs.dev --log-failed
```

```
gh run view <run-id> --repo The-Read-Onlys/cscs.dev --log-failed
```

c. Fix the failures in the worktree.
d. Re-run Step 6 (Verify) locally to confirm the fix.
e. Stage specific files, commit with a message like `fix: resolve CI failure in <check-name>`, and push.
Expand All @@ -165,13 +172,13 @@ Ask the user: "Should I close issue #$ARGUMENTS now, or let the PR merge close i

## Error Handling

| Scenario | Action |
|---|---|
| Issue not found | Stop immediately, tell the user |
| Worktree name conflict | Ask user for alternative name |
| Build fails | Fix errors, re-run build |
| Lint fails | Fix errors, re-run lint |
| Push rejected | Pull with rebase, resolve conflicts, push again |
| PR already exists for branch | Show existing PR URL, ask user how to proceed |
| CI check fails | Inspect logs, fix errors, push fix, re-monitor (max 3 attempts) |
| CI monitoring timeout | Tell user to check CI manually, provide PR link |
| Scenario | Action |
| ---------------------------- | --------------------------------------------------------------- |
| Issue not found | Stop immediately, tell the user |
| Worktree name conflict | Ask user for alternative name |
| Build fails | Fix errors, re-run build |
| Lint fails | Fix errors, re-run lint |
| Push rejected | Pull with rebase, resolve conflicts, push again |
| PR already exists for branch | Show existing PR URL, ask user how to proceed |
| CI check fails | Inspect logs, fix errors, push fix, re-monitor (max 3 attempts) |
| CI monitoring timeout | Tell user to check CI manually, provide PR link |
30 changes: 22 additions & 8 deletions AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ Comprehensive audit of the CSCS community website (cscs.dev) covering project he

## Project Stats

| Metric | Count |
|--------|-------|
| Pages | 13 (5 public, 8 authenticated/app) |
| React Components | 12 custom + 28 Catalyst UI Kit |
| Blog Posts | 3 published |
| Test Files | 2 (EventForm: 50+ tests, PocketBase RSVP) |
| NPM Scripts | 13 |
| CI Pipeline Steps | 6 (lint, format, test, build, storybook) |
| Metric | Count |
| ----------------- | ----------------------------------------- |
| Pages | 13 (5 public, 8 authenticated/app) |
| React Components | 12 custom + 28 Catalyst UI Kit |
| Blog Posts | 3 published |
| Test Files | 2 (EventForm: 50+ tests, PocketBase RSVP) |
| NPM Scripts | 13 |
| CI Pipeline Steps | 6 (lint, format, test, build, storybook) |

---

Expand All @@ -43,79 +43,93 @@ Comprehensive audit of the CSCS community website (cscs.dev) covering project he
### HIGH — Broken Links / Placeholder Pages

#### 1. Footer "About" link is a placeholder

- **File**: `src/components/Footer.tsx:5`
- **Issue**: `href: "#"` — navigates nowhere
- **Fix**: Create `/about` page, update link

#### 2. Footer "Contact" link is a placeholder

- **File**: `src/components/Footer.tsx:9`
- **Issue**: `href: "#"` — navigates nowhere
- **Fix**: Create `/contact` page, update link

#### 3. Newsletter "privacy policy" link is a placeholder

- **File**: `src/components/Newsletter.tsx:92`
- **Issue**: `href="#"` — text says "Read our privacy policy" but links nowhere
- **Fix**: Create `/privacy` page, update link. Especially important since the site collects emails and has user registration.

### HIGH — Functionality Gaps

#### 4. Newsletter form may not work in production

- **File**: `src/components/Newsletter.tsx:67`
- **Issue**: Uses `data-netlify="true"` for Netlify Forms, but the site infrastructure uses Podman/PocketBase — no evidence of Netlify deployment. Form submissions may silently fail.
- **Fix**: Integrate with PocketBase (newsletter collection) or a third-party email service. Verify form submissions are actually captured.

### MEDIUM — Code Quality

#### 5. Hero images lack proper decorative attributes

- **File**: `src/components/Hero.tsx:132,142,150,160,168`
- **Issue**: 5 Unsplash images have `alt=""` but no `role="presentation"` or `aria-hidden="true"` to explicitly mark as decorative.
- **Fix**: Add `role="presentation" aria-hidden="true"` to each decorative image.

#### 6. Copyright year is hardcoded

- **File**: `src/components/Footer.tsx:90`
- **Issue**: `© 2025 College Station Computer Science` — will be stale in future years
- **Fix**: Use `{new Date().getFullYear()}` for dynamic year

#### 7. Catalyst link component TODO not resolved

- **File**: `src/components/catalyst/link.tsx:2`
- **Issue**: `// TODO: Update this component to use your client-side framework's link`
- **Fix**: Since this is a static Astro site, remove the TODO or document that `<a>` tags are the correct approach.

#### 8. Field naming inconsistency: `time_zone` vs `timeZone`

- **Referenced in**: `IMPROVEMENTS.md` Phase 3 backlog
- **Issue**: PocketBase uses `time_zone` (snake_case) while JS convention is `timeZone` (camelCase). No clear mapping layer.
- **Fix**: Standardize naming and add explicit mapping in `src/lib/pocketbase.ts`

### MEDIUM — Testing

#### 9. Limited test coverage

- **Current**: Only `EventForm.test.tsx` (50+ tests) and `pocketbase.test.ts` (RSVP functions)
- **Missing**: LoginForm, RegisterForm, AccountDashboard, Header, ScheduleEvents, Newsletter, Footer
- **Fix**: Prioritize tests for auth components (LoginForm, RegisterForm) and ScheduleEvents

### MEDIUM — Documentation

#### 10. CLAUDE.md says "No test suite configured" — inaccurate

- **File**: `CLAUDE.md`
- **Issue**: States "No test suite is configured" and "No test infrastructure — manual testing required." This is outdated — the project has Vitest, React Testing Library, 50+ tests, and CI-integrated testing.
- **Fix**: Update CLAUDE.md with test commands and remove the outdated notes.

#### 11. CLAUDE.md missing auth, events, and app page documentation

- **File**: `CLAUDE.md`
- **Issue**: Documents the original static site but not: login/register/account pages, PocketBase integration, auth store, EventForm, ScheduleEvents, AppLayout, Storybook, container setup.
- **Fix**: Add sections for backend integration, auth architecture, new pages, and new components.

### LOW — Enhancements

#### 12. No RSS feed for blog

- **Issue**: Blog has 3 posts and content collections but no RSS feed
- **Fix**: Install `@astrojs/rss`, create `src/pages/rss.xml.ts`, add autodiscovery `<link>` tag

#### 13. No web analytics

- **Issue**: No tracking configured (Google Analytics, Plausible, etc.)
- **Fix**: Choose privacy-friendly analytics, add to Layout, update privacy policy

#### 14. No deployment documentation or CI/CD deploy step

- **Issue**: `astro.config.mjs` sets site to `https://cscs.dev` but there's no hosting configuration, no deploy step in CI, and no production environment docs.
- **Fix**: Document production hosting, add CI deploy step, document environment variable management.

Expand Down
3 changes: 3 additions & 0 deletions AUTHENTICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ podman-compose up
```

This will:

- Start PocketBase on `http://localhost:8080`
- Start the Astro dev server on `http://localhost:4321`
- Client-side code will automatically connect to `http://localhost:8080`
Expand All @@ -53,6 +54,7 @@ cp .env.example .env
```

Add to `.env`:

```env
PUBLIC_POCKETBASE_URL=http://localhost:8080
```
Expand Down Expand Up @@ -219,6 +221,7 @@ Alternatively, you can manually verify users via Admin Dashboard (Collections
SendGrid wraps all email links with click tracking URLs (e.g., `url8394.cscs.dev`). This is normal behavior and the link will redirect to the actual verification URL after tracking.

To disable link tracking (optional):

1. Login to SendGrid dashboard
2. Go to Settings → Tracking
3. Disable "Click Tracking"
Expand Down
35 changes: 27 additions & 8 deletions backend/MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ podman-compose up
```

**Steps:**

1. Login to the Admin Dashboard
2. Go to "Collections"
3. Create or modify collections using the UI
Expand All @@ -29,6 +30,7 @@ podman-compose up
6. Commit them to git

**Advantages:**

- Visual interface for schema design
- Automatic migration generation
- No syntax errors
Expand All @@ -46,11 +48,14 @@ cd backend
This creates a file like `1234567890_migration_name.js` with the structure:

```javascript
migrate((app) => {
// Upgrade operations
}, (app) => {
// Downgrade operations (optional)
})
migrate(
(app) => {
// Upgrade operations
},
(app) => {
// Downgrade operations (optional)
},
);
```

### 3. Testing Migrations
Expand Down Expand Up @@ -78,13 +83,15 @@ Your production workflow is already configured:
4. **Backups**: Your GCE block storage undergoes scheduled backups

**Migration Flow:**

```
Local Changes → Git Commit → GitHub → CI/CD Build → GCE VM → Container Restart → Migrations Apply
```

## Best Practices

### DO:

- ✅ Use Admin Dashboard for schema changes (automigrate)
- ✅ Commit all migration files to git
- ✅ Test migrations locally before deploying
Expand All @@ -93,6 +100,7 @@ Local Changes → Git Commit → GitHub → CI/CD Build → GCE VM → Container
- ✅ Keep migrations small and focused

### DON'T:

- ❌ Manually edit the production database
- ❌ Delete migration files after they've been applied
- ❌ Modify migration files after committing
Expand All @@ -103,7 +111,7 @@ Local Changes → Git Commit → GitHub → CI/CD Build → GCE VM → Container

### Creating a New Collection

1. Navigate to http://localhost:8080/_/
1. Navigate to http://localhost:8080/\_/
2. Collections → New Collection
3. Choose collection type (Base, Auth, View)
4. Add fields with appropriate types
Expand All @@ -120,6 +128,7 @@ Local Changes → Git Commit → GitHub → CI/CD Build → GCE VM → Container
### Creating Relationships

When creating a relation field:

- **Type**: Relation
- **Collection**: Select the target collection
- **Cascade Delete**: Check if deleting parent should delete children
Expand All @@ -128,6 +137,7 @@ When creating a relation field:
### Adding Indexes

For performance or uniqueness:

1. Edit collection
2. Scroll to "Indexes" section
3. Add index SQL: `CREATE INDEX idx_name ON table (column)`
Expand All @@ -136,6 +146,7 @@ For performance or uniqueness:
## Example: Events and RSVPs Schema

### Events Collection

```
Collection Type: Base
Name: events
Expand All @@ -153,6 +164,7 @@ Fields:
```

### RSVPs Collection

```
Collection Type: Base
Name: rsvps
Expand All @@ -171,13 +183,15 @@ CREATE UNIQUE INDEX idx_event_user ON rsvps (event, user)
For each collection, set appropriate rules:

**Events:**

- List: `@request.auth.id != ""` (authenticated users can list)
- View: `@request.auth.id != ""` (authenticated users can view)
- Create: `@request.auth.id != ""` (authenticated users can create)
- Update: `@request.auth.id != ""` (authenticated users can update)
- Delete: `@request.auth.id != ""` (authenticated users can delete)

**RSVPs:**

- List: `@request.auth.id != ""` (authenticated users can list)
- View: `@request.auth.id != ""` (authenticated users can view)
- Create: `@request.auth.id != "" && @request.data.user = @request.auth.id` (users can only RSVP for themselves)
Expand All @@ -187,22 +201,26 @@ For each collection, set appropriate rules:
## Troubleshooting

### Migration fails on production

1. Check logs: `podman logs pocketbase`
2. Verify migration file syntax
3. Check if migration was already partially applied
4. Use `migrate history-sync` to clean orphaned entries

### Migration file not generated

1. Ensure `--automigrate` flag is enabled (default)
2. Check file permissions on `pb_migrations/` directory
3. Restart PocketBase after making changes

### Schema out of sync

1. Use `./pocketbase migrate collections` to create snapshot
2. Review and apply the generated migration
3. Commit to git

### Testing locally before production

```bash
# 1. Backup your local database
cp backend/pb_data/data.db backend/pb_data/data.db.backup
Expand All @@ -219,15 +237,16 @@ cp backend/pb_data/data.db.backup backend/pb_data/data.db
## TypeScript Integration

PocketBase generates TypeScript definitions automatically:

- Location: `backend/pb_data/types.d.ts`
- Updated when collections change
- Use these types in your frontend code:

```typescript
import type { EventsResponse, RsvpsResponse } from '../backend/pb_data/types';
import type { EventsResponse, RsvpsResponse } from "../backend/pb_data/types";

// Type-safe record access
const event: EventsResponse = await pb.collection('events').getOne('RECORD_ID');
const event: EventsResponse = await pb.collection("events").getOne("RECORD_ID");
```

## Resources
Expand Down
Loading