Skip to content

Repository files navigation

Palette Platform

Palette Platform is an end-to-end, multi-platform color discovery and collection platform. It provides a production-grade REST API built with Kotlin and Spring Boot, a modern responsive web client with Vue 3 and TypeScript, and native mobile apps powered by Kotlin Multiplatform (KMP) sharing networking, business logic, and offline caching across Android (Jetpack Compose) and iOS (SwiftUI).

Architecture & Features

The platform is designed around a clean modular monolith backend and client apps:

  • identity: User registration, authentication, JWT access tokens, opaque refresh tokens with rotation and SHA-256 database hashing, logout, and current user retrieval.
  • palette: Palette creation, editing, deletion, detail lookup, random palette discovery, and feed listing (newest, popular, tag filtering, name search, hex color filtering, pagination).
  • favorite: Idempotent palette favoriting/unfavoriting, personal collections, atomic count updates preventing negative likes.
  • moderation: Admin review queue (pending palettes), publish, reject, archive operations with an audit trail (moderation_logs).
  • mobile (KMP): Shared Kotlin Multiplatform core (mobile/shared/) powering both native Android (Jetpack Compose) and native iOS (SwiftUI) applications with zero business logic duplication.
  • web: Responsive Vue 3 + TypeScript SPA mirroring mobile design specifications with dark/light themes.
  • shared: RFC 9457 ProblemDetail error handling, rate limiting filter, OpenAPI / Swagger documentation, Actuator health and metrics probes.

Technology Stack

  • Backend: Kotlin 2.0.21 on Java 17+, Spring Boot 3.4.3, Spring Data JPA, Hibernate, PostgreSQL, Flyway, Spring Security, JJWT
  • Mobile (KMP): Kotlin Multiplatform (KMP), Ktor Client, Kotlinx Coroutines, Kotlinx Serialization, Android Jetpack Compose, iOS SwiftUI
  • Web: Vue 3 (Composition API), TypeScript, Vite, Pinia, Vue Router
  • Documentation: SpringDoc OpenAPI 3 / Swagger UI
  • Testing: JUnit 5, MockK, MockMvc, Testcontainers PostgreSQL, Vitest, Playwright, XCTest
  • Quality: Detekt static analysis, ESLint, Prettier
  • Containers & CI/CD: Docker, Docker Compose, GitHub Actions, GitHub Container Registry (GHCR)

Repository Layout

palette-platform/
├── backend/                 Kotlin + Spring Boot REST API
├── web/                     Vue.js 3 + TypeScript Client (Vite, Pinia)
├── mobile/                  Mobile clients & Kotlin Multiplatform (KMP)
│   ├── shared/              Shared KMP Core (Ktor, domain models, use cases, offline cache)
│   ├── androidApp/          Android native client (Jetpack Compose, Material 3)
│   └── iosApp/              iOS native client (SwiftUI)
├── infrastructure/          Docker and deployment configuration
├── docs/                    Product, mobile, and engineering documentation
└── .github/workflows/       Path-scoped CI and Release pipelines

Environment Variables

Variable Default Description
PORT 8080 Server HTTP listening port
DB_URL jdbc:postgresql://localhost:5432/palette PostgreSQL JDBC connection URL
DB_USERNAME palette Database username
DB_PASSWORD palette Database password
JWT_SECRET Development default string (32+ bytes) Secret key for signing HMAC-SHA256 JWT tokens
JWT_ACCESS_TOKEN_EXPIRATION_MINUTES 15 Expiration lifetime for access tokens in minutes
JWT_REFRESH_TOKEN_EXPIRATION_DAYS 7 Expiration lifetime for refresh tokens in days

Run Locally

Requirements: Java 17+ (JDK 17) and Docker (or local PostgreSQL).

Run with Local PostgreSQL

  1. Start PostgreSQL:
docker compose -f infrastructure/docker/compose.yml up -d postgres
  1. Start Spring Boot backend:
cd backend
./gradlew bootRun
  1. Access Health and Swagger UI:
  • Health probe: curl http://localhost:8080/actuator/health
  • OpenAPI Specification: http://localhost:8080/v3/api-docs
  • Swagger UI: http://localhost:8080/swagger-ui.html

Run Complete Stack with Docker Compose

docker compose -f infrastructure/docker/compose.yml --profile full up --build

Testing & Quality

Run unit and web tests:

cd backend
./gradlew test

Run static analysis with Detekt:

cd backend
./gradlew detekt

Build executable JAR:

cd backend
./gradlew bootJar

Run Testcontainers PostgreSQL integration tests:

cd backend
TESTCONTAINERS_ENABLED=true ./gradlew test

API Overview & Curl Examples

Base path: /api/v1

1. Register User

curl -X POST http://localhost:8080/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "designer@example.com",
    "password": "Password123!",
    "displayName": "ColorCrafter"
  }'

Response:

{
  "accessToken": "eyJhbGciOi...",
  "refreshToken": "xP93nK...",
  "tokenType": "Bearer",
  "user": {
    "id": "c3f8e6c4-...",
    "email": "designer@example.com",
    "displayName": "ColorCrafter",
    "role": "USER",
    "createdAt": "2026-09-16T19:00:00Z"
  }
}

2. Log In

curl -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "designer@example.com",
    "password": "Password123!"
  }'

3. Refresh Access Token

curl -X POST http://localhost:8080/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "xP93nK..."
  }'

4. Create Palette

Palettes require exactly 4 valid, uppercase, non-duplicate HEX colors:

curl -X POST http://localhost:8080/api/v1/palettes \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nordic Autumn",
    "colors": ["#2E3440", "#4C566A", "#D8DEE9", "#ECEFF4"],
    "tags": ["nordic", "cool", "minimal"],
    "publish": true
  }'

5. List Palettes

Publicly query newest or popular palettes with optional search query, tag, or exact HEX color:

curl "http://localhost:8080/api/v1/palettes?sort=popular&tag=minimal&page=0&size=20"

6. Favorite and Unfavorite Palette

# Favorite
curl -X POST http://localhost:8080/api/v1/palettes/<PALETTE_ID>/favorite \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

# Unfavorite
curl -X DELETE http://localhost:8080/api/v1/palettes/<PALETTE_ID>/favorite \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

7. Moderation (Admin Only)

# List pending palettes
curl http://localhost:8080/api/v1/admin/palettes/pending \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

# Publish pending palette
curl -X POST http://localhost:8080/api/v1/admin/palettes/<PALETTE_ID>/publish \
  -H "Authorization: Bearer <ADMIN_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Meets quality standards"}'

Troubleshooting

  • Port in use: Change PORT in environment variables or command line (-DPORT=8081).
  • Database connection error: Verify Docker is running and PostgreSQL is ready (pg_isready -U palette -d palette).
  • Authentication failure: Ensure the Authorization header starts with Bearer .
  • Invalid palette submission: Ensure all four colors are distinct 6-character hex strings with # prefix.

Documentation

About

Full-stack color palette discovery & collection platform with Spring Boot backend, Kotlin Multiplatform (KMP), Jetpack Compose Android, and SwiftUI iOS.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages