Skip to content

Latest commit

Β 

History

68 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lobos

A vocabulary and grammar management application built with Spring Boot. Lobos provides both a RESTful JSON API and a Thymeleaf-based web interface for organizing vocabulary collections and grammar notes.


Features

  • πŸ“š Collections β€” Group vocabulary entries into named, color-coded collections
  • πŸ“ Grammar Notes β€” Store words with their meanings, examples, and star/favorite them
  • πŸ” Authentication β€” Register, log in, update your profile, and log out securely
  • πŸͺ Remember Me β€” Optional persistent login (JDBC-backed, 30-day rotating token) so the web session survives a closed browser
  • 🌐 Web UI β€” Full-featured browser interface built with Thymeleaf and Tailwind CSS
  • πŸ”Œ REST API β€” Stateless JSON API secured with JWT bearer tokens
  • πŸ€– MCP Server β€” Remote MCP server (Streamable HTTP) exposing collections and grammars as tools for AI clients, secured with scoped MCP tokens
  • πŸ“„ Pagination β€” Navigate large lists with built-in pagination

Tech Stack

Layer Technology
Language Java 21
Framework Spring Boot 4.1.0
Web / MVC Spring Web MVC, Thymeleaf
Security Spring Security (JWT for API, session for Web)
Database MySQL
Persistence Spring JDBC (JdbcTemplate) β€” raw SQL, no ORM
Build Tool Maven (./mvnw)
Frontend CSS Tailwind CSS via CDN
Password jBCrypt
JWT JJWT 0.12.6
MCP Server Spring AI MCP Server (WebMVC, Streamable HTTP)

Project Structure

src/main/java/id/my/tudemaha/lobos/
β”œβ”€β”€ config/             # Security & application configuration
β”œβ”€β”€ controller/
β”‚   β”œβ”€β”€ api/            # REST controllers (@RestController, /api prefix)
β”‚   β”œβ”€β”€ web/            # MVC controllers (@Controller, Thymeleaf views)
β”‚   └── mcp/            # MCP tools (@McpTool components exposed over the MCP server)
β”œβ”€β”€ dto/
β”‚   β”œβ”€β”€ request/        # Incoming request DTOs
β”‚   └── response/       # Outgoing response DTOs
β”œβ”€β”€ exception/          # Custom exceptions & GlobalExceptionHandler
β”œβ”€β”€ mapper/             # Entity ↔ DTO mappers
β”œβ”€β”€ model/              # Domain models (User, Collection, Grammar, McpToken)
β”œβ”€β”€ repository/         # Data access via JdbcTemplate
β”œβ”€β”€ security/           # JWT/MCP filters, remember-me (JdbcPersistentTokenRepository, AppUserDetailsService) & token services
β”œβ”€β”€ service/            # Business logic
└── utils/              # Pagination, PasswordHasher

src/main/resources/
β”œβ”€β”€ application.properties   # App configuration (DB, JWT secret, MCP server)
β”œβ”€β”€ schema.sql               # MySQL DDL
β”œβ”€β”€ static/
β”‚   β”œβ”€β”€ css/main.css         # Global styles
β”‚   β”œβ”€β”€ fonts/               # Custom fonts (vimala.ttf)
β”‚   β”œβ”€β”€ js/                  # Vanilla JS per-page scripts (incl. mcp.js)
β”‚   └── index.html           # Static landing page
└── templates/               # Thymeleaf HTML templates
    β”œβ”€β”€ layout.html           # Shared base layout
    β”œβ”€β”€ auth/                 # login.html, register.html, profile.html
    β”œβ”€β”€ mcp/                   # index.html (MCP token management)
    β”œβ”€β”€ collections/          # index.html
    └── grammars/             # index.html, detail.html

Database Schema

users              (id, first_name, last_name, email, password, created_at, updated_at)
persistent_logins  (series, user_id, token, last_used)
mcp_tokens         (id, user_id β†’ users.id, name, token, created_at, last_used_at)
collections        (id, name, color, user_id β†’ users.id, created_at, updated_at)
grammars           (id, word, meaning, example, is_starred, collection_id β†’ collections.id, created_at, updated_at)

Primary keys are VARCHAR(36) UUIDs, auto-generated by MySQL (DEFAULT (UUID())). persistent_logins is keyed by series instead (remember-me tokens), with user_id referencing the immutable users.id.


Getting Started

Prerequisites

  • Java 21+
  • MySQL database
  • Maven (or use the included ./mvnw wrapper)

1. Clone the repository

git clone <repository-url>
cd lobos

2. Set up the database

Create a MySQL database and run the schema:

mysql -u <user> -p <database_name> < src/main/resources/schema.sql

3. Configure the application

Edit src/main/resources/application.properties:

spring.ai.mcp.server.name=lobos-mcp-server
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.protocol=streamable

spring.datasource.url=jdbc:mysql://<host>:<port>/<database>
spring.datasource.username=<db_user>
spring.datasource.password=<db_password>

jwt.secret=<your_strong_secret_key>
app.remember-me.key=<your_strong_secret_key>

⚠️ Never commit application.properties with real credentials to version control.

4. Run the application

./mvnw spring-boot:run

The application starts at http://localhost:8080.


Docker

Run with Docker Compose (prebuilt image)

The prebuilt image is published to GitHub Container Registry at ghcr.io/tudemaha/lobos:latest. Fill in your database and JWT values in docker-compose.yml, then start it:

services:
  lobos:
    restart: on-failure
    image: ghcr.io/tudemaha/lobos:latest
    environment:
      - DB_URL=jdbc:mysql://<host>:<port>/<database>
      - DB_USERNAME=<username>
      - DB_PASSWORD=<password>
      - JWT_SECRET=<secret>
      - REMEMBER_ME_KEY=<key>
    ports:
      - 127.0.0.1:8080:8080
docker compose up -d

The app will be available at http://localhost:8080.

Build the image locally

docker build -t lobos .

Run the image directly

docker run -d \
  -p 8080:8080 \
  -e DB_URL=jdbc:mysql://<host>:<port>/<database> \
  -e DB_USERNAME=<username> \
  -e DB_PASSWORD=<password> \
  -e JWT_SECRET=<secret> \
  -e REMEMBER_ME_KEY=<key> \
  lobos

⚠️ Never commit real database credentials, JWT secrets, or the remember-me key into docker-compose.yml or version control.


Usage

Web Interface

Route Description
/ Landing page
/login Log in to your account
/register Create a new account
/profile View and update your profile
/collections Manage your vocabulary collections
/grammars Browse and manage grammar notes
/grammars/{id} View grammar note detail
/tokens Manage MCP tokens

REST API

All API endpoints are prefixed with /api and require a Bearer <token> JWT header (except auth endpoints).

Method Endpoint Description
POST /api/auth/register Register a new user
POST /api/auth/login Log in and receive a JWT
GET /api/collections List user's collections
POST /api/collections Create a new collection
PUT /api/collections/{id} Update a collection
DELETE /api/collections/{id} Delete a collection
GET /api/collections/{collectionId}/grammars List grammar notes in a collection
POST /api/collections/{collectionId}/grammars Create a grammar note
GET /api/collections/{collectionId}/grammars/{grammarId} Get a single grammar note
PUT /api/collections/{collectionId}/grammars/{grammarId} Update a grammar note
PATCH /api/collections/{collectionId}/grammars/{grammarId} Toggle star on a grammar note
DELETE /api/collections/{collectionId}/grammars/{grammarId} Delete a grammar note
POST /api/tokens Generate a new MCP token
GET /api/tokens List user's MCP tokens
PATCH /api/tokens/{id} Rename an MCP token
DELETE /api/tokens/{id} Revoke an MCP token

MCP Server

Lobos embeds a remote MCP server (Streamable HTTP) at /mcp, letting AI clients (Claude Desktop, Claude Code, etc.) read and write a user's collections and grammars directly. It's authenticated with a dedicated MCP token β€” generated from the /tokens page β€” instead of the login JWT, so a leaked token can't be used to change account credentials.

claude mcp add --transport http lobos http://localhost:8080/mcp -H "Authorization: Bearer <mcp_token>"
Tool Description
list_collections List the authenticated user's collections
create_collection Create a new collection
update_collection Update a collection's name and color
delete_collection Delete a collection
list_grammars List grammars within a collection
get_grammar Get a single grammar's detail
create_grammar Create a grammar note inside a collection
update_grammar Update a grammar note
toggle_star_grammar Toggle star/favorite on a grammar note
delete_grammar Delete a grammar note

Development

Common Commands

# Compile
./mvnw compile

# Run tests
./mvnw test

# Package as JAR
./mvnw clean package

# Run with Spring Boot dev tools (live reload)
./mvnw spring-boot:run

Security Notes

  • REST API (/api/**) uses stateless JWT authentication via JwtAuthFilter.
  • MCP server (/mcp/**) uses stateless MCP tokens (McpAuthFilter), separate from the login JWT and scoped to collections/grammars only.
  • Web UI uses session-based Spring Security authentication, with an optional remember-me persistent login (JDBC-backed rotating token, 30-day validity) when the "Keep me signed in" checkbox is used at login. Tokens are keyed off the immutable users.id and are invalidated on password change or account deletion.
  • All POST forms include a CSRF token for protection.
  • Passwords are hashed with jBCrypt.
  • Unauthenticated users are redirected to /login.

License

This project is licensed under the Apache License 2.0.

About

Save your new grammars easily. Find it easily, like a lobo!

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages