Getting Started

Prerequisites before you begin:

  • Java 17 or 21 installed
  • Node.js 18 or higher installed
  • PostgreSQL 15 running locally
  • Maven 3.9 (or use the included ./mvnw wrapper)

Step 1 — Download and unzip

Download your generated ZIP from zovlyn.dev. Unzip it into your projects folder. You will see three things at the root: backend/, frontend/, and AGENTS.md. If you enabled Docker, docker-compose.yml is also there.

Step 2 — Create your database

This is required. The backend will refuse to start if the database does not exist. Run this once in your terminal before anything else:

psql -U postgres -c "CREATE DATABASE your_project_db;"

Replace your_project_db with the name you entered during generation. Replace postgres with your local PostgreSQL username if it is different.

Not sure what your username is? Run:

psql -c "\du"

The database name is also shown in backend/AGENTS.md and backend/src/main/resources/application-local.yml inside your downloaded ZIP.

Step 3 — Start the backend

cd backend
./mvnw spring-boot:run

Wait for: "Started Application in X seconds". Verify: GET http://localhost:8080/api/health returns OK.

Step 4 — Start the frontend

cd frontend
npm install
npm run dev

Open http://localhost:3000 in your browser.

Step 5 — Verify the connection

The home page will confirm the backend is reachable. If you see any errors, check the troubleshooting section in the FAQ below.

Project Structure

Your generated project follows a strict separation of concerns. Every layer has one job and one job only.

Root level

  • AGENTS.md — Context file for AI coding agents
  • stack.md — Full technical reference
  • README.md — Setup instructions
  • docker-compose.yml — Docker setup (if enabled)

backend/

src/main/java/your.package/
  config/      # Spring configuration classes
  controller/  # REST controllers — HTTP layer only
  service/     # Business logic — no HTTP concerns
  repository/  # JPA interfaces — data access only
  model/       # JPA entity classes
  dto/
    request/   # Incoming request body classes
    response/  # Outgoing response body classes
  exception/   # Global exception handlers

frontend/

app/           # Next.js App Router pages and routes
  api/         # Server-side proxy routes to backend
components/    # Reusable UI and layout components
hooks/         # Custom React hooks
lib/
  api/         # All backend call functions live here
  utils/       # Pure utility functions
types/         # TypeScript interfaces

The rule: never put business logic in a controller. Never call fetch() directly inside a React component. Always go through lib/api/ functions.

Running Locally

Running locally means PostgreSQL runs on your machine and both services run as normal processes. No Docker needed.

# Start the backend
cd backend
./mvnw spring-boot:run

# Start the frontend
cd frontend
npm install
npm run dev

The frontend runs on port 3000. It calls the backend through Next.js API routes — never directly. This is why there are no CORS issues.

Running with Docker

Docker mode runs the backend and PostgreSQL as containers. The frontend still runs locally with npm run dev for hot reload during development.

Important: with Docker you do NOT need to create the database manually. Docker Compose creates it automatically using the POSTGRES_DB environment variable. Just run:

docker compose up --build

If port 8080 is already in use on your machine, stop any running Spring Boot processes before running Docker. Run: lsof -i :8080 to find what is using it, then kill that process.

PostgreSQL will run on port 5433 to avoid conflicts with local instances. The backend will be available at http://localhost:8080.

Profile System

The backend uses Spring Profiles to switch database configuration without touching any Java code. The active profile is set in backend/src/main/resources/application.yml.

  • local: Connects to localhost:5432.
  • docker: Connects to the postgres container.
  • supabase: Connects to a hosted Supabase instance.

CORS Configuration

Zovlyn uses the Next.js proxy pattern to eliminate CORS. The browser calls Next.js at http://localhost:3000/api/*, which forwards calls to Spring Boot server-to-server.

Never call fetch('http://localhost:8080/...') anywhere in the frontend — it will break in production and cause CORS errors in development.

Environment Variables

Frontend (.env.local)

BACKEND_URL=http://localhost:8080
NEXT_PUBLIC_API_URL=http://localhost:8080

Backend

Variables like SPRING_DATASOURCE_URL are typically handled via profiles or environment variables in production.

Adding a Feature

Backend order: Entity → Repository → DTOs → Service → Controller.

Frontend order: Type → Proxy route → API function → Component.

// Example Task Entity
@Entity
@Table(name = "tasks")
public class Task {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private boolean completed;
}

FAQ

Why does the backend fail with database does not exist?

You need to create the PostgreSQL database manually before running locally. Run: psql -U postgres -c 'CREATE DATABASE your_db;' replacing your_db with your project name. This is a one-time setup step. With Docker this is handled automatically.

Why does Docker fail with port already in use?

Something else is already running on port 8080 — usually a Spring Boot process you did not stop. Find it with: lsof -i :8080. Then kill it with: kill -9 <PID>. Then run docker compose up --build again.

Why does the frontend never call the backend directly?

Because of CORS. Browsers block requests from one origin (port 3000) to another (port 8080) by default. The Next.js proxy pattern routes all backend calls through the Next.js server, which has no CORS restrictions. This also means your backend URL never appears in the browser — it stays server-side only.

What are AGENTS.md files?

Markdown files written specifically for AI coding agents like Claude Code, Cursor, and Copilot. They explain the project architecture, naming conventions, how to add features, what profiles exist, and what each folder is for. When an AI agent opens your project it reads these files first and immediately understands how to help you — without you re-explaining anything.

Why are there three AGENTS.md files?

One at the root explains the overall system and how the two services connect. One in backend/ explains Spring Boot specifics. One in frontend/ explains Next.js specifics. Each AI agent reads the file closest to where it is working, so context is always precise and relevant.

Why Java 17 or 21 and not the latest?

17 and 21 are LTS (Long Term Support) releases. They receive security patches for years and are stable for production. Non-LTS releases are short-lived and not recommended for production projects. Always pick an LTS version.

Why does Docker use port 5433 for PostgreSQL?

Because your local machine likely already runs PostgreSQL on port 5432. Using 5433 for the Docker container avoids the conflict. Inside Docker the containers still talk to each other on port 5432 — only the host-facing port is 5433.

Why no Spring Security in v1?

Spring Security locks all endpoints by default. To keep the starter template "run out of the box" simple, it is intentionally left out for you to add once ready.

Can I add Spring Security myself?

Yes. Add spring-boot-starter-security to pom.xml and create a SecurityConfig class. Modern Spring uses the SecurityFilterChain bean approach. Your AGENTS.md files will help an AI agent add this correctly.

Why does the generated project use constructor injection?

Constructor injection is the recommended approach in modern Spring. It makes dependencies explicit, makes testing easier, and avoids null injection issues. Never use @Autowired field injection in new Spring Boot code. Lombok's @RequiredArgsConstructor generates the constructor automatically.

Can I rename the project after generating?

Yes, but it involves several steps across Java package names, pom.xml, package.json, and database configurations. It is generally easier to generate a fresh project with the correct name.

What is stack.md?

A comprehensive technical reference for the generated project. It lists every technology and version, the full folder structure with explanations, and common commands. Read it before starting development.

The backend starts but the frontend shows connection error.

Check that BACKEND_URL in .env.local points to http://localhost:8080. Ensure the backend actually started (look for "Started Application"). Try hitting /api/health directly in your browser.

Can I deploy this to production?

Yes. Deploy the backend to Railway and the frontend to Vercel. Set BACKEND_URL in Vercel to your Railway URL. Update the CORS allowed origins in CorsConfig.java to include your production URL.