README.md
Rama dev · réplica de lectura del repositorio original.
# Personal Developer Analytics
<!-- CI / build -->


<!-- Backend stack -->




<!-- Frontend stack -->




<!-- AI / infra -->


<!-- Repo activity -->



Master's thesis project — a self-hosted platform that aggregates developer productivity
metrics from local Git repositories, GitHub, and Jira, and surfaces them through
a React dashboard with AI-generated insights via local Ollama.
## Architecture
| Layer | Technology |
|-------|-----------|
| Backend API | Spring Boot 3.5, Java 17, JWT auth |
| Database | PostgreSQL 16, Flyway migrations |
| Frontend SPA | React 19, TypeScript, Vite, Tailwind CSS 4, Recharts |
| AI insights | Ollama (llama3.2) — runs locally, no cloud dependency |
| Mail (dev/Docker) | MailHog — local SMTP capture, web UI on port 8025 |
| Deployment | Docker Compose (app + Postgres + Ollama + MailHog) |
## Prerequisites
- Java 17+
- Node 20+
- PostgreSQL 16 (or Docker)
- [Ollama](https://ollama.com) — for AI features
- `openssl` — for generating secrets
- Docker + Docker Compose — for one-command deployment
## Environment Variables
| Variable | Purpose | Default | How to generate |
|----------|---------|---------|----------------|
| `JWT_SECRET` | JWT signing key | none — **startup fails** if unset | `openssl rand -hex 32` |
| `ENCRYPTION_KEY` | AES-256-GCM token encryption key (base64) | none — **startup fails** if unset | `openssl rand -base64 32` |
| `POSTGRES_PASSWORD` | Database password | none — Compose requires it | choose one |
| `SMTP_HOST` | SMTP server for password-reset emails | `mailhog` (Docker) / `smtp.gmail.com` (manual) | — |
| `SMTP_PORT` | SMTP port | `1025` (Docker) / `587` (manual) | — |
| `SMTP_USERNAME` | SMTP sender address (not needed with MailHog) | — | your email |
| `SMTP_PASSWORD` | SMTP app password (not needed with MailHog) | — | your app password |
| `OLLAMA_BASE_URL` | Ollama server URL | `http://localhost:11434` | — |
| `OLLAMA_MODEL` | LLM model name | `llama3.2` | — |
| `APP_BASE_URL` | Base URL used in password-reset email links | `http://localhost:8080` | — |
| `APP_FRONTEND_URL` | SPA origin the reset links point at | `http://localhost:5173` | — |
| `COOKIE_SECURE` | Set `true` in production (HTTPS only) | `false` | — |
> `JWT_SECRET` and `ENCRYPTION_KEY` have no defaults. Unset, the application fails to
> start: `JWT_SECRET` shorter than 32 bytes raises `WeakKeyException`, and an empty
> `ENCRYPTION_KEY` raises `IllegalArgumentException: Empty key`. Both are thrown during
> bean creation, so the stack trace names the bean rather than the variable.
>
> In production, always set `JWT_SECRET`, `ENCRYPTION_KEY`, and `POSTGRES_PASSWORD`
> via environment variables or a secrets manager. Never commit real secrets.
### Email in Docker mode
The Docker Compose stack includes a **MailHog** service, so password-reset and
other outgoing emails work out of the box with **no external mail account**.
`SMTP_HOST` defaults to `mailhog` and `SMTP_PORT` to `1025`; captured messages
are viewable in the MailHog web UI at **http://localhost:8025**.
To send real email instead (e.g. in manual dev mode without Docker), override
`SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, and `SMTP_PASSWORD` — for example with
a Gmail app password (`smtp.gmail.com`, port `587`).
## Running Locally (Dev Mode)
```bash
# 1. Start Postgres
cd dev-analytics && docker compose up -d db
# 2. Start Ollama (separate terminal)
ollama serve
# First time only — downloads ~2 GB:
ollama pull llama3.2
# 3. Start the backend http://localhost:8080
cd dev-analytics
./mvnw spring-boot:run
# 4. Start the frontend dev server http://localhost:5173
cd dev-analytics/frontend
npm install
npm run dev
```
The frontend dev server proxies `/api` requests to `localhost:8080`.
> In this manual dev mode Postgres runs in Docker but Ollama and mail do not.
> Configure `SMTP_*` for a real mail server if you need password-reset emails,
> or run the full Docker stack below to get MailHog automatically.
## One-Command Deployment (Docker Compose)
```bash
# 1. Copy and fill in secrets
cd dev-analytics
cp .env.example .env
# Edit .env — set JWT_SECRET, ENCRYPTION_KEY, POSTGRES_PASSWORD
# 2. Start the full stack
docker compose up -d
```
The app is available at **http://localhost:8080**.
Captured emails are viewable in MailHog at **http://localhost:8025**.
The `ollama` service in `docker-compose.yml` is pinned to a specific image tag (not `latest`),
matching the version each generated summary records in its `runtime_version` field. Bump the
tag deliberately when you need a newer Ollama build.
First boot pulls the llama3.2 model (~2 GB) — allow a few minutes before the AI features work.
### Analysing local Git repositories
A `GIT_LOCAL` data source is a filesystem path that JGit opens, so the path has to exist
**inside the app container**. Compose bind-mounts `LOCAL_REPOS_PATH` (default `./repos`)
read-only at `/repos`, so put the working copies there and register each repository under
its container path:
```bash
# in dev-analytics/.env
LOCAL_REPOS_PATH=/home/you/code
```
A repository at `/home/you/code/my-project` is then registered as `/repos/my-project`.
The mount is read-only: the platform reads commit history and never writes to a repository.
Running the backend outside Docker needs none of this — the host path is registered directly.
## Building the Fat JAR
Maven does **not** build the frontend — there is no `frontend-maven-plugin`.
`src/main/resources/static/` is a committed build artifact, and `./mvnw package`
packages whatever that directory already holds. Any change under `frontend/src/`
needs `npm run build` first, and the rebuilt bundle belongs in the same commit.
```bash
cd dev-analytics/frontend
npm run build # emits into ../src/main/resources/static/
cd ..
./mvnw clean package # packages the static/ directory as it stands
java -jar target/dev-analytics-*.jar
```
## Running Tests
```bash
# Backend unit + integration tests
cd dev-analytics && ./mvnw test
# Frontend tests
cd dev-analytics/frontend && npm run test:run
# Lint
cd dev-analytics/frontend && npm run lint
```
## Demo Mode
Start with a pre-seeded dashboard — no real data source needed:
```bash
cd dev-analytics
./mvnw spring-boot:run -Dspring-boot.run.profiles=demo
```
**Login:** `demo@demo.com` / `demo`
On first boot the seeder creates 12 weeks of realistic metrics. Subsequent boots skip seeding (idempotent).