VernissageWeb
Application which is Web component for Vernissage photos sharing platform.
Install / Use
/learn @VernissageApp/VernissageWebREADME
Vernissage Web
Web client for Vernissage, a federated, photo-first social platform connected to the fediverse through ActivityPub.
This repository contains the Angular application used to browse timelines, publish content, manage accounts, moderate content, and work with server settings from the browser. It supports SSR, hydration, service worker updates, and production deployment through Docker.
<p align="center"> <img src="images/01.png" width="400" alt="Vernissage Web screenshot 1"> <img src="images/02.png" width="400" alt="Vernissage Web screenshot 2"> </p>Highlights
- Angular 21 application with server-side rendering and client hydration
- Photo-focused timelines, profiles, search, upload, bookmarks, favourites, and notifications
- Authentication flow based on access token refresh, cookies, and XSRF protection
- PWA support with Angular service worker update handling
- Configurable instance branding through public settings, custom CSS, and custom JS
- Shared product surface with the Vernissage API and iOS client
Quick Links
- Project website: joinvernissage.org
- Documentation: docs.joinvernissage.org
- API server: VernissageServer
- iOS client: VernissageMobile
- Create an account: vernissage.photos
Requirements
- Node.js 24
- npm
- a running Vernissage API server, usually available on
http://localhost:8080during local development
For backend setup, see VernissageServer.
Getting Started
- Clone the repository.
- Install dependencies:
$ npm install --force
- Start the local development server:
$ npm start
- Open http://localhost:4200.
The app reloads automatically when source files change.
Development Commands
$ npm start # Angular dev server
$ npm run build # Production browser + server build
$ npm run lint # ESLint
$ npm test # Karma/Jasmine tests
$ npm run serve:ssr
How This App Fits Into Vernissage
The web client talks to the Vernissage Server HTTP API. In local development it expects:
- web app on
http://localhost:4200 - API server on
http://localhost:8080
In deployed environments the client usually talks to the API on the same public host. The backend then connects to PostgreSQL or SQLite, Redis, and S3-compatible object storage depending on deployment mode.
Architecture
The repository follows a UI-oriented Angular structure:
src/app/pages- route-level screens such as home, profile, upload, settings, search, and moderation pagessrc/app/components- reusable UI building blocks, split intocorelayout parts andwidgetssrc/app/dialogs- modal flows and edit dialogssrc/app/services/http- API clients grouped by backend resourcesrc/app/services/common- browser, SSR, loading, routing, preferences, and UI support servicessrc/app/services/authorization- sign-in state, refresh-token flow, and route guardssrc/app/models- API and view modelssrc/app/directives,src/app/pipes,src/app/validators- shared template utilitiesserver.ts- Express-based SSR entrypoint with optional security headers
Runtime Flow
At startup the app:
- tries to refresh the access token,
- loads instance metadata and public settings from the API,
- injects custom scripts and styles exposed by the server,
- hydrates the Angular application in the browser,
- registers the service worker outside development mode.
Request handling is centered around:
APIInterceptor, which addswithCredentialsand theX-XSRF-TOKENheader,AuthorizationService, which refreshes expired sessions,GlobalErrorHandler, which maps failures to dedicated error pages and reports unexpected client-side errors.
Routing Model
Routes are defined in src/app/pages/pages-routing.module.ts. The application mixes public pages and authenticated areas:
- public: home, news, public profiles, status pages, FAQ, terms, privacy
- authenticated: upload, notifications, invitations, account, settings, reports, shared cards, moderation views
Several gallery-like views use route reuse and shared context state to preserve timeline data when navigating between screens.
Repository Layout
src/main.tsandsrc/main.server.ts- browser and server bootstrapsrc/app/app.module.ts- root module, hydration, service worker, interceptors, global error handlersrc/app/pages/pages.module.ts- all route-level page declarationssrc/styles- global SCSS variables, fonts, utilities, and layout helperssrc/assets- icons, fonts, screenshots, and bundled client assetsDockerfile- multi-stage SSR image build.github/workflows/build.yml- CI build, lint, test, and production build verification
SSR, PWA, and Deployment
The production build includes both browser assets and a server bundle. SSR is served through Express and @angular/ssr, while static assets are emitted to dist/VernissageWeb/browser.
Build locally:
$ npm run build
$ npm run serve:ssr
Build a Docker image:
$ docker build -t vernissage-web .
$ docker run --rm -p 8080:8080 vernissage-web
Production images are published to Docker Hub.
Security Headers
When running the SSR server in production, it is recommended to enable the image source used in the Content Security Policy through the VERNISSAGE_CSP_IMG environment variable:
export VERNISSAGE_CSP_IMG=https://s3.eu-central-1.amazonaws.com
This value is used by server.ts to extend the Content-Security-Policy header for remote image loading.
Angular SSR also validates request hostnames (SSRF protection). To allow your production host, configure one of the following environment variables:
export VERNISSAGE_ALLOWED_HOSTS=yourdomain.photos,*.otherdomain.social
# or
export NG_ALLOWED_HOSTS=yourdomain.photos,*.otherdomain.social
If no variable is provided, the server falls back to:
localhost, 127.0.0.1, ::1, vernissage.photos, *.vernissage.photos.
Contributing
Contributions are welcome.
- Keep changes focused and aligned with the existing module structure.
- Run
npm run lint,npm test, andnpm run buildbefore opening a pull request. - Document any behavior changes that affect SSR, authentication, or deployment.
License
This project is licensed under the Apache License 2.0.
