Internal URL shortener.
- Create short link:
{domain}/{CODE}whereCODEis case-sensitive[A-Za-z0-9]+ - Redirect:
GET /{CODE}→302tooriginal_url(active only) - Never reuse codes (rows are never deleted)
- Tag required; expiry is required (permanent is allowed via
expires_at = NULL) - Reserved codes are blocked for both creation and redirect
docker compose up -dcd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
cp .env.example .env
alembic upgrade head
uvicorn app.main:app --reload --port 8000Backend runs at http://localhost:8000.
cd frontend
npm install
cp .env.example .env
npm run devFrontend runs at http://localhost:5173.
- Copy
.firebaserc.example→.firebasercand set your Firebase project id.
cd frontend
npm install
npm run build
cd ..
firebase deploy --only hostingBuild + deploy a container (example):
gcloud run deploy tpe-short-links-api \
--source backend \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars DATABASE_URL="postgresql+psycopg://USER:PASSWORD@/DBNAME?host=/cloudsql/PROJECT:REGION:INSTANCE",ALLOW_HTTP_URLS=false,SHORTLINK_CODE_LENGTH=8,RESERVED_CODES="api,docs,admin,health,metrics",PUBLIC_BASE_URL="https://YOUR_DOMAIN",FIREBASE_PROJECT_ID="YOUR_FIREBASE_PROJECT_ID"For Postgres on GCP, use Cloud SQL + the Cloud SQL Unix socket via /cloudsql/... (as above), or use a private IP/VPC connector depending on your setup.
To enforce Firebase admin authentication on all /api/* routes in production, set:
FIREBASE_PROJECT_IDto your Firebase Project ID (matches Firebase ID tokenaud)
See AUTH_SETUP.md for the full magic-link + Functions setup.
POST /api/linksGET /api/links?query=&tag_id=&status=&limit=&offset=POST /api/links/{code}/disableGET /api/tagsGET /{code}(redirect)