BCF

There are no high-quality resources for perfumers to avail of on the Internet. Disparate opinions, niche treasures, badly-built websites. I needed an app that would let perfumers find perfume ingredients, bring system to their huge collections of compounds, and write formulas anywhere on this earth.

See for yourself View the code
Description of image 1

Main Page

1 / 4

BCF – The Perfumers' Digital Lab

Overview

BCF (Browse, Collect, Formulate) is an open-source, self-hosted platform that serves as a comprehensive digital laboratory for perfumers. It combines a robust Rust backend with a responsive Svelte frontend to deliver a Wikipedia-style collaborative environment for perfume formulation and knowledge sharing.

Architecture

Backend (Rust)

  • Framework: Axum for high-performance, async web services
  • Database Access: SQLx for type-safe SQL queries without an ORM
  • API Design: RESTful endpoints with JSON payloads
  • Performance Optimization: Redis caching layer for frequently accessed data
  • Authentication: JWT-based auth flow with separate access and refresh tokens

Frontend (Svelte)

  • Server-Side Features: Leverages Svelte's native SSR capabilities
  • State Management: Built-in Svelte stores
  • Form Handling: Custom Svelte form actions with client-side validation

Database Schema

  • Primary Store: PostgreSQL with optimized indexes for ingredient searches
  • Caching Layer: Redis for frequent queries and unsplash data caching
  • Data Models:
    • Ingredients (3100+ entries)
    • User Profiles
    • Formulations
    • Contributions
    • Collection Ingredients

Infrastructure

  • Containerization: Multi-stage Docker builds for optimal image sizes
  • Container Registry: GitHub Packages for version control
  • Deployment: VPS with Docker Compose orchestration
  • SSL/TLS: Automated certificate management
  • Backup Strategy: Automated PostgreSQL dumps with retention policies

Core Functionalities

1. Database Operations

-- Example of raw SQL usage with SQLx
WITH descriptor_info AS (
SELECT
i.*,
array_remove(array_agg (DISTINCT d.name), NULL) as descriptors,
array_remove(array_agg (DISTINCT d.colour), NULL) as colours
FROM ingredients i
LEFT JOIN ingredient_descriptors id ON i.id = id.ingredient_id
LEFT JOIN descriptors d ON id.descriptor_id = d.id
WHERE i.slug = $1
GROUP BY i.id
)
SELECT * FROM descriptor_info

2. Security Implementation

  • Authentication Flow:
    • JWT token generation and validation
    • Refresh token rotation
    • Server-side session validation
  • Access Control:
    • Role-based authorization
    • Resource-level permissions
    • Rate limiting with Redis

3. API Integration

  • External Services:
    • Unsplash API for dynamic imagery
    • IFRA database synchronization
    • Captcha verification
  • Error Handling:
    • Structured error responses
    • Automatic retry mechanisms
    • Rate limit compliance

4. Performance Optimizations

  • Caching Strategy:
    • Redis for session data
    • Application-level caching for static content
    • Database query optimization
  • Load Management:
    • Connection pooling
    • Query batching
    • Async operations

Development Workflow

Local Development

# Development environment setup
docker-compose -f docker-compose.dev.yml up

# Database migrations (should be run inside of the axum container)
sqlx migrate run

# Frontend development
npm run dev

Deployment Pipeline

  1. GitHub Actions workflow triggers on push to main
  2. Runs tests and builds Docker images
  3. Pushes to GitHub Packages
  4. Deploys to VPS via webhook
  5. Performs health checks and rollback if necessary

Technical Roadmap

Short-term Goals

  • Enhance search with full-text capabilities

Long-term Vision

  • Distributed caching with Redis Cluster
  • API marketplace for third-party integrations
Let's get something done