- Introduced `ShareModal` to replace the deprecated `SharePanel`, providing a more streamlined sharing experience. - Added `CopyButton` and `ShareActionButton` components for improved user interaction when sharing photos. - Updated `PhotoViewer` to utilize the new `ShareModal` for sharing functionality. - Removed `SharePanel` and updated localization files to include new sharing strings in multiple languages. - Enhanced the handling of share links and download options within the modal. Signed-off-by: Innei <tukon479@gmail.com>
11 KiB
AGENTS
Commands
Development Commands
# Start development server (runs both web and SSR)
pnpm dev
# Start only web development server
pnpm --filter web dev
# Start only SSR development server
pnpm --filter @afilmory/ssr dev
# Build production version
pnpm build
# Build manifest from storage (generates photo metadata)
pnpm run build:manifest
# Force rebuild all photos and metadata
pnpm run build:manifest -- --force
# Force regenerate thumbnails only
pnpm run build:manifest -- --force-thumbnails
# Force regenerate manifest only
pnpm run build:manifest -- --force-manifest
Database Commands (SSR app)
# Generate database migrations
pnpm --filter @afilmory/ssr db:generate
# Run database migrations
pnpm --filter @afilmory/ssr db:migrate
Code Quality Commands
# Lint and fix code
pnpm lint
# Format code
pnpm format
# Type check (web app)
pnpm --filter web type-check
Architecture
The project employs a sophisticated, modular architecture that separates concerns across different applications and packages, enabling independent development, deployment, and scaling.
Core Components
The project is divided into four main applications:
-
apps/web- Standalone Frontend SPA- Description: A pure client-side application built with React, Vite, and TypeScript. It can be deployed independently as a static website and is fully functional on its own.
- UI/Design: Features a modern, interactive, and user-centric UI. It utilizes a "Glassmorphic Depth Design System" for components like modals, toasts, and floating panels, creating a sense of visual hierarchy through layered transparency and subtle color accents. The design is geared towards a rich end-user experience for photo browsing and visualization.
- Server Integration: It can operate in two modes:
- Standalone: Functions without a server, using a pre-built
photos-manifest.jsonfile. - Server-Connected: When a global variable like
window.__MANIFEST__is detected, it unlocks enhanced features. This injection is handled by eitherapps/ssr(from a static file) orbe/apps/core(from the database).
- Standalone: Functions without a server, using a pre-built
-
apps/ssr- Next.js Wrapper for SEO & Prerendering- Description: A Next.js application that acts as a transparent proxy for the
apps/webSPA. Its primary role is to enhance the frontend with server-side capabilities for performance and discoverability, rather than serving as a full-fledged backend. It injects the manifest from a static JSON file. - Key Features:
- OG (Open Graph) Rendering: Dynamically generates social media preview cards for shared links.
- SEO Metadata Injection: Injects dynamic SEO tags into the HTML for better search engine visibility.
- SSR for Shared Pages: Server-renders specific pages to provide fast initial load times.
- Description: A Next.js application that acts as a transparent proxy for the
be/apps/core: The complete backend server (Hono) for real-time data. For a detailed breakdown of its architecture, seebe/apps/core/AGENTS.md.be/apps/dashboard: The administration panel for the backend, using a linear, data-first admin aesthetic (crisp frames, subtle gradients). Seebe/apps/dashboard/AGENTS.mdfor full UI guidelines.
Monorepo Structure
This is a pnpm workspace with multiple applications and packages:
apps/web/- Main frontend React application (Vite + React 19 SPA).apps/ssr/- Next.js 15 application serving as an SPA host and dynamic SEO/OG generator.be/apps/core/- The complete backend server (Hono) for real-time data.be/apps/dashboard/- The administration panel for the backend (linear, data-first admin look).packages/builder/- Photo processing and manifest generation tool.packages/webgl-viewer/- High-performance WebGL-based photo viewer component.packages/data/- Shared data access layer and PhotoLoader singleton.packages/components/- Reusable UI components shared across apps.packages/ui/- Core UI elements and design system components.packages/hooks/- Shared React hooks.packages/utils/- Utility functions.
Next.js as SPA Host & SEO Provider
Dual Server Architecture (for apps/ssr):
- Development Mode:
apps/ssr/src/app/[...all]/route.tscatches all SPA routes and servesindex.htmlwith injected manifest data from the static JSON file. - Production Mode: Next.js serves pre-built Vite SPA assets while providing dynamic OG image generation.
Dynamic SEO Implementation:
apps/ssr/src/index.html.ts- Pre-compiled HTML template with manifest data injected aswindow.__MANIFEST__.- Dynamic OG images generated per photo via Next.js API routes (
/og/[photoId]/route.ts). - HTML meta tags dynamically replaced for social media sharing.
Configuration Architecture
Two-Layer Configuration System:
-
Builder Config (
builder.config.ts) - Infrastructure/Processing Layer:- Controls photo processing, storage connections, and build performance.
- Handles remote git repository sync for manifest/thumbnails.
- Configures multi-process/cluster processing for large photo sets.
-
Site Config (
site.config.ts+config.json) - Presentation/Content Layer:{ name: "Gallery Name", description: "...", author: { name: "...", url: "...", avatar: "..." }, social: { twitter: "...", github: "..." }, map: ["maplibre"] // Map provider configuration }- Controls site branding, author info, social links.
- Merged with user
config.json. - Consumed by both SPA and SSR/Backend for consistent branding.
Manifest Generation & Data Flow
Builder Pipeline (packages/builder/src/cli.ts):
- Storage Sync: Downloads photos from S3/GitHub with incremental change detection.
- Format Processing: HEIC→JPEG, TIFF→web formats, Live Photo detection.
- Multi-threaded Processing: Configurable worker pools or cluster mode for performance.
- EXIF & Metadata Extraction: Camera settings, GPS, Fujifilm recipes, tone analysis.
- Thumbnail Generation: Multiple sizes with blurhash placeholders.
- Manifest Serialization: Generates
photos-manifest.jsonwith full metadata. - Remote Sync: Pushes updates to a git repository if configured.
SPA Data Consumption (packages/data/src/index.ts):
class PhotoLoader {
constructor() {
this.photos = window.__MANIFEST__.data // Injected via global
this.cameras = window.__MANIFEST__.cameras
this.lenses = window.__MANIFEST__.lenses
// Creates lookup maps and provides data access layer
}
}
Data Flow Scenarios:
- Static/SSR Flow:
- Builder generates
photos-manifest.json. apps/ssrreads the JSON and injects it into the HTML aswindow.__MANIFEST__.- SPA's
PhotoLoaderconsumes the global data.
- Builder generates
- Full Backend Flow:
be/apps/corefetches data from the database.- It generates the manifest object in memory.
- It injects the manifest into the HTML as
window.__MANIFEST__before serving the page. - SPA's
PhotoLoaderconsumes the global data, unaware of the source.
Key Technologies
- Frontend: React 19, TypeScript, Vite, Tailwind CSS, Jotai (state), TanStack Query
- SSR Layer: Next.js 15
- Backend: Hono, Drizzle ORM, PostgreSQL, tsyringe (for DI)
- Image Processing: Sharp, exiftool-vendored, HEIC conversion, blurhash generation
- Storage: S3-compatible (AWS/MinIO), GitHub repository storage
- Build System: pnpm workspaces, concurrent dev servers, cluster-based processing
Development Workflow
- Concurrent Development:
pnpm devruns both SPA (Vite) and SSR (Next.js) servers. Usepnpm --filter @afilmory/core devto run the full backend. - Hot Reloading: SPA changes reflect immediately.
- Manifest Building:
pnpm run build:manifestprocesses photos and updates the staticphotos-manifest.json. - Type Safety: Shared types between builder, SPA, and servers ensure consistency.
- Page Structure: Keep files under
pages/as thin routing shells; move reusable UI/logic intomodules/<domain>/**. - State Isolation: When a UI feature has deep subtrees (e.g., photo library actions), do not thread handler props through multiple layers. Lift shared logic into colocated contexts or local stores (Jotai/Zustand) that expose hooks and let the consuming components trigger actions directly. This minimizes prop drilling and avoids unnecessary React re-renders.
Code Quality Rules
- Avoid code duplication - extract common types and components.
- Keep components focused - use hooks and component composition.
- Follow React best practices - proper Context usage, state management.
- Use TypeScript strictly - leverage type safety throughout.
- Build React features out of small, atomic components. Push data fetching, stores, and providers down to the feature or tab that actually needs them so switching views unmounts unused logic and prevents runaway updates instead of centralizing everything in a mega component.
i18n Guidelines
- Use flat keys with
.separation (e.g.,exif.camera.model). - Support pluralization with
_oneand_othersuffixes. - Modify English first, then other languages (ESLint auto-removes unused keys).
- CRITICAL: Avoid nested key conflicts in flat structure.
- During build, flat dot-separated keys are automatically converted to nested objects. A key cannot be both a string value AND a parent object.
- ❌ WRONG:
"action.tag.mode.and": "AND"+"action.tag.mode.and.tooltip": "..." - ✅ CORRECT:
"action.tag.mode.and": "AND"+"action.tag.tooltip.and": "..." - ❌ WRONG:
"photo.share.preview": "Share preview"+"photo.share.preview.download": "Download preview" - ✅ CORRECT:
"photo.share.preview": "Share preview"+"photo.share.downloadPreview": "Download preview" - Rule: If a key
a.b.cexists as a string value, you cannot usea.b.c.das a child key. Use a different parent path likea.b.dor rename the child key to avoid the conflict.
Testing Strategy
- Check
README.mdandpackage.jsonscripts for test commands. - Verify builds work with
pnpm build. - Test photo processing with
pnpm run build:manifest. - Validate types with
pnpm --filter web type-check.
Design System
This project contains multiple web applications with distinct design systems. For specific UI and design guidelines, please refer to the AGENTS.md file within each application's directory:
apps/web: Contains the "Glassmorphic Depth Design System" for the main user-facing photo gallery. Seeapps/web/AGENTS.mdfor details.be/apps/dashboard: Contains guidelines for the functional, data-driven UI of the administration panel (linear, data-first aesthetic). Seebe/apps/dashboard/AGENTS.mdfor details.
IMPORTANT
Avoid feature gates/flags and any backwards compability changes - since our app is still unreleased" is really helpful.