profileShare

rasmusjy / tasteprint

Read-only snapshot

No repository description.

main default branch 169 files Expires Sep 13, 2026, 9:06 AM
README.md 5,409 bytes

Tasteprint

Tasteprint is a travel food passport. Users record dishes they have tried, see which parts of a food culture they have covered, receive a five-bite mission for an upcoming trip, and compare or combine their map with friends.

The product measures cultural breadth instead of restaurant visits. Each destination starts with six entry points: staple, street food, breakfast, sweet, drink, and signature dish. Importance weights keep a famous or defining dish more meaningful than a secondary discovery.

What is included

  • Account registration, login, opaque bearer sessions, logout, editable profiles, and verified account deletion
  • A curated atlas of 12 destinations and 72 dishes
  • Tasting journal with ratings, notes, dates, places, coordinates, and validated photo uploads
  • Weighted world and destination coverage
  • Important missing dishes based on the user's current map and next trip
  • Trips with a persisted five-bite mission and date-aware completion
  • Shared destination challenges with invite codes and group progress
  • Public Tasteprint pages with privacy controls
  • Two-person taste map comparison and a suggested shared bite
  • Responsive desktop and mobile interfaces
  • OpenAPI documentation, health probes, Docker deployment, and CI

Architecture

Browser
  |
  v
Nginx, React single-page application
  |
  +---- /api and /uploads
            |
            v
      Spring Boot modular monolith
       |          |          |
       v          v          v
   PostgreSQL  file media  health and OpenAPI

The backend is a modular monolith. Account, catalog, tasting, journey, progress, media, social, and demo data are separate Java packages with verified Spring Modulith boundaries. This keeps deployment and transactions simple while preserving service boundaries that can be extracted later if scale requires it.

See Architecture for module ownership, request flows, security choices, and the reasons for not starting with microservices.

Stack

Area Technology
Backend Java 21, Spring Boot 3.5, Spring Security, Spring Data JPA
Architecture Spring Modulith
Database PostgreSQL 17, Flyway migrations, H2 for fast integration tests
Frontend React 19, TypeScript 5.9, Vite, TanStack Query, React Router
Map D3 Geo, TopoJSON, Natural Earth data through world-atlas
Testing JUnit 5, MockMvc, Testcontainers, Vitest, Testing Library
Delivery Docker Compose, Nginx, GitHub Actions

Run with Docker

Requirements: Docker Desktop or Docker Engine with Compose.

cp .env.example .env
docker compose up --build

Open:

  • Application: http://localhost:3000
  • API documentation: http://localhost:8080/docs
  • Backend readiness: http://localhost:8080/actuator/health/readiness

The local demo account is:

Email: demo@tasteprint.app
Password: tasteprint

Set DEMO_DATA_ENABLED=false before a public deployment. Replace the sample database password in .env with a generated secret.

Run for development

Start the backend. No local database is required because development defaults to a file-backed H2 database in PostgreSQL compatibility mode.

cd backend
.\mvnw.cmd spring-boot:run

In another terminal:

cd frontend
npm install
npm run dev

Vite serves the interface at http://localhost:5173 and proxies API and upload requests to port 8080.

Tests

Backend tests cover authentication, validation, privacy, ownership, tasting CRUD, paging, trip missions, shared challenge progress, media validation, CORS, module boundaries, and application startup.

cd backend
.\mvnw.cmd verify

The PostgreSQL compatibility test runs automatically when Docker is available and skips cleanly when it is not.

Frontend tests cover the API client, expired sessions, protected routing, date behavior, and formatting. The production build also performs strict TypeScript checking.

cd frontend
npm test
npm run lint
npm run build

Configuration

Variable Purpose Local default
DB_URL JDBC database URL File-backed H2
DB_USER Database user sa
DB_PASSWORD Database password Empty
APP_ALLOWED_ORIGINS Comma-separated browser origins Local frontend ports
MEDIA_DIRECTORY Photo storage path ./uploads
DEMO_DATA_ENABLED Seed demo accounts and activity true
PORT Backend HTTP port 8080

Product rules

  • A dish counts toward a user's global Tasteprint wherever it was eaten.
  • A dish counts toward a trip only when the tasting country and date match that trip.
  • A challenge combines member dishes logged within its date range. This allows both travel groups and local tasting clubs.
  • Coverage is weighted by cultural importance and means breadth, not expertise.
  • Public pages are private by default and never expose email addresses, exact coordinates, restaurant details, or internal timestamps.
  • Uploaded files are limited to 6 MB, checked by MIME type and file signature, bound to their owner, and removed with their last tasting or account.

The catalog is intentionally stored as reviewed migration data, not copied blindly from a third-party popularity feed. Adding a destination means adding six balanced cultural entry points with an explanation of why each matters.