# khalidelokiely/squash-it architecture

> Architecture diagram of the GitHub repository khalidelokiely/squash-it, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-12). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/khalidelokiely/squash-it
- Repository: https://github.com/khalidelokiely/squash-it

## Overview

#### Purpose and Startup
Squash It is a Go URL-shortening service: it creates short hash tokens for long URLs, resolves tokens to destinations, and redirects visit requests while tracking clicks. `main.go` is the process entry point; dependency construction is centralized in `internal/app/provide.go`. Runtime configuration is loaded from `internal/config/config.go`.

#### HTTP Edge and Routing
A custom router wraps `net/http`, providing route groups, handler adaptation, options, and serving behavior. Application routes connect HTTP endpoints to handlers; middleware applies cross-cutting controls such as client-based throttling.
- `internal/router/router.go`
- `internal/router/serve.go`
- `internal/app/routes.go`
- `internal/app/middleware.go`
- `internal/app/handlers.go`

#### Application Layer
The app layer owns request/response models and orchestrates encode, decode, and redirect use cases. Handlers parse HTTP DTOs and invoke the service; the service coordinates hashing, Bloom checks, repository persistence, caches, and redirect/click behavior without embedding transport concerns.
- `internal/app/model.go`
- `internal/app/service.go`
- `internal/app/handlers.go`

#### Persistence and URL Identity
SQLite is the source of truth for URL mappings and click counts. The repository abstracts database operations, including lookup and idempotent find-or-create behavior needed when concurrent or repeated encode requests target an existing long URL. Short tokens are generated with seeded Murmur hashing and retried on collisions.
- `internal/db/db.go`
- `internal/app/repository.go`
- `internal/hash/hash.go`

#### Encode Control Flow
`/encode` is rate-limited, then the service generates an 8-character candidate token. A Bloom negative permits an idempotent repository insert; a “maybe present” result triggers DB verification. Matching long URLs reuse their mapping; token collisions retry with another hash seed until success or retry exhaustion. Successful mappings update the Bloom filter.
- `internal/app/service.go`
- `internal/filter/filter.go`
- `internal/filter/bloom.go`
- `internal/rate/user_token_bucket.go`

#### Decode and Redirect Read Path
Decode first consults the Bloom filter to reject definite misses cheaply. Possible matches follow an L1/L2 cache pipeline, then SQLite on cache miss. DB hits repopulate cache and Bloom. The visit route follows this resolution path, increments the persisted click count, and returns a `302 Found` redirect.
- `internal/app/service.go`
- `internal/cache/pipeline.go`
- `internal/cache/lru.go`
- `internal/app/repository.go`

#### State Acceleration and Runtime Infrastructure
The cache pipeline uses in-process LRU as L1 and optional Redis as L2; Redis failure degrades safely to local caching. The Bloom filter is persisted/reconstructed asynchronously and backed up on an interval, guarding DB/cache traffic but allowing false positives. Docker Compose provisions Redis alongside the service; SQLite requires no network dependency.
- `internal/cache/redis.go`
- `internal/cache/provide.go`
- `internal/filter/persistent_bloom.go`
- `docker-compose.yml`
- `Dockerfile`

Main entry points: [`internal/app/service.go`](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/service.go) (URL service), [`internal/app/routes.go`](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/routes.go) (Application routes), [`internal/app/provide.go`](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/provide.go) (Dependency wiring), [`main.go`](https://github.com/khalidelokiely/squash-it/blob/main/main.go) (Process entry)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_edge["HTTP Edge"]
  node_router["Custom router<br/>HTTP router<br/>[router.go]"]
  node_routes["Application routes<br/>route registration<br/>[routes.go]"]
  node_throttling["Client throttling<br/>HTTP middleware<br/>[middleware.go]"]
  node_handlers["HTTP handlers<br/>transport adapter<br/>[handlers.go]"]
end

subgraph group_app["Application"]
  node_composition["Dependency wiring<br/>composition root<br/>[provide.go]"]
  node_service["URL service<br/>application service<br/>[service.go]"]
  node_hashing["Token hashing<br/>Murmur token generator<br/>[hash.go]"]
end

subgraph group_state["State &amp; Acceleration"]
  node_repository["URL repository<br/>persistence adapter<br/>[repository.go]"]
  node_sqlite[("SQLite<br/>source-of-truth database<br/>[db.go]")]
  node_bloom["Persistent Bloom filter<br/>probabilistic index"]
  node_cache["L1/L2 cache pipeline<br/>[pipeline.go]"]
  node_redis[("Redis L2<br/>optional cache<br/>[redis.go]")]
end

subgraph group_runtime["Runtime"]
  node_main["Process entry<br/>Go entrypoint<br/>[main.go]"]
  node_config["Runtime config<br/>configuration<br/>[config.go]"]
  node_compose["Docker Compose<br/>deployment definition<br/>[docker-compose.yml]"]
  node_container["Service image<br/>container build"]
end

node_main -->|"loads"| node_config
node_main -->|"starts"| node_composition
node_composition -->|"assembles"| node_router
node_composition -->|"injects dependencies"| node_service
node_router -->|"serves"| node_routes
node_routes -->|"protects /encode"| node_throttling
node_routes -->|"dispatches"| node_handlers
node_handlers -->|"invokes use cases"| node_service
node_service -->|"generates candidates"| node_hashing
node_service -->|"checks and updates"| node_bloom
node_service -->|"reads and repopulates"| node_cache
node_service -->|"finds, creates, counts clicks"| node_repository
node_repository -->|"persists mappings and clicks"| node_sqlite
node_cache -.->|"optional L2"| node_redis
node_compose -->|"provisions"| node_redis
node_container -->|"packages service"| node_main

click node_main "https://github.com/khalidelokiely/squash-it/blob/main/main.go"
click node_config "https://github.com/khalidelokiely/squash-it/blob/main/internal/config/config.go"
click node_composition "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/provide.go"
click node_router "https://github.com/khalidelokiely/squash-it/blob/main/internal/router/router.go"
click node_routes "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/routes.go"
click node_throttling "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/middleware.go"
click node_handlers "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/handlers.go"
click node_service "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/service.go"
click node_hashing "https://github.com/khalidelokiely/squash-it/blob/main/internal/hash/hash.go"
click node_repository "https://github.com/khalidelokiely/squash-it/blob/main/internal/app/repository.go"
click node_sqlite "https://github.com/khalidelokiely/squash-it/blob/main/internal/db/db.go"
click node_bloom "https://github.com/khalidelokiely/squash-it/blob/main/internal/filter/persistent_bloom.go"
click node_cache "https://github.com/khalidelokiely/squash-it/blob/main/internal/cache/pipeline.go"
click node_redis "https://github.com/khalidelokiely/squash-it/blob/main/internal/cache/redis.go"
click node_compose "https://github.com/khalidelokiely/squash-it/blob/main/docker-compose.yml"
click node_container "https://github.com/khalidelokiely/squash-it/blob/main/Dockerfile"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_router,node_routes,node_throttling,node_handlers toneBlue
class node_composition,node_service,node_hashing toneAmber
class node_repository,node_sqlite,node_bloom,node_cache,node_redis toneMint
class node_main,node_config,node_compose,node_container toneRose
```

## Components

### HTTP Edge

- [Custom router](https://github.com/khalidelokiely/squash-it/blob/main/internal/router/router.go): HTTP router · Wraps net/http route grouping and serving. · `internal/router/router.go`
- [Application routes](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/routes.go): route registration · `internal/app/routes.go`
- [Client throttling](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/middleware.go): HTTP middleware · Rate-limits encode requests. · `internal/app/middleware.go`
- [HTTP handlers](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/handlers.go): transport adapter · `internal/app/handlers.go`

### Application

- [Dependency wiring](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/provide.go): composition root · `internal/app/provide.go`
- [URL service](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/service.go): application service · Orchestrates encode, decode, and redirect behavior. · `internal/app/service.go`
- [Token hashing](https://github.com/khalidelokiely/squash-it/blob/main/internal/hash/hash.go): Murmur token generator · Generates seeded candidates and supports collision retries. · `internal/hash/hash.go`

### State & Acceleration

- [URL repository](https://github.com/khalidelokiely/squash-it/blob/main/internal/app/repository.go): persistence adapter · Provides lookup, idempotent mapping creation, and click updates. · `internal/app/repository.go`
- [SQLite](https://github.com/khalidelokiely/squash-it/blob/main/internal/db/db.go): source-of-truth database · Stores URL mappings and click counts. · `internal/db/db.go`
- [Persistent Bloom filter](https://github.com/khalidelokiely/squash-it/blob/main/internal/filter/persistent_bloom.go): probabilistic index · Rejects definite misses and is asynchronously persisted/backed up. · `internal/filter/persistent_bloom.go`
- [L1/L2 cache pipeline](https://github.com/khalidelokiely/squash-it/blob/main/internal/cache/pipeline.go): cache pipeline · Uses local LRU and optional Redis with safe degradation. · `internal/cache/pipeline.go`
- [Redis L2](https://github.com/khalidelokiely/squash-it/blob/main/internal/cache/redis.go): optional cache · `internal/cache/redis.go`

### Runtime

- [Process entry](https://github.com/khalidelokiely/squash-it/blob/main/main.go): Go entrypoint · `main.go`
- [Runtime config](https://github.com/khalidelokiely/squash-it/blob/main/internal/config/config.go): configuration · `internal/config/config.go`
- [Docker Compose](https://github.com/khalidelokiely/squash-it/blob/main/docker-compose.yml): deployment definition · Provisions the service with Redis. · `docker-compose.yml`
- [Service image](https://github.com/khalidelokiely/squash-it/blob/main/Dockerfile): container build · `Dockerfile`

## Connections

- Process entry → Runtime config: loads
- Process entry → Dependency wiring: starts
- Dependency wiring → Custom router: assembles
- Dependency wiring → URL service: injects dependencies
- Custom router → Application routes: serves
- Application routes → Client throttling: protects /encode
- Application routes → HTTP handlers: dispatches
- HTTP handlers → URL service: invokes use cases
- URL service → Token hashing: generates candidates
- URL service → Persistent Bloom filter: checks and updates
- URL service → L1/L2 cache pipeline: reads and repopulates
- URL service → URL repository: finds, creates, counts clicks
- URL repository → SQLite: persists mappings and clicks
- L1/L2 cache pipeline → Redis L2: optional L2
- Docker Compose → Redis L2: provisions
- Service image → Process entry: packages service
