Skip to main content
The Portfolio system allows you to organize and showcase completed tattoo work for each artist and user in your studio.

Understanding Portfolio Structure

Portfolio items are linked to:
  • Users (primary) - Each user has their own portfolio
  • Artists (fallback) - For backward compatibility with older items
  • Sessions (optional) - Link work to specific appointments
  • Clients (optional) - Associate work with client records
The system automatically uses the user_id when available, falling back to artist_id for legacy items.

Selecting a User Portfolio

1
Step 1: View User List
2
The left sidebar shows all users with:
3
  • Avatar - User profile picture or initials
  • Name - Username or artist name
  • Role chip - Tatuador, Admin, Asistente, etc.
  • Status chip - Activo (green) or Inactivo (gray)
  • Count badge - Number of portfolio items
  • Color bar - Top accent in artist color (for tattoo artists)
  • 4
    Step 2: Select a User
    5
    Click any user card to load their portfolio. The selected user is highlighted with a thicker border.

    Adding Portfolio Images

    1
    Step 1: Select Target User
    2
    Click the user whose portfolio you want to add to (see above).
    3
    Step 2: Open Upload Dialog
    4
    Click the + button in the toolbar.
    5
    Step 3: Select Images
    6
    In the file picker:
    7
  • Select one or multiple images
  • Supported formats: PNG, JPG, JPEG, WebP, BMP
  • Multiple selection is enabled for batch uploads
  • 9
    For artists, a session selection dialog appears:
    10
  • — No vincular — - Don’t link to a session
  • Session list - Recent sessions showing:
    • Session ID
    • Date
    • Client name
  • 11
    Select a session to automatically populate:
    12
  • Artist ID
  • Client ID
  • 13
    from the session data.
    14
    Linking portfolio items to sessions helps track which work belongs to which client and appointment.
    15
    Step 5: Confirm Upload
    16
    Click Continuar. The system:
    17
  • Creates the user’s portfolio directory if needed
  • Copies images to uploads/portfolios/{user_id}/
  • Handles duplicate filenames automatically (appends _1, _2, etc.)
  • Creates portfolio item records
  • Refreshes the gallery
  • Updates the user’s item count
  • Viewing Portfolio Items

    Portfolio items are displayed as cards in a flowing grid:
    • Thumbnail - Image scaled to 260px height
    • Date - Creation date in YYYY-MM-DD format
    • Hover effect - Border brightens on hover
    • Drop shadow - Subtle depth effect

    Item Details

    Click any portfolio card to open the detail dialog showing:
    • Full-size image - Up to 640px wide
    • Fecha - Creation date
    • Artista - Artist name
    • Sesión - Session ID, status, and price (if linked)
    • Cliente - Client name (if linked)
    • Transacción - Transaction details (if paid)
    • Notas - Caption or notes field
    The detail dialog is draggable. Click and hold the background to reposition it.

    Filtering Portfolio Items

    The toolbar provides several filter options:

    Style Filter

    • Estilo: Todos - All styles
    • Filters by the style field if populated

    Body Area Filter

    • Zona: Todas - All body areas
    • Filters by the body_area field if populated

    Color Mode Filter

    • Color: Todos - All items
    • Color - Color tattoos only
    • B&N - Black and gray only

    State Filter

    • Estado: Todos - All items
    • Fresh - Fresh tattoo photos
    • Healed - Healed tattoo photos

    Sorting

    • Más recientes - Newest first (default)
    • Más antiguos - Oldest first
    Filters work in combination. Use “Limpiar” to reset all filters to default values.

    Portfolio Storage

    Directory Structure

    data_directory/
    └── uploads/
        └── portfolios/
            ├── {user_id_1}/
            │   ├── image1.jpg
            │   ├── image2.png
            │   └── ...
            ├── {user_id_2}/
            └── ...
    

    Legacy Compatibility

    Older installations stored avatars in assets/. The system automatically:
    1. Checks the new data directory first
    2. Falls back to legacy location if needed
    3. Migrates files when accessed
    All portfolio data is stored locally, giving you full control and no cloud dependencies.

    Portfolio Metadata

    Each portfolio item can store:
    • path - Full file path (required)
    • user_id - Owner user ID (preferred)
    • artist_id - Artist ID (fallback)
    • session_id - Linked session
    • client_id - Associated client
    • transaction_id - Payment record
    • style - Tattoo style
    • body_area - Body placement
    • color_mode - “color” or “bn”
    • fresh_or_healed - “fresh” or “healed”
    • caption - Notes or description
    • created_at - Upload timestamp
    Currently, style, body_area, color_mode, and fresh_or_healed are not editable from the UI. These fields are reserved for future filtering features.

    User Colors

    Artists have color-coded portfolios:
    • Color bar - Top accent on user cards
    • Role chip - Border matches artist color
    • Avatar dot - Indicator dot in artist color
    Colors are assigned from:
    1. artist_colors.json by artist_id (key as string)
    2. Fallback color palette based on ID modulo 10

    Permissions

    Portfolio access:
    • All users can view portfolios
    • Users can upload to their own portfolio
    • Admins can upload to any portfolio

    Best Practices

    High Quality Images

    Upload high-resolution photos for the best portfolio presentation.

    Link to Sessions

    Always link portfolio items to sessions when possible for better organization.

    Regular Updates

    Add fresh work regularly to keep portfolios current and impressive.

    Proper Attribution

    Ensure each piece is uploaded to the correct artist’s portfolio.

    Troubleshooting

    Check that the uploads/portfolios directory is writable and has sufficient disk space.
    Verify the file still exists at the stored path. The system uses absolute paths.
    The count badge refreshes after successful uploads. Try reloading the page if it seems stuck.

    Build docs developers (and LLMs) love