Skip to content

Latest commit

 

History

History
253 lines (189 loc) · 7.67 KB

File metadata and controls

253 lines (189 loc) · 7.67 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

ZipURL is a URL shortening service with UTM parameter tracking, Open Graph metadata support, and OIDC authentication. Built with Rust using the Leptos full-stack framework (version 0.8) with server-side rendering (SSR) and client-side hydration.

Development Environment

This project uses Nix flakes for reproducible development environments. All development should be done within the Nix shell:

nix develop  # Enter the dev environment (automatic with direnv)

The Nix shell provides:

  • Rust nightly toolchain with wasm32-unknown-unknown target
  • cargo-leptos (must be installed separately: cargo install cargo-leptos)
  • just (task runner)
  • Tailwind CSS v4

Essential Commands

Development:

just dev                    # Start dev server with hot reload (port 1337)
cargo leptos watch          # Same as above (direct command)
just dev-server             # Backend only (no SSR)

Building:

just build                  # Development build
just build-release          # Production build with optimizations
cargo leptos build          # Full Leptos build (frontend + backend)

Testing:

just test                   # Run all tests
just test-one <TEST>        # Run specific test
just test-unit              # Unit tests only
just test-integration       # Integration tests only

Code Quality:

just fmt                    # Format code (includes leptosfmt)
just lint                   # Run clippy
cargo clippy -- -W clippy::all                    # Clippy for server
cargo clippy --target wasm32-unknown-unknown -- -W clippy::all  # Clippy for WASM

Frontend Checks:

just check-frontend         # Verify WASM compilation
just check-all              # Check both frontend and backend

Architecture

Crate Structure

The workspace is organized into 4 crates with clear separation of concerns:

  1. zipurl-core - Shared data models and DTOs

    • Domain models: ZipUrl, DomainConfig, ApiKey, Tag
    • Metadata types: CardMetadata, UtmParams, OgType, TwitterCard
    • No dependencies on server or client code
    • Used by all other crates
  2. zipurl-server - Backend logic and API

    • Database layer: db.rs uses redb (embedded database)
    • API routes: api/ directory (domains, urls, tags, redirect, metadata)
    • Authentication: auth/ directory (OIDC/Keycloak integration)
    • Metadata fetching: metadata.rs (scrapes Open Graph tags)
    • Bot detection: bot_detection.rs
    • Metrics: Prometheus metrics via metrics.rs
  3. zipurl-client - Browser-side utilities

    • WASM-specific code for browser interactions
    • Uses gloo-* crates for web APIs
  4. zipurl-app - Leptos UI application

    • Main entry point: main.rs (SSR setup with Axum)
    • App root: app.rs (Leptos component tree)
    • Pages: pages/ directory
    • Reusable components: components/ directory
    • Modals: modals/ directory
    • Feature flags: ssr for server, hydrate for client

Leptos SSR Architecture

ZipURL uses Leptos with full-stack SSR:

  • Server side (ssr feature): Renders initial HTML, handles API routes via Axum
  • Client side (hydrate feature): Takes over after initial load, compiles to WASM
  • Shared code: Components in zipurl-app compile for both targets

The main.rs sets up:

  1. Axum router with Leptos routes
  2. Database connection (redb)
  3. Optional OIDC auth provider
  4. API routes merged with SSR routes
  5. Static file serving from target/site

Database

  • Type: redb (embedded key-value database)
  • Location: zipurl.db (configurable via config.toml)
  • Schema: See zipurl-server/src/db.rs for table definitions
  • Key tables:
    • urls - Short URL records
    • domains - Domain configurations
    • api_keys - API key hashes
    • tags - Tag definitions
    • url_tags - Many-to-many URL-tag relationships

Configuration

Configuration is loaded via figment (supports TOML files + env vars):

  • config.toml - Main config file (not in git)
  • config.toml.example - Template to copy
  • Environment variables override file settings
  • See zipurl-server/src/config.rs for structure

Key settings:

  • database_path - Database file location
  • host, port - Server binding
  • base_url - Public URL for short links
  • auth.mode - "none", "mock", "oidc", or "keycloak"

Common Development Tasks

Working with Frontend (WASM)

The frontend compiles to WASM and has different clippy requirements:

# Check frontend compilation
cargo check --package zipurl-app --target wasm32-unknown-unknown --no-default-features --features hydrate

# Run clippy for frontend
cargo clippy --package zipurl-app --target wasm32-unknown-unknown --no-default-features --features hydrate

Working with Backend

Backend code uses the ssr feature:

# Check backend compilation
cargo check --package zipurl-server

# Run backend only (useful for API development)
cargo run --package zipurl-server

Adding Dependencies

Use cargo add (provided by nix shell):

cargo add <crate>                    # Add to workspace
cargo add -p zipurl-server <crate>   # Add to specific crate

For workspace-shared deps, add to [workspace.dependencies] in root Cargo.toml.

Database Operations

just db-backup              # Backup database
just db-reset               # Delete and recreate database

Working with Keycloak (for auth testing)

just keycloak-up            # Start Keycloak in Docker
just keycloak-down          # Stop Keycloak
just keycloak-logs          # View logs
just keycloak-reset         # Reset Keycloak data

Tailwind CSS

Tailwind v4 is integrated via cargo-leptos:

  • Input file: crates/zipurl-app/style/tailwind.css
  • Automatically compiled during cargo leptos watch
  • Output: Included in build artifacts

Code Patterns

Feature Flags

Always use feature flags for platform-specific code:

#[cfg(feature = "ssr")]
// Server-only code

#[cfg(feature = "hydrate")]
// Client-only code

Error Handling

  • Server errors: Use zipurl_server::error::ServerError (thiserror-based)
  • Core errors: Define in zipurl-core if shared
  • Leptos server functions: Return Result<T, ServerFnError>

Leptos Components

  • Use the #[component] macro
  • Props should derive Clone for reactivity
  • Server functions use #[server] macro
  • Keep component files focused and small

Testing

Unit Tests

  • Co-locate with code using #[cfg(test)]
  • Use rstest for parameterized tests
  • Mock external dependencies with mockall

Integration Tests

  • Located in tests/ directory
  • Use wiremock for HTTP mocking
  • Test full API flows

Project History

The project was recently rebranded from "ShortURL" to "ZipURL". Some references to the old name may still exist in documentation or comments.

Build Profiles

Two custom release profiles are defined:

  • wasm-release - Optimized for WASM size (opt-level='z', LTO enabled)
  • server-release - Optimized for server performance (opt-level=3, LTO enabled)

These are automatically used by cargo-leptos during release builds.

Port Usage

  • 1337 - Main application server
  • 1338 - Auto-reload WebSocket (dev mode)
  • 8080 - Keycloak (when running via docker-compose)

Important Notes

  • Never commit config.toml, *.db, or API keys
  • The project uses Rust edition 2024
  • WASM compilation requires the getrandom crate with js feature
  • All timestamps are i64 Unix timestamps (supports dates before 1970)
  • API keys are stored as SHA-256 hashes, never plaintext
  • URL metadata can be auto-fetched from target URLs using Open Graph tags