Skip to content

Dev#73

Merged
KyleTryon merged 46 commits intomainfrom
dev
Dec 5, 2025
Merged

Dev#73
KyleTryon merged 46 commits intomainfrom
dev

Conversation

@KyleTryon
Copy link
Contributor

This pull request updates documentation to reflect the new Tuvix subscription URL and introduces the browser extension for easier feed discovery. The changes ensure users and developers reference the correct service endpoint and highlight new integration options.

Documentation updates for subscription URL:

  • Changed all examples, bookmarklets, and integration snippets in docs/features/url-subscribe.md to use the new https://feed.tuvix.app/app/subscriptions URL instead of the old feedsmith.dev endpoint. [1] [2] [3] [4]

New browser extension announcement:

  • Added a section to README.md introducing the Tuvix Tricorder Extension for Chrome and Firefox, with a link to its repository for easy RSS feed discovery.

KyleTryon and others added 30 commits December 2, 2025 23:09
Update all references from feedsmith.dev to feed.tuvix.app in the
URL-based subscription documentation. This corrects the domain used
in example URLs, bookmarklets, and integration examples.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add mention of the Tuvix Tricorder Extension for Chrome and Firefox
in the Hosted section of the README. This helps users discover the
companion extension for easy RSS feed subscription.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
docs: add browser extension section to README
docs: fix incorrect subscription URLs in url-subscribe documentation
Add extractHeaders() utility function to normalize request header
extraction across authentication flows. Handles both Headers object
and plain object formats, reducing code duplication by ~100 lines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fix silent email failures by adding comprehensive breadcrumbs and
proper error checking throughout email sending flows.

- Add breadcrumbs at email service level (attempt, API call, result)
- Change Better Auth callbacks from .catch() to .then() to check
  emailResult.success (email service returns errors, doesn't throw)
- Add breadcrumbs for verification, welcome, and password reset emails
- Add Sentry capture for settings check failures
- Ensures all email failures are tracked for debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add complete tracking and security logging throughout authentication
endpoints to prevent silent failures and enable monitoring.

Login flow enhancements:
- Wrap in Sentry span for performance tracking
- Add breadcrumbs for login attempts and results
- Add security audit logging for successful and failed logins
- Add metrics for monitoring login success rates and duration
- Use extractHeaders() utility for consistency

Password operation security:
- Add security audit logging to password change endpoint
- Query verification token before reset to capture userId
- Add security audit logging to password reset completion
- Non-blocking audit logging to prevent operation failures

All audit logging wrapped in try/catch to ensure authentication
operations succeed even if logging fails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Wrap verification and welcome email operations in Sentry spans
to track success/failure even though emails are sent in a
fire-and-forget pattern.

- Add span tracking for verification email with status codes
- Add span tracking for welcome email with status codes
- Track email success/failure as span attributes
- Maintain existing breadcrumbs for debugging
- Preserve fire-and-forget behavior (no await on email send)

This provides visibility into email delivery without blocking
user registration/verification flows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive Sentry span tracking around batch database
operations to monitor performance and catch failures.

- Wrap mark articles read/unread batch in Sentry span
- Wrap mark all articles read batch in Sentry span
- Track batch size, operation type, and user ID as attributes
- Capture exceptions with full context (batch size, user, article count)
- Set appropriate span status codes for success/failure

Batch operations are critical for user experience - this ensures
we're alerted to failures and can identify performance patterns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add Sentry span tracking for OpenGraph image extraction with
metrics emission for pattern analysis.

- Wrap OG image fetch in Sentry span with domain tracking
- Track success (found/not found) and failures separately
- Emit metrics counters for error patterns (by domain and error type)
- Set appropriate span status for found/not found/error cases
- Avoid spamming Sentry with every failure (use metrics instead)

This allows us to identify problematic domains and error patterns
without creating excessive noise in Sentry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implement automatic retry for transient feed fetch failures and
add full transaction monitoring for OPML import operations.

Subscription Creation & Preview Enhancements:
- Add automatic retry logic for HTTP 502, 503, 504, 429 errors
- Implement exponential backoff (1s, 2s delays) with max 2 retries
- Track retry attempts in Sentry breadcrumbs and error context
- Enhanced error tagging with domain and HTTP status codes
- Track attempt count and last status code for debugging

OPML Import Transaction Monitoring:
- Wrap entire import in Sentry transaction span
- Create individual spans for each feed import
- Track feed-level attributes (URL, title, domain, filters, categories)
- Calculate and report success rate as span attribute
- Proper error boundaries with per-feed exception capture
- Handle limit reached and already subscribed cases gracefully
- Fix loop control flow to work within Sentry span callbacks

Benefits:
- Improved resilience against transient failures (network, server)
- Clear visibility into which feeds fail and why during bulk imports
- Domain-based error pattern analysis for subscription issues
- Success rate tracking for OPML import operations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fix critical bugs identified in code review:

1. Security Audit Logging (HIGH):
   - Fix incorrect action type for failed password resets
   - Changed "password_reset_success" to "password_reset_failed" in error handler
   - Added missing "password_reset_failed" to SecurityAction type

2. Retry Logic Separation (HIGH):
   - Separate fetch errors from parse errors in retry logic
   - Parse errors now throw immediately without retry
   - Only HTTP fetch errors (502, 503, 504, 429) are retried
   - Improves error classification: "fetch_error" vs "parse_error"
   - Applied to both create and preview endpoints

3. Header Extraction (MEDIUM):
   - Fix String(undefined) converting undefined to "undefined" string
   - Preserve undefined values correctly in header extraction
   - Prevents confusion where missing headers appear as "undefined"

4. Code Cleanup (LOW):
   - Remove unused lastError assignments in retry loops
   - Assignments were made but value never used before continue

All changes verified with 819 passing tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add explicit paths for packages/api/wrangler.toml files since
root-level patterns don't match subdirectories

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Admin dashboard was missing emailVerified field, causing unverified
users to appear as "active" when they weren't. This adds:
- emailVerified field to AdminUserSchema
- emailVerified filter option for queries
- Metrics tracking for when filter is used

Fixes user status discrepancy where unverified users showed as active

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Security audit logging was completely non-functional due to missing
SQL default on created_at column. This caused silent failures:

Root cause:
- security_audit_log.created_at was NOT NULL without SQL DEFAULT
- Drizzle's $defaultFn() only works at app level, not in database
- logSecurityEvent() didn't provide createdAt value
- All insert attempts failed silently (caught and logged to console)
- Result: Zero audit logs ever written to production

Fix (3-part):
1. Quick fix: logSecurityEvent() now explicitly provides createdAt
2. Schema fix: Changed to SQL DEFAULT using unixepoch()
3. Migration: 0006_fix_security_audit_log_default.sql adds DEFAULT to DB

Impact:
- Enables tracking of login attempts, password resets, registrations
- Critical for security monitoring and compliance
- Consistent with other tables using same timestamp pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
While .claude/ directory is gitignored, settings.json should be
committed to share team-wide Claude Code configurations like
security policies and approved tool permissions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add shared Claude Code configuration with:
- Security deny rules for .env, secrets, production operations
- Broader allow patterns for common workflows
- Git co-authoring enabled
- MCP server integrations (Sentry, Better Auth, Shadcn)

Establishes team-wide safety guardrails and tool permissions
for AI-assisted development

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Improvements from code review:
- Extract getRequestMetadata() helper to reduce header extraction duplication
- Consolidate security module imports in auth router
- Extract retry constants (MAX_RETRIES, RETRY_DELAY_MS, TRANSIENT_STATUS_CODES) to module top
- Add clarifying comment for createdAt defense-in-depth pattern

No functional changes, just improved maintainability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Import logSecurityEvent and getRequestMetadata in login handler
- Add emailVerified field to admin listUsers and getUser responses
- Fixes type errors from refactoring

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Dynamic imports lose type information, causing ESLint to treat
destructured values as 'error' types. Added explicit type annotations
to resolve "unsafe assignment" and "unsafe call" linting errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Type assertions (as) are more effective than type annotations (:) for
dynamic imports, as they assert the return type of the function call
rather than just the destructured variables.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove dynamic imports of security module to fix type inference
- Add explicit type annotations to destructured variables
- Use top-level import instead of await import() pattern

This resolves ESLint errors where dynamic imports lose type information,
causing getRequestMetadata to be treated as 'error' type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add top-level import for Sentry module
- Add nullish coalescing for optional olderThanDays attribute

Resolves ESLint errors from missing Sentry import and TypeScript
errors from passing undefined to Sentry span attributes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add nullish coalescing for extractDomain() calls
- Prevents TypeScript errors when domain extraction returns null

Sentry span attributes require string | number | boolean types,
not null or undefined.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ements

- Add --> statement-breakpoint markers for Drizzle compatibility
- Prevents "more than one statement" error in test migrations
- Maintains same logic, just properly formatted for migration runner

This fixes test failures caused by better-sqlite3 rejecting
multi-statement SQL strings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Security audit logging:
- Remove redundant createdAt field setting in application code
- Rely solely on SQL DEFAULT from database schema

Subscription error handling:
- Add TRPCError rethrow guards in catch blocks
- Prevents parse errors from being incorrectly retried as fetch errors
- Ensures parse errors exit immediately without retry logic

All three issues identified by Copilot AI have been resolved.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Merge executeBatch import with existing @/db/utils imports
- Group @/db/* imports together for better organization
- Remove duplicate import statement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
KyleTryon and others added 16 commits December 4, 2025 11:22
Fixes #75

## Problem
Docker Compose builds were failing with "ERR_PNPM_OUTDATED_LOCKFILE"
because the build context was set to individual package directories
(./packages/api, ./packages/app), but pnpm workspaces require the
monorepo root context to access the shared pnpm-lock.yaml.

The individual package lockfiles were outdated and shouldn't exist
in a pnpm workspace setup.

## Solution
1. Changed Docker build context from individual packages to monorepo root (.)
2. Updated Dockerfiles to copy workspace files (pnpm-workspace.yaml, root pnpm-lock.yaml)
3. Updated Dockerfiles to copy all needed package.json files
4. Removed outdated individual package lockfiles
5. Added packages/*/pnpm-lock.yaml to .gitignore
6. Updated deployment documentation

## Changes
- docker-compose.yml: Changed context from ./packages/* to . (monorepo root)
- packages/api/Dockerfile: Copy workspace files and all needed packages
- packages/app/Dockerfile: Copy workspace files and all needed packages
- Removed packages/api/pnpm-lock.yaml (outdated)
- Removed packages/app/pnpm-lock.yaml (outdated)
- .gitignore: Prevent individual package lockfiles
- docs/deployment.md: Updated to reflect new build context

## Testing
✅ Tested with `docker compose build --no-cache`
✅ Both API and app containers build successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes #75

## Root Causes Identified

1. **Lockfile mismatch**: Docker build context was set to individual
   packages but pnpm workspaces require monorepo root context

2. **ESM import issues**: TypeScript compilation without bundling
   resulted in missing `.js` extensions in imports (Node ESM requirement)

3. **Double-migration bug**: When tsup bundled migrate-local.ts into
   node.ts, the CLI check (import.meta.url) executed twice, causing
   migrations to run twice and server to hang

## Solutions Implemented

### 1. Monorepo Context (from previous commit 23e386b)
- Changed docker-compose.yml context from `./packages/*` to `.` (root)
- Updated Dockerfiles to copy workspace files
- Removed outdated individual package lockfiles
- Added packages/*/pnpm-lock.yaml to .gitignore

### 2. Add tsup Bundler
- Added tsup as dev dependency for proper ESM bundling
- Created tsup.config.ts to bundle node.ts and migrate-local.ts
- tsup handles ESM imports correctly (no .js extension issues)
- Optimized bundle: 525KB for node.ts entry point
- Updated package.json build script to use tsup

### 3. Fix Double-Migration Bug
- Added check in migrate-local.ts to prevent CLI code from running
  when bundled into dist/entries/node.js
- CLI check now excludes execution when argv[1] contains "dist/entries"
- Migrations now run exactly once during server startup

### 4. Update Dockerfile CMD
- Changed from running separate migration + server to just server
- Migrations now run automatically inside node.ts (as designed)
- Removed redundant migration command from CMD

## Testing
✅ Local build: `pnpm --filter @tuvixrss/api build` succeeds
✅ Local run: Server starts, migrations run once, cron initializes
✅ Docker build: `docker compose build` succeeds
✅ Docker run: Containers healthy, API responds on :3001
✅ Health check: `curl http://localhost:3001/health` returns OK

## Changes
- packages/api/Dockerfile: Use tsup-bundled code, simplified CMD
- packages/api/package.json: Add tsup dependency, update build script
- packages/api/tsup.config.ts: Configure bundling for node.ts + migrate-local.ts
- packages/api/src/db/migrate-local.ts: Fix double-execution bug
- pnpm-lock.yaml: Add tsup dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Security improvements:
- Run containers as non-root users (uid 1001)
- API runs as 'nodejs' user
- App runs as 'nginx-app' user

Build optimization:
- Add .dockerignore files (root and API package)
- Reduce build context by excluding unnecessary files
- Build tricorder before API in multi-stage build

Health checks:
- Add explicit health check to app Dockerfile
- Consistent health check configuration across services

Image sizes:
- API: 553MB (increased from 357MB due to security layer overhead)
- App: 60.9MB (optimized from 57.1MB with health checks)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Critical Fix:
- Create non-root user BEFORE copying files (was causing 196MB layer)
- Use --chown flag during COPY operations instead of chown after
- This prevents Docker copy-on-write from duplicating the entire /app directory

Results:
- API image: 357MB (down from 553MB with previous optimization)
- User creation layer: 3.22kB (down from 196MB)
- All functionality verified working

Technical Details:
- The issue was that running `chown -R nodejs:nodejs /app` after copying
  files created a new 196MB layer because Docker's copy-on-write system
  duplicates all files when permissions change
- By creating the user first and using COPY --chown, we set permissions
  during the copy operation, avoiding the duplication

Security maintained:
- Still runs as non-root user (nodejs:1001)
- Health checks working
- Containers start successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive CI/CD testing for Docker Compose deployment:

GitHub Actions Workflow (.github/workflows/docker-test.yml):
- Build validation for both API and App images
- Image size enforcement (API < 400MB, App < 100MB)
- Health check verification with 60s timeout
- Endpoint testing (API and App health checks)
- Security validation (non-root user verification)
- Database migration verification
- Smoke tests for basic functionality
- Detailed logging and cleanup on failure

Test Configuration (docker-compose.test.yml):
- Faster health check intervals for CI (5s vs 30s)
- Test-specific environment variables
- Extended retries for reliability

Local Testing Script (scripts/test-docker.sh):
- Run the same CI tests locally before pushing
- Colorized output for easy debugging
- Automatic cleanup on exit/interrupt
- Shows container stats and leaves services running

Package Scripts:
- `pnpm docker:test` - Run local Docker tests
- `pnpm docker:test:ci` - Run with CI configuration

Triggers:
- Pull requests affecting Docker-related files
- Pushes to main or dev branches

Expected CI runtime: 3-5 minutes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add script to check for outdated GitHub Actions locally without
waiting for Dependabot's monthly schedule.

Usage: ./scripts/check-gha-versions.sh

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Update GitHub Actions dependencies:
- actions/checkout@v4 → @v6
- actions/github-script@v7 → @v8
- actions/setup-node@v5 → @v6
- actions/upload-artifact@v4 → @v5

Major version pinning allows automatic security patches while
preventing breaking changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The API container needs time to:
- Run database migrations
- Initialize Sentry
- Start cron jobs
- Boot the Hono server

Increased from 5s to 30s to prevent false health check failures
in CI environments.

Also fixed test-docker.sh to work on macOS (no timeout command).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The docker-compose.yml health check configuration overrides the
Dockerfile HEALTHCHECK. Updated both to use consistent timing:
- API: 30s start period (needs time for migrations + Sentry + cron)
- App: 10s start period (nginx starts faster)

This fixes the CI failure where docker compose up -d was exiting
because the API was marked unhealthy before fully starting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- Start API and App containers separately (not docker compose up -d)
- Show container status and logs immediately after starting
- Poll health status every 2s with timestamp logging
- Show API logs every 10s while waiting
- Increased API wait time to 90s (was 60s implicit)
- Show full logs on failure for better debugging

This allows us to see exactly what's happening during startup
in CI and diagnose why health checks are failing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The real issue was a permissions problem with the SQLite database:
- Container runs as uid 1001 (nodejs user)
- Volume mount ./data:/app/data didn't exist in CI
- When Docker creates the mount point, it's owned by root
- nodejs user can't write to /app/data/tuvix.db

Solution: Create ./data directory with 777 permissions before
starting containers, allowing uid 1001 to write the database file.

This fixes the "SqliteError: unable to open database file" crash
that was causing the health check failures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Changed health check interval from 30s to 5s for both containers.
This allows health status to update quickly instead of waiting
30s between each check.

With the old config:
- start_period: 10s
- interval: 30s
- retries: 3
- = could take 100+ seconds to become healthy

With new config:
- start_period: 10-30s
- interval: 5s
- retries: 3
- = becomes healthy in 10-40 seconds

Also increased App wait timeout to 120s to be safe.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change nginx to listen on port 8080 instead of 80 (non-root compatible)
- Update port mapping from 5173:80 to 5173:8080
- Fix health checks to use explicit IPv4 (127.0.0.1) instead of localhost
- Move non-root user creation before nginx config for clarity
- Add manual health check test in CI workflow

This fixes the app container health check failures while maintaining
security by running as non-root user (uid 1001).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…pose

- Change hardcoded DATABASE_PATH to use environment variable with fallback
- Allows CI to use /app/data/test.db while local dev uses /app/data/tuvix.db
- Fixes CI database verification step that was looking for test.db

This resolves the "Database file not found" error in CI workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@KyleTryon KyleTryon requested a review from Copilot December 5, 2025 00:28
@KyleTryon KyleTryon merged commit bb0be35 into main Dec 5, 2025
18 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces comprehensive Docker build and testing infrastructure along with enhanced observability, retry logic, and security improvements. The changes focus on production-readiness by adding Docker health checks, non-root user support, automated testing workflows, and improved error tracking through Sentry.

Key Changes:

  • Docker infrastructure with automated testing, health checks, and non-root security
  • Database retry logic for transient HTTP failures in subscription endpoints
  • Enhanced Sentry observability with breadcrumbs, spans, and metrics across auth, email, and RSS operations
  • Build system improvements using tsup for better ESM bundling

Reviewed changes

Copilot reviewed 33 out of 37 changed files in this pull request and generated no comments.

Show a summary per file
File Description
scripts/test-docker.sh Comprehensive Docker testing script with health checks and validation
scripts/check-gha-versions.sh GitHub Actions version checking utility
packages/api/Dockerfile Multi-stage build with tsup bundling, non-root user, and proper workspace structure
packages/app/Dockerfile Nginx-based app container with non-root user and port 8080
docker-compose.yml Updated build contexts to monorepo root with adjusted health check intervals
docker-compose.test.yml CI-specific Docker Compose configuration
packages/api/tsup.config.ts New bundler config for ESM output with workspace package resolution
packages/api/src/routers/subscriptions.ts Retry logic for transient HTTP errors with exponential backoff and Sentry spans
packages/api/src/routers/auth.ts Enhanced audit logging and Sentry observability for auth flows
packages/api/src/services/email.ts Breadcrumb tracking for email operations
packages/api/src/auth/better-auth.ts Fire-and-forget email tracking with Sentry spans
packages/api/src/db/schema.ts SQL DEFAULT for timestamp instead of runtime function
.github/workflows/docker-test.yml Automated Docker build and integration testing workflow
docs/features/url-subscribe.md URL updated from feedsmith.dev to feed.tuvix.app
README.md Browser extension announcement added
CLAUDE.md New AI assistant guidelines document
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants