diff --git a/.gitignore b/.gitignore index 62fcee8..bcf51bf 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ # production /build +/dist # misc .DS_Store @@ -41,3 +42,6 @@ yarn-error.log* next-env.d.ts /lib/generated/prisma + +# IDE +.vscode/ diff --git a/CLAUDE.md b/CLAUDE.md index b643fb6..80d30c8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,16 +5,70 @@ competency-based learning. ## Tech Stack -Next.js 15 (App Router) · React 19 · TypeScript · shadcn/ui · Tailwind CSS 4 · PostgreSQL 16 · -Prisma (planned) · Zustand + TanStack Query · Vitest + Playwright (planned) · Docker +**Frontend**: Next.js 15 (App Router) · React 19 · TypeScript · shadcn/ui · Tailwind CSS 4 · React +Query · Axios + +**Backend**: Spring Boot 4.0 · Java 25 · PostgreSQL 16 · Flyway · JPA/Hibernate + +**Auth**: Keycloak 26.4 · OAuth2 · JWT + +**Deployment**: Docker Compose · Gradle + +## Architecture + +``` +Next.js Frontend (port 3000) +├── React Components +├── TanStack Query (server state) +├── Axios API Client +├── Keycloak Authentication +└── TypeScript API Types + +Spring Boot Backend (port 8080) +├── REST Controllers + OpenAPI +├── Service Layer +├── Spring Data JPA +├── JPA Entities +├── Flyway Migrations +└── Spring Security + OAuth2 + +Keycloak (port 8081) +└── OAuth2/JWT Authentication + +PostgreSQL (port 5433) +└── Application Database +``` ## Key Conventions - **Components**: PascalCase files, Server Components by default, `'use client'` only when needed - **Code Style**: Self-documenting code, minimal comments, rely on ESLint/Prettier - **Git**: Feature branches → PR → merge to main, multiple commits per branch OK -- **Deployment**: Manual GitHub Actions triggers for staging/production -- **Docker**: Use `./docker-manage.sh` for all operations (memo-dev, memo-staging, memo-prod) +- **API**: RESTful endpoints, JWT authentication required +- **Backend**: Use `server/server-manage.sh` for Spring Boot operations +- **Frontend**: Standard Next.js development workflow + +## Quick Start + +**Backend:** + +```bash +cd server +./server-manage.sh up +``` + +**Frontend:** + +```bash +npm run dev +``` + +**Access:** + +- Frontend: http://localhost:3000 +- API: http://localhost:8080 +- Swagger UI: http://localhost:8080/swagger-ui.html +- Keycloak: http://localhost:8081 (admin/admin) ## AI Subagents @@ -22,9 +76,9 @@ Five specialized agents in `.claude/agents/`: 1. **senior-architect** - Plans & orchestrates (NO implementation). Use proactively for new features. -2. **nextjs-expert** - App Router, routing, Server Actions +2. **nextjs-expert** - App Router, routing, React components 3. **shadcn-expert** - UI components, Tailwind -4. **database-expert** - PostgreSQL, Prisma, domain modeling +4. **database-expert** - PostgreSQL, JPA, Spring Data 5. **docker-expert** - Containers, deployment ## Workflow @@ -32,5 +86,29 @@ Five specialized agents in `.claude/agents/`: For new features: senior-architect analyzes → designs → creates plan → gets approval → orchestrates specialized agents -Commands: `npm run quality` (type-check + lint + format), `npm run dev`, -`./docker-manage.sh up development` +**Frontend Commands:** + +- `npm run dev` - Development server +- `npm run build` - Production build +- `npm run quality` - Type-check + lint + format + +**Backend Commands:** + +- `cd server && ./server-manage.sh up` - Start all services +- `./server-manage.sh logs` - View logs +- `./server-manage.sh build` - Build Spring Boot app +- `./server-manage.sh test` - Run tests + +## Documentation + +- **QUICKSTART.md** - Step-by-step setup guide +- **MIGRATION_COMPLETE.md** - Migration summary +- **server/README.md** - Backend documentation +- **SECURITY.md** - Security guidelines + +## Authentication + +All API requests require JWT token from Keycloak. Default users: + +- **Demo**: `demo@memo.local` / `demo` (USER role) +- **Admin**: `admin@memo.local` / `admin` (ADMIN role) diff --git a/DATABASE.md b/DATABASE.md deleted file mode 100644 index 3cba45d..0000000 --- a/DATABASE.md +++ /dev/null @@ -1,124 +0,0 @@ -# Database Setup and Migrations - -## Overview - -PostgreSQL 16 with Prisma ORM. **Migrations auto-apply on server startup** in all environments. - -## Setup - -**Using Docker (recommended):** - -```bash -./docker-manage.sh up development -``` - -- Database runs automatically in Docker -- No `.env` file needed - `DATABASE_URL` is set in `docker-compose.yml` -- Migrations run on startup - -**Using Prisma Studio GUI:** - -1. Ensure Docker database is running: `./docker-manage.sh up development` -2. Create `.env` file in project root with `DATABASE_URL` from - `docker/development/docker-compose.yml` -3. Run: `npm run db:studio` - -## Quick Start - -```bash -# Development -./docker-manage.sh up development - -# Production/Staging -./docker-manage.sh up production -./docker-manage.sh up staging -``` - -## How Migrations Work - -**Automatic on startup:** - -- **Production/Staging**: Crashes if migration fails (safe) -- **Development**: Continues if migration fails (non-blocking) - -**Creating migrations:** - -```bash -# 1. Edit prisma/schema.prisma -# 2. Create migration file -npm run db:migrate - -# 3. Restart server - migration auto-applies -./docker-manage.sh restart development -``` - -## Database Scripts - -| Script | Purpose | -| ------------- | --------------------------------- | -| `db:migrate` | Create new migration file | -| `db:studio` | Open Prisma Studio GUI | -| `db:reset` | Reset database (⚠️ destroys data) | -| `db:generate` | Regenerate Prisma Client | -| `db:seed` | Seed demo user + competencies | - -## Common Tasks - -**View database:** - -```bash -# Prisma Studio (GUI) - requires .env file with DATABASE_URL -npm run db:studio -# Opens at http://localhost:5555 -``` - -Alternatively, use VS Code PostgreSQL extensions with connection: - -- Host: `localhost`, Port: `5432`, Database: `memo_dev` -- Username: `memo_user`, Password: `memo_password` - -**Check migration status:** - -```bash -npx prisma migrate status -``` - -**Reset database (dev only):** - -```bash -npm run db:reset -``` - -**Seed demo content (user + 5 competencies):** - -```bash -npm run db:seed -``` - -Creates a demo user (`demo@memo.local`) and 5 sample competencies. Idempotent, safe to run multiple -times. - -## Schema - -See [prisma/schema.prisma](prisma/schema.prisma) for the complete schema. - -Models: User, Competency, CompetencyRelationship, LearningResource, CompetencyResourceLink - -## Troubleshooting - -**"Database schema is not in sync"** - -```bash -npm run db:migrate -``` - -**"Prisma Client out of sync"** - -```bash -npm run db:generate -``` - -**Production migration failed** - -- Check `DATABASE_URL` environment variable -- View logs: `./docker-manage.sh logs production` diff --git a/DEPLOYMENT_CHECKLIST.md b/DEPLOYMENT_CHECKLIST.md deleted file mode 100644 index 08c8aab..0000000 --- a/DEPLOYMENT_CHECKLIST.md +++ /dev/null @@ -1,75 +0,0 @@ -# Deployment Setup Verification Checklist - -## ✅ **GitHub Actions Workflows** - -- [x] `build-and-push.yml` - Builds and pushes Docker images -- [x] `deploy-staging.yml` - Deploys to staging environment -- [x] `deploy-production.yml` - Deploys to production environment -- [x] No development deployment workflow (correct!) - -## ✅ **Docker Compose Files** - -- [x] `docker/development/docker-compose.yml` - Local development (uses build:) -- [x] `docker/staging/docker-compose.yml` - Uses registry image with ${IMAGE_TAG} -- [x] `docker/production/docker-compose.yml` - Uses registry image with ${IMAGE_TAG} - -## ✅ **Environment Files** - -- [x] `docker/development/.env` - Local development config (localhost URLs) -- [x] `docker/staging/.env` - Staging config (staging.memo.aet.cit.tum.de) -- [x] `docker/production/.env` - Production config (memo.aet.cit.tum.de) -- [x] All env files have IMAGE_TAG=latest -- [x] All URLs updated to memo.aet.cit.tum.de domain - -## ✅ **Dockerfile** - -- [x] Multi-stage Dockerfile with development, builder, and production targets -- [x] Properly configured for Next.js application - -## ✅ **Configuration Files** - -- [x] `.dockerignore` - Excludes unnecessary files from build context -- [x] `docker/staging/nginx.conf` - Nginx config for staging -- [x] `docker/production/nginx.conf` - Nginx config for production with security - -## 🔧 **Next Steps Required (Manual Setup)** - -### GitHub Repository Settings: - -1. **Create Environments**: - - Go to `Settings > Environments` - - Create: `Staging`, `Production` - -2. **For each environment, configure**: **Secrets:** - - `VM_SSH_PRIVATE_KEY` - SSH private key for deployment user - - **Variables:** - - `VM_HOST` - Server hostname (e.g., `staging.memo.aet.cit.tum.de`, `memo.aet.cit.tum.de`) - - `VM_USERNAME` - `github_deployment` - -### VM Setup (for each environment): - -1. Create deployment user: `github_deployment` -2. Add to docker group -3. Generate SSH keys -4. Set up deployment directory: `/opt/github` - -## 🚀 **Deployment Process** - -1. **Code Push** → Automatic image build (`ghcr.io/ls1intum/memo/memo-app:latest` or `pr-`) -2. **Staging Deploy** → Manual trigger via GitHub Actions UI -3. **Production Deploy** → Manual trigger via GitHub Actions UI - -## 🎯 **Environment Usage** - -- **Development**: `./docker-manage.sh up development` (local only) -- **Staging**: GitHub Actions deployment (testing) -- **Production**: GitHub Actions deployment (live) - -## ✅ **All Issues Fixed** - -- [x] Removed redundant development deployment workflow -- [x] Fixed all domain URLs to memo.aet.cit.tum.de -- [x] Added IMAGE_TAG to environment files -- [x] Proper separation of local vs CI environments -- [x] Clean file structure without duplicates diff --git a/DOCKER.md b/DOCKER.md deleted file mode 100644 index e6a9c32..0000000 --- a/DOCKER.md +++ /dev/null @@ -1,280 +0,0 @@ -# Memo Docker Setup - -This document describes the Docker setup for the Memo Next.js application across three environments: -development, staging, and production. - -## Architecture Overview - -### Development Environment - -- **App**: Next.js application running in development mode with hot reload -- **Database**: PostgreSQL database -- **Ports**: - - App: 3000 (direct access) - - Database: 5432 (exposed for debugging) - -### Staging Environment - -- **Nginx**: Reverse proxy handling external requests -- **App**: Next.js application in production mode -- **Database**: PostgreSQL database (internal network only) -- **Ports**: - - Nginx: 80 (external access) - -### Production Environment - -- **Nginx**: Reverse proxy with enhanced security and SSL support -- **App**: Next.js application in production mode -- **Database**: PostgreSQL database (internal network only) -- **Ports**: - - Nginx: 80, 443 (external access) - -## Quick Start - -### Prerequisites - -- Docker and Docker Compose installed -- Git repository cloned - -### Using the Management Script - -The `docker-manage.sh` script provides convenient commands for managing all environments: - -```bash -# Start development environment -./docker-manage.sh up development - -# Start staging environment -./docker-manage.sh up staging - -# Start production environment -./docker-manage.sh up production - -# View logs -./docker-manage.sh logs development - -# Stop environment -./docker-manage.sh down development - -# Build images -./docker-manage.sh build staging - -# Connect to database -./docker-manage.sh db-shell production - -# Connect to app container -./docker-manage.sh app-shell development -``` - -### Manual Docker Compose Commands - -If you prefer using Docker Compose directly: - -```bash -# Development -cd docker/development -docker-compose up -d - -# Staging -cd docker/staging -docker-compose up -d - -# Production -cd docker/production -docker-compose up -d -``` - -## Environment Configuration - -Each environment has its own configuration: - -- `docker/development/.env` - Development environment variables -- `docker/staging/.env` - Staging environment variables -- `docker/production/.env` - Production environment variables - -### Important Environment Variables - -Update these variables according to your needs: - -```env -# Database connection -DATABASE_URL=postgresql://memo_user:memo_password@db:5432/memo_dev - -# Next.js public variables -NEXT_PUBLIC_APP_ENV=development -NEXT_PUBLIC_API_URL=http://localhost:3000/api -``` - -## Database Setup - -### Initial Database Setup - -The PostgreSQL databases are automatically created with: - -- Database names: `memo_dev`, `memo_staging`, `memo_prod` -- User: `memo_user` -- Password: `memo_password` (change this in production!) - -### Database Initialization - -Custom initialization scripts can be added to `scripts/init-db.sql`. This script runs when the -database container starts for the first time. - -### Connecting to Database - -```bash -# Using the management script -./docker-manage.sh db-shell development - -# Using docker-compose directly -docker-compose exec db psql -U memo_user -d memo_dev -``` - -## Nginx Configuration - -### Staging and Production - -Nginx is configured as a reverse proxy with: - -- Security headers -- Gzip compression -- Rate limiting (production only) -- Health check endpoint (`/health`) - -### SSL Configuration (Production) - -To enable SSL in production: - -1. Add your SSL certificates to `docker/production/ssl/` -2. Uncomment SSL-related lines in `docker/production/nginx.conf` -3. Update the nginx service volumes in `docker/production/docker-compose.yml` - -## Development Workflow - -### Development Mode - -```bash -./docker-manage.sh up development -# App available at http://localhost:3000 -# Database available at localhost:5432 -``` - -Features: - -- Hot reload enabled -- Source code mounted as volume -- Direct access to application -- Database port exposed for debugging - -### Staging Mode - -```bash -./docker-manage.sh up staging -# App available at http://localhost:80 -``` - -Features: - -- Production build -- Nginx proxy -- Internal database communication -- Staging environment variables - -### Production Mode - -```bash -./docker-manage.sh up production -# App available at http://localhost:80 -``` - -Features: - -- Production build -- Nginx with security features -- Rate limiting -- SSL ready -- Restart policies - -## Troubleshooting - -### Common Issues - -1. **Port conflicts**: Make sure ports 3000, 5432, and 80 are not in use -2. **Permission issues**: Ensure the script is executable: `chmod +x docker-manage.sh` -3. **Database connection**: Check that the database is fully started before the app tries to connect - -### Viewing Logs - -```bash -# All services -./docker-manage.sh logs development - -# Specific service -cd docker/development && docker-compose logs app -cd docker/development && docker-compose logs db -``` - -### Rebuilding Images - -```bash -# Rebuild everything -./docker-manage.sh build development - -# Rebuild specific service -cd docker/development && docker-compose build app -``` - -### Cleaning Up - -```bash -# Remove containers and volumes -./docker-manage.sh clean development - -# Remove everything including images -cd docker/development && docker-compose down -v --rmi all -``` - -## Security Considerations - -### Development - -- Database password is visible in docker-compose files -- Database port is exposed externally -- No rate limiting or security headers - -### Staging/Production - -- Database is only accessible internally -- Nginx provides security headers -- Rate limiting enabled (production) -- SSL support ready - -### Recommendations - -1. Change default database passwords -2. Use Docker secrets for sensitive data in production -3. Configure SSL certificates for production -4. Set up proper backup strategies -5. Monitor resource usage and logs - -## File Structure - -``` -docker/ -├── development/ -│ ├── docker-compose.yml -│ ├── .env -├── staging/ -│ ├── docker-compose.yml -│ ├── nginx.conf -│ └── .env -├── production/ -│ ├── docker-compose.yml -│ ├── nginx.conf -│ └── .env -scripts/ -└── init-db.sql -docker-manage.sh -Dockerfile -.dockerignore -``` diff --git a/DOMAIN_CORE.md b/DOMAIN_CORE.md deleted file mode 100644 index 7fcb711..0000000 --- a/DOMAIN_CORE.md +++ /dev/null @@ -1,234 +0,0 @@ -# Domain Core Architecture - -This project uses a layered architecture. The "domain core" includes the service and repository -layers, and **only the repository implementation layer communicates with the database**. - -## Architecture Flow - -``` -Client Side - ↓ -Server Actions (app/actions/) - ↓ -Service Layer (domain_core/services/) - ↓ -Repository Interface (domain_core/repositories/dc_interface.ts) - ↓ -Repository Implementation (domain_core/repositories/dc_repo.ts) ← ONLY layer that touches DB - ↓ -Prisma Client (domain_core/infrastructure/prisma.ts) - ↓ -PostgreSQL Database -``` - -## Folder Structure - -``` -domain_core/ -├── infrastructure/ # External service clients & utilities -│ ├── prisma.ts # Prisma client singleton -│ ├── run-migrations.ts # Database migration runner -│ └── utils.ts # Utility functions (cn, etc.) -├── model/ # Domain entities & input types -│ └── domain_model.ts # Pure domain interfaces -├── repositories/ # Data access layer -│ ├── dc_interface.ts # Repository contracts -│ └── dc_repo.ts # Prisma implementations -└── services/ # Business logic layer - ├── user.ts - ├── competency.ts - ├── learning_resource.ts - ├── competency_relationship.ts - └── competency_resource_link.ts -``` - -## How It Works - -### 1. Shared Domain Model (`domain_core/model/domain_model.ts`) - -Pure entities and input types. No database dependencies. - -```typescript -export interface Competency { - id: string; - title: string; - description: string | null; - createdAt: Date; -} - -export interface CreateCompetencyInput { - title: string; - description?: string; -} -``` - -### 2. Repository Interface (`domain_core/repositories/dc_interface.ts`) - -Contract definition. No implementation. - -```typescript -export interface CompetencyRepository { - create(data: CreateCompetencyInput): Promise; - findById(id: string): Promise; - findAll(): Promise; -} -``` - -### 3. Repository Implementation (`domain_core/repositories/dc_repo.ts`) - -Prisma implementation. **ONLY this layer touches the database.** - -```typescript -export class PrismaCompetencyRepository implements CompetencyRepository { - async create(data: CreateCompetencyInput): Promise { - return await prisma.competency.create({ data }); - } -} - -export const competencyRepository = new PrismaCompetencyRepository(); -``` - -### 4. Service Layer (`domain_core/services/`) - -Business logic and validation. - -```typescript -export class CompetencyService { - constructor(private readonly repository: CompetencyRepository) {} - - async createCompetency(data: CreateCompetencyInput) { - return await this.repository.create(data); - } -} - -export const competencyService = new CompetencyService(competencyRepository); -``` - -### 5. Server Actions (`app/actions/`) - -Exposes operations to Client Side. - -```typescript -'use server'; - -import { competencyService } from '@/domain_core/services/competency'; - -export async function createCompetencyAction(formData: FormData) { - try { - const title = formData.get('title') as string; - const competency = await competencyService.createCompetency({ title }); - return { success: true, competency }; - } catch (error) { - return { success: false, error: error.message }; - } -} -``` - -## Usage from Client Side - -### Server Components (Default) - -```tsx -import { getAllCompetenciesAction } from '@/app/actions/competencies'; - -export default async function CompetenciesPage() { - const { success, competencies } = await getAllCompetenciesAction(); - - if (!success) return
Error loading competencies
; - - return ( -
- {competencies?.map(comp => ( -
-

{comp.title}

-

{comp.description}

-
- ))} -
- ); -} -``` - -### Client Components - -```tsx -'use client'; - -import { createCompetencyAction } from '@/app/actions/competencies'; -import { useState } from 'react'; - -export default function CreateCompetencyForm() { - const [message, setMessage] = useState(''); - - async function handleSubmit(formData: FormData) { - const result = await createCompetencyAction(formData); - setMessage(result.success ? 'Created!' : result.error); - } - - return ( -
- -