Architecture
The URL Shortener is a 6-module Maven reactor (plus root) built on plain Java with zero external framework dependencies. Each module has a single, well-defined responsibility.
graph TB
Browser["🌐 Browser / Client"]
Agent["🤖 AI Agent"]
UI["urlshortener-ui\nVaadin WAR\n:8080"]
Server["urlshortener-server\nREST Admin API\n:9090"]
Redirect["Redirect Server\n:8081"]
MCP["urlshortener-mcp\nMCP Server\n:9091"]
Core["urlshortener-core\nDomain Model"]
Client["urlshortener-client\nJava HTTP Client"]
Store["Storage Layer\nIn-Memory / EclipseStore"]
Browser -->|"Short link GET /{code}"| Redirect
Browser -->|"Manage links"| UI
Agent -->|"JSON-RPC 2.0 POST /mcp"| MCP
UI -->|"HTTP REST"| Client
MCP -->|"HTTP REST"| Client
Client -->|"HTTP/JSON"| Server
Server --> Core
Server --> Store
Redirect --> Store
Modules
Six modules with explicit boundaries — the shared domain model, the server runtime, a Java client, the Vaadin UI, a CLI and the MCP server.
urlshortener-core
The shared domain model — entities, Base62 encoder, alias policy, URL validator and statistics models. No dependencies on the other modules.
urlshortener-server
The runtime process: two HttpServer instances — Admin API on :9090 and redirects on :8081 — with storage injected via interface.
urlshortener-client
A pure-Java HTTP client for the Admin API, used by the UI and useful for scripting or CI pipelines.
urlshortener-ui
A Vaadin web application packaged as a WAR for Jetty 12 — create, overview, statistics and profile views.
urlshortener-cli
A command-line interface for scripting and CI pipelines, delegating to the client SDK.
urlshortener-mcp
A Model Context Protocol server over JSON-RPC 2.0 on :9091 — agent tools with X-API-Key pass-through, so jCustos stays the single authorization point.
urlshortener-core
The shared domain model. Has no dependencies on the other modules.
ShortUrlMapping— the central entity (shortCode, originalUrl, active, expiresAt)Base62Encoder— generates short codes from a 62-character alphabetAliasPolicy— validates custom aliases (3–32 chars,[A-Za-z0-9_-])UrlValidator— rejects malformed or unsafe URLsRedirectEvent,HourlyAggregate,DailyAggregate— statistics models
urlshortener-server
The runtime process. Starts two com.sun.net.httpserver.HttpServer instances.
| Instance | Port | Handler |
|---|---|---|
| Admin API | 9090 | AdminApiHandler — full CRUD + import/export |
| Redirect | 8081 | RedirectHandler — resolves short codes, records events |
Storage is injected via interface:
UrlMappingStore ──→ InMemoryUrlMappingStore
└─→ EclipseStoreUrlMappingStoreurlshortener-client
A pure-Java HTTP client for the Admin API. Used by the UI and useful for scripting or CI pipelines.
Key classes: URLShortenerClient, StatisticsClient, AdminClient, ColumnVisibilityClient
urlshortener-ui
A Vaadin web application packaged as a WAR for Jetty 12.
Views:
| View | Path | Description |
|---|---|---|
| CreateView | /create | Form to create/edit short links |
| OverviewView | /overview | Grid with all mappings, filters, pagination |
| StatisticsView | /statistics | Hourly/daily charts |
| StatisticsDetailView | /statistics/{code} | Per-link deep dive |
| ProfileView | /profile | API key self-service (create, list, revoke) |
| AboutView | /about | Project info |
urlshortener-cli
A command-line interface for scripting and CI pipelines, delegating to the client SDK.
urlshortener-mcp
A Model Context Protocol server exposing the shortener as agent tools over JSON-RPC 2.0 (POST /mcp). Delegates to the client SDK; every call carries the caller’s X-API-Key so jCustos remains the single authorization point. Ships as a runnable fat-jar; bind host and port are configurable (-Dmcp.host / -Dmcp.port).
| Tool group | Tools |
|---|---|
| Links | create_short_link, resolve_shortcode, edit_link, toggle_active, delete_link, list_links, bulk_create_links, bulk_validate, export_links, import_links_validate, import_links_apply |
| Statistics | get_statistics, get_statistics_daily, get_statistics_hourly, get_statistics_timeline, get_statistics_config, set_statistics_enabled, update_statistics_config, export_statistics, import_statistics |
Data Flow: Creating a Short Link
sequenceDiagram
actor User
participant UI as Vaadin UI
participant Client as URLShortenerClient
participant Server as Admin API :9090
participant Core as Core (AliasPolicy)
participant Store as Storage
User->>UI: Fill form, click "Shorten"
UI->>Client: createShortUrl(originalUrl, alias)
Client->>Server: POST /api/shorten (JSON)
Server->>Core: validate alias + URL
Core-->>Server: OK / ValidationError
Server->>Store: save(ShortUrlMapping)
Store-->>Server: stored
Server-->>Client: 201 Created + ShortUrlMapping
Client-->>UI: ShortUrlMapping
UI-->>User: Display short link
Data Flow: Redirect
sequenceDiagram
actor Visitor
participant Redirect as Redirect Server :8081
participant Store as Storage
participant Stats as StatisticsStore
Visitor->>Redirect: GET /oss-project
Redirect->>Store: lookup("oss-project")
Store-->>Redirect: ShortUrlMapping
Redirect->>Stats: record(RedirectEvent)
Redirect-->>Visitor: 302 → originalUrl
Storage Architecture
flowchart TB
UrlMappingStore["UrlMappingStore<br/><small>interface</small><br/>save(mapping)<br/>findByCode(code)<br/>findAll()<br/>delete(code)"]
StatisticsStore["StatisticsStore<br/><small>interface</small><br/>record(event)<br/>getHourly(code)<br/>getDaily(code)"]
InMemoryStore["InMemoryUrlMappingStore<br/><small>ConcurrentHashMap data</small>"]
EclipseStore["EclipseStoreUrlMappingStore<br/><small>EmbeddedStorageManager manager<br/>DataRoot root</small>"]
StatisticsImpl["StatisticsStore implementation<br/><small>redirect events and aggregates</small>"]
UrlMappingStore -. implemented by .-> InMemoryStore
UrlMappingStore -. implemented by .-> EclipseStore
StatisticsStore -. implemented by .-> StatisticsImpl
InMemoryStore -->|"development mode"| Runtime["Server runtime"]
EclipseStore -->|"persistent mode"| Runtime
StatisticsImpl --> Runtime
Design Decisions
| Decision | Choice | Reason |
|---|---|---|
| HTTP server | JDK HttpServer | Zero dependencies, educational clarity |
| Serialization | Jackson 3 | Industry standard, lightweight |
| Persistence | EclipseStore | Pure-Java, no SQL schema migration |
| UI | Vaadin | Server-side Java, no manual JS |
| Build | Maven multi-module | Standard Java tooling |
| Short codes | Base62 | URL-safe, compact, well-understood |