Project Overview
What pakAG is
pakAG is a delivery operations platform for small-to-medium logistics operations. It centralizes the full lifecycle of a package — from creation to doorstep delivery — for an organization that manages its own fleet of distributors.
The system is composed of three parts:
- An internal web application (
frontend-app) used by admins and distributors to manage packages, plan routes, and report delivery outcomes. - A REST API backend (
backend-js) that enforces all business rules, persists data, and dispatches email notifications. - A public tracking endpoint that allows package recipients to check their delivery status without logging in.
[!NOTE] The project was developed as part of a competition (“erronka”) — hence the repository name
erronka2025_js. The product name in business logic and documentation is pakAG.
Problem it solves
Before pakAG, logistics operations managed package assignments, delivery sequences, and status updates through spreadsheets or disconnected tools. pakAG replaces that with:
- Centralized package records — every package has a lifecycle:
pending → assigned → in_transit → delivered / undelivered / failed - Route optimization — admins assign packages to a distributor for a given day, and the system calls the Google Directions API to compute the optimal stop order
- Real-time status visibility — every state transition is logged, and recipients receive automatic email notifications at key milestones
- Public tracking — recipients get a unique tracking URL when their package is created; no account required
Business domain
Entities
| Entity | Description |
|---|---|
| User | System user with role admin or distributor; is_active flag controls login access |
| Package | A physical parcel with a recipient, an address, and a current status |
| Address | Geocoded delivery address — stored with latitude/longitude for route optimization |
| Route | A day’s delivery plan for one distributor — contains an ordered list of stops |
| Stop | A single delivery stop on a route — links a route to a package, holds order and estimated arrival |
| PackageStatusLog | Immutable audit trail — every status change records timestamp, new status, and optionally a note |
| Token | Opaque hex tokens for: refresh_token, tracking_token, reset_pwd_token, activate_account_token |
Package status machine
┌──────────┐
│ pending │ ← package created by admin
└────┬─────┘
│ admin assigns to route
▼
┌──────────┐
│ assigned │
└────┬─────┘
│ distributor starts route
▼
┌────────────┐
│ in_transit │
└──┬──┬──┬──┘
│ │ │
─────────────┘ │ └─────────────────
│ │ │
▼ ▼ ▼
┌───────────┐ ┌─────────────┐ ┌──────────────┐
│ delivered │ │ undelivered │ │ failed │
└───────────┘ └─────────────┘ └──────────────┘
(success) (nobody home, (refused,
try again) lost, etc.)Each transition triggers a side effect: an entry in package_status_logs and an email to the recipient.
Route lifecycle
- Admin creates a route: selects a distributor user and a date, picks the packages to include (max 20 stops).
- The backend fetches any carryover packages — packages assigned to that distributor from previous days still in
assignedstatus — and prepends them to the stop list. - The Google Directions API is called with
optimize:trueto compute the optimal waypoint order. - Estimated arrival times are calculated per stop and stored in the database.
- The distributor sees their daily route in the frontend, starts it, arrives at each stop, and marks packages as delivered / undelivered / failed.
- At end of day, any undelivered stops are eligible to carry over to the next route.
Users and roles
Admin
Admins manage the full operational scope. They:
- Create and manage user accounts (admins and distributors)
- Create, update, and delete packages
- Assign packages to routes
- View all package and route history
- Access system-wide logs and daily delivery summaries
Admins access the internal dashboard in frontend-app.
Distributor
Distributors execute the daily delivery work. They:
- View their assigned route for the day
- Progress through stops in the optimized order
- Mark packages as delivered, undelivered, or failed at each stop
- Record actual arrival time at each stop
- Can continue a previous day’s pending route if undelivered stops were carried over
Distributors access the same internal app as admins but see a different, role-scoped view.
Recipient (package recipient)
Recipients are not system users — they have no account and no login. They interact with pakAG only through:
- Email notifications at each status transition (assigned, in_transit, delivered/failed)
- The public tracking page — a URL containing a one-time tracking token that shows the current package status and history
The tracking token is created when the package is created and expires after a configurable number of days (default: 30).
Key workflows
Creating a package (admin)
- Admin submits: recipient name, email, delivery address, package description
- Backend geocodes the address via Google Geocoding API → stores
lat/lng - Backend generates a tracking token and stores it in the
tokenstable - Backend sends a “package created” notification email to the recipient with the tracking URL
- Package is in
pendingstatus until assigned to a route
Activating a new user account
- Admin creates a user via
POST /api/users/create - Backend stores the user with
is_active=falseand a hashed default password - Backend generates an
activate_account_tokenand sends an activation email - User clicks the link and POSTs to
/api/auth/activateAccount?token=<token>with their chosen password - Backend verifies the token, hashes the password, sets
is_active=true, revokes the token
Password reset
- User visits “forgot password” and submits their email
- Backend responds with a generic message (does not reveal whether the email exists)
- If the email matches a user, a
reset_pwd_tokenis generated and an email is sent - User clicks the link and POSTs to
/api/auth/changePwd?token=<token>with a new password - Backend verifies, changes the password, revokes the token
Technical stack summary
| Layer | Technology | Version |
|---|---|---|
| API runtime | Next.js Route Handlers | 16.2.4 |
| Language | TypeScript | 5.x |
| Database | MySQL | 8.x |
| DB client | mysql2 | 3.22.0 |
| Auth | JWT (HS256) + bcrypt | jsonwebtoken 9.0.2 / bcrypt 6.0.0 |
| Resend | 6.12.2 | |
| Maps | Google Directions + Geocoding API | — |
| Frontend framework | Next.js App Router | 16.2.4 |
| Styling | Tailwind CSS | 4.x |
| Data fetching (frontend) | TanStack React Query + Axios | 5.x / 1.x |
| Monorepo | pnpm workspaces | 10.20.0 |
| Documentation | Nextra | 4.6.1 |
What pakAG is NOT
- Not a public SaaS product — it is designed for a single organization with internal users
- Not a mobile app — the frontend is a web application (though responsive)
- Not a warehouse management system — it handles packages after they leave the warehouse
- Not a real-time tracking system — status updates are manual, entered by the distributor
[!WARNING] Some UI labels in
frontend-appare currently in Basque (Euskara). This is intentional for the target region. This documentation site is in English for developer onboarding consistency.