feat: base64 uploads, reusable forms, Discord roles, and UX improvements #66

Merged
naomi merged 8 commits from fix/base64 into main 2026-02-20 20:32:52 -08:00
Owner

Summary

This PR includes multiple feature additions and fixes to improve the library application:

๐ŸŽจ Base64 Image Upload Support

  • Fixed Fastify body limit (1MB โ†’ 10MB) to accommodate base64-encoded images
  • Corrected base64 size calculation and validation logic
  • Improved error handling with proper 400 status codes and helpful messages
  • Removed duplicate validation that was blocking uploads
  • Users can now upload cover images up to 5MB (decoded size)

๐Ÿ“ Reusable Form Components

  • Created 6 form components: GameForm, BookForm, MusicForm, ShowForm, MangaForm, ArtForm
  • All forms support both 'add' and 'edit' modes with pre-population
  • Integrated inline editing into all detail views (edit/delete buttons)
  • Enhanced admin suggestions workflow with full forms instead of basic modals
  • Added scroll-to-top when clicking edit in list views for better UX

๐Ÿ–ผ๏ธ Default Cover Image

  • Added beautiful library reading image as default cover for all media types
  • Fixed static asset serving to use correct MIME types
  • Updated all 12 components (6 list views + 6 detail views) to always show images

๐Ÿ”’ Tiered Rate Limiting

  • Unauthenticated users: 100 requests/minute
  • Authenticated users: 500 requests/minute (5x more lenient)
  • Admin users: No rate limits (complete bypass via allowList)

๐ŸŽฎ Discord Integration

  • Auto-assign library member role to users in NHCarrigan Discord server
  • Checks server membership on every login
  • Only assigns role if user is in server and doesn't have it yet
  • Graceful error handling without blocking login
  • Similar pattern to badge refresh flow

๐Ÿ“š Documentation

  • Added comprehensive CLAUDE.md with:
    • Project structure and tech stack
    • Development workflow and commands
    • Database schema documentation
    • Authentication flow details
    • Security features
    • Code style conventions
    • Common gotchas and solutions

Test Plan

  • Base64 image uploads work for cover images up to 5MB
  • Helpful error messages appear for validation failures
  • Edit/delete buttons appear on all detail views for admin users
  • Inline edit forms display and save correctly
  • Admin suggestions workflow uses full forms for all media types
  • Scroll-to-top works when editing from list views
  • Default cover image displays when no cover is provided
  • Static assets serve with correct MIME types
  • Rate limiting works correctly for different user types
  • Discord role assignment works on login
  • All builds pass without errors
  • No TypeScript errors

Related Issues

Closes #65 - Base64 image upload issue

โœจ This pull request was created with help from Hikari~ ๐ŸŒธ

## Summary This PR includes multiple feature additions and fixes to improve the library application: ### ๐ŸŽจ Base64 Image Upload Support - Fixed Fastify body limit (1MB โ†’ 10MB) to accommodate base64-encoded images - Corrected base64 size calculation and validation logic - Improved error handling with proper 400 status codes and helpful messages - Removed duplicate validation that was blocking uploads - Users can now upload cover images up to 5MB (decoded size) ### ๐Ÿ“ Reusable Form Components - Created 6 form components: `GameForm`, `BookForm`, `MusicForm`, `ShowForm`, `MangaForm`, `ArtForm` - All forms support both 'add' and 'edit' modes with pre-population - Integrated inline editing into all detail views (edit/delete buttons) - Enhanced admin suggestions workflow with full forms instead of basic modals - Added scroll-to-top when clicking edit in list views for better UX ### ๐Ÿ–ผ๏ธ Default Cover Image - Added beautiful library reading image as default cover for all media types - Fixed static asset serving to use correct MIME types - Updated all 12 components (6 list views + 6 detail views) to always show images ### ๐Ÿ”’ Tiered Rate Limiting - Unauthenticated users: 100 requests/minute - Authenticated users: 500 requests/minute (5x more lenient) - Admin users: No rate limits (complete bypass via allowList) ### ๐ŸŽฎ Discord Integration - Auto-assign library member role to users in NHCarrigan Discord server - Checks server membership on every login - Only assigns role if user is in server and doesn't have it yet - Graceful error handling without blocking login - Similar pattern to badge refresh flow ### ๐Ÿ“š Documentation - Added comprehensive CLAUDE.md with: - Project structure and tech stack - Development workflow and commands - Database schema documentation - Authentication flow details - Security features - Code style conventions - Common gotchas and solutions ## Test Plan - [x] Base64 image uploads work for cover images up to 5MB - [x] Helpful error messages appear for validation failures - [x] Edit/delete buttons appear on all detail views for admin users - [x] Inline edit forms display and save correctly - [x] Admin suggestions workflow uses full forms for all media types - [x] Scroll-to-top works when editing from list views - [x] Default cover image displays when no cover is provided - [x] Static assets serve with correct MIME types - [x] Rate limiting works correctly for different user types - [x] Discord role assignment works on login - [x] All builds pass without errors - [x] No TypeScript errors ## Related Issues Closes #65 - Base64 image upload issue โœจ This pull request was created with help from Hikari~ ๐ŸŒธ
hikari added 7 commits 2026-02-20 20:18:27 -08:00
This resolves issue #65 by addressing multiple problems that were preventing base64-encoded cover images from being uploaded:

1. Increased Fastify body limit from 1MB to 10MB to accommodate base64-encoded images
2. Removed duplicate coverImage string length validation that was blocking base64 data URLs
3. Fixed base64 size calculation to properly extract and measure just the base64 data portion
4. Updated validateDataUrl regex to allow whitespace in base64 strings
5. Added proper error handling with 400 status codes and helpful error messages instead of 500 errors

Users can now successfully upload cover images as base64 data URLs up to 5MB (decoded size) and will receive clear validation error messages if uploads fail.

Closes #65
Add detailed project documentation for AI assistants covering:
- Git commit guidelines and user permissions
- Project structure and technology stack
- Database schema with all models
- Authentication flow with Discord OAuth
- Image upload handling (base64 and regular URLs)
- Development workflow and scripts
- CI/CD pipeline configuration
- Configuration standards (TypeScript, ESLint, Jest)
- Secrets management with 1Password CLI
- Security features and API route structure
- Code style conventions and common gotchas
- Deployment instructions

This documentation will help AI assistants understand the project architecture, follow established patterns, and work effectively within the codebase.
Update rate limiting to be more lenient for authenticated users and bypass limits entirely for admin users:

- Unauthenticated users: 100 requests/minute (original limit)
- Authenticated users: 500 requests/minute (5x increase)
- Admin users: No rate limits (completely bypassed via allowList)

This allows the admin to interact with the library without restrictions whilst still protecting against abuse from unauthenticated users. Authenticated users get a much more generous limit for better user experience.

Uses @fastify/rate-limit's allowList and dynamic max options to implement the tiered system.
Created reusable form components for all media types (Game, Book, Music, Show,
Manga, Art) to provide a consistent editing experience across the application.

Changes:
- Created 6 new form components in shared folder for all media types
- Each form component supports both 'add' and 'edit' modes
- Forms include all fields: title, author/artist/platform, status, dates,
  rating, time spent, notes, cover images, tags, and links
- Added inline editing to all detail views using form components
- Detail views now show edit form inline instead of navigating away
- Integrated form components into admin suggestions workflow
- Admins can now review and edit all suggestion details before accepting
- Added scroll-to-top functionality when clicking edit in all list views
- Ensures edit form is visible when opened from paginated lists

Benefits:
- Consistent UX across all media types
- Better editing experience with inline forms
- Improved admin suggestion workflow with full editing capabilities
- No route navigation for edits (better for SEO and UX)
- All forms follow the same styling and interaction patterns

Co-Authored-By: Naomi Carrigan <commits@nhcarrigan.com>
Added a beautiful default cover image featuring Naomi reading in her cozy
library, which will be displayed whenever a media item doesn't have a cover
image provided.

Changes:
- Added default-cover.jpg to frontend public/assets directory
- Updated all list components (games, books, music, shows, manga, art) to
  always display an image using the default as fallback
- Updated all detail components to always show cover section with default
  fallback
- Removed conditional rendering of cover images - now always visible
- Properly handles different property names (coverImage, coverArt, imageUrl)

Benefits:
- Consistent visual appearance across all media types
- No more empty spaces where cover images would be
- Better UX with uniform card layouts
- Beautiful placeholder that matches the library theme

Co-Authored-By: Naomi Carrigan <commits@nhcarrigan.com>
Fixed the not-found handler to exclude /assets routes, allowing static assets
like images to be served with correct MIME types instead of being caught by
the SPA fallback handler.

Changes:
- Updated setNotFoundHandler to check for /assets prefix
- Assets are now served directly by fastify-static with correct content-type
- Only non-API, non-asset routes fall through to index.html

This fixes the default cover image not displaying because it was being served
as text/html instead of image/jpeg.

Co-Authored-By: Naomi Carrigan <commits@nhcarrigan.com>
feat: auto-assign Discord role to library members
Node.js CI / CI (pull_request) Failing after 35s
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m9s
536cf6e7f9
Implemented automatic Discord role assignment for users who are
members of the NHCarrigan server. This happens on every login:

- Check if user is in Discord server (ID: 1354624415861833870)
- Fetch user's current roles via Discord API
- Assign library member role if they don't have it yet
- Graceful error handling without blocking login

Uses Discord Bot API with proper permissions to manage roles.
Similar pattern to badge refresh on login.

Environment variables added:
- DISCORD_BOT_TOKEN: Bot token for Discord API calls
- LIBRARY_ROLE_ID: Role ID to assign (1474616681023279236)
naomi added 1 commit 2026-02-20 20:26:38 -08:00
fix: rename form output bindings to avoid DOM event conflicts
Node.js CI / CI (pull_request) Successful in 1m22s
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m26s
309a20f694
Renamed @Output() properties in all form components from 'save' and
'cancel' to 'formSubmit' and 'formCancel' to resolve ESLint rule
@angular-eslint/no-output-native which prohibits output bindings
named after standard DOM events.

Updated all template bindings in detail components and admin
suggestions to use the new output names.

- Renamed save โ†’ formSubmit in all 6 form components
- Renamed cancel โ†’ formCancel in all 6 form components
- Updated bindings in 6 detail components
- Updated bindings in admin suggestions component
naomi merged commit 983b78b0e9 into main 2026-02-20 20:32:52 -08:00
naomi deleted branch fix/base64 2026-02-20 20:32:53 -08:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nhcarrigan/library#66