Files
qrknit/README.md
T
2026-03-06 10:18:15 -06:00

131 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QRknit — URL Shortener & QR Code Generator
A managed URL shortener with QR code generation, deep click analytics, and tag-based link organization.
- **Multi-user** — admin account seeded from env vars; admin can create/delete/manage accounts via the UI
- **Per-user isolation** — each user sees only their own links and tags; admin has its own isolated workspace separate from all other accounts
- **Organizations** — group users into orgs that share link/tag visibility and pool usage quotas under a shared plan
- **Plan tiers** — Admin / Free / Starter / Pro / Team with enforced limits on active links, monthly clicks, and analytics history window; org members inherit their org's plan
- **Scoped tags** — tags are owned by the user who creates them; org members share a tag namespace, solo users and admins each have their own isolated namespace
- **Deep analytics** — daily charts, referrer/device/browser/country breakdowns, hourly 7×24 heatmap, raw click CSV export
- **Private instance** — Pro and Team plans include a dedicated private deployment on your own infrastructure
---
## 🗺 Feature Map
### Shipped
| Feature area | What's included |
|---|---|
| **Short links** | Random & custom codes, link expiry, pinned links, one-click copy, auto-fetch page title |
| **QR codes** | QR generation for any link or URL, logo overlay, dot-shape presets, inline thumbnail, copy to clipboard |
| **Analytics** | Per-link daily click charts, referrer / device / browser / country breakdowns, hourly 7×24 heatmap, raw click CSV export |
| **Tags** | Tag links for filtering; tags are scoped per user — org members share a namespace, solo users and admins each have their own |
| **Bulk tools** | Bulk delete, bulk tag, bulk expire; CSV import & export |
| **Auth** | Session-cookie login, 30-day HttpOnly cookie, works behind Cloudflare and Nginx Proxy Manager |
| **Multi-user** | Per-user link isolation, admin user-management panel, username + password login |
| **Organizations** | Group users into orgs that share link/tag visibility and pool usage quotas under a shared plan |
| **Plan tiers** | Free / Starter / Pro / Team plans with enforced limits on active links, monthly clicks, and analytics history; org plan overrides member plans |
| **Admin tier** | Admin accounts sit above all plans with unlimited quotas and an isolated workspace; can filter into any user's links on demand |
| **Landing & portal** | Marketing landing page, SaaS pricing page, contact form, admin inbox with unread badge |
| **Deployment** | `APP_NAME` / `BASE_URL` env vars, four colour themes, single Docker container, Unraid-ready |
### Upcoming
| Feature area | What's planned |
|---|---|
| **Billing** | Stripe checkout & subscriptions, upgrade/downgrade UI, self-serve account portal |
| **Custom domains** | CNAME-based short domains, SSL provisioning, domain verification, Team tier multi-domain support |
| **Power features** | API key auth, password-protected links, UTM parameter builder, custom 404 & expired-link pages |
| **Link organisation** | Folders/groups, duplicate link, dead-link detection, per-link redirect type (301 vs 302) |
---
> **Installing?** See [INSTALL.md](INSTALL.md) for Docker, Docker Compose, and Unraid setup instructions, environment variables, and update steps.
---
## 🔌 API Reference
All write endpoints require an active session (log in via the web UI or `POST /api/auth/login`).
### Auth
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | `/api/auth/login` | — | Login — `{"username": "...", "password": "..."}`, sets session cookie; returns `plan`, `plan_limits`, `org_id` |
| POST | `/api/auth/logout` | ✓ | Clear session |
| GET | `/api/auth/me` | ✓ | Returns `{"authenticated": true, "username": "...", "is_admin": bool, "org_id": int\|null, "plan": "...", "plan_limits": {…}}` |
### Links
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | `/api/shorten` | ✓ | Create a short link |
| GET | `/api/links` | ✓ | List links — supports `?q=`, `?tag=`, `?page=`, `?per_page=`; org members see all links within their org; admin sees own links only, optionally filtered with `?user=<username>` |
| GET | `/api/links/:code` | ✓ | Link detail — includes `created_by` username |
| PATCH | `/api/links/:code` | ✓ | Edit link — `url`, `title`, `expires_at`, `tags`, `is_pinned` |
| DELETE | `/api/links/:code` | ✓ | Delete link |
| GET | `/api/links/:code/analytics` | ✓ | Click analytics — supports `?days=7\|30\|90` (capped to plan's max window); returns `daily`, `referrers`, `devices`, `browsers`, `countries`, `heatmap` (7×24 array), and `max_days` |
| GET | `/api/links/:code/clicks/export` | ✓ | Download raw click events as CSV — columns: `timestamp`, `referrer`, `device`, `browser`, `country` |
### Utilities
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | `/api/stats` | ✓ | Total links, total clicks, clicks/7d, top 5 links, and a 30-day `daily` click array for the dashboard chart |
| GET | `/api/plan` | ✓ | Current user's effective plan, limits, and live usage — `{plan, limits: {max_links, monthly_clicks, analytics_days}, usage: {active_links, monthly_clicks}}`; org members see pooled usage across all org members; admin plan is always `"admin"` (unlimited) |
| GET | `/api/tags` | ✓ | Tags scoped to the requesting user — own tags only for solo users and admins; all org member tags for org members |
| GET | `/api/fetch-title` | ✓ | Server-side page title fetch — `?url=`. Returns `{"title":"…"}` |
| GET | `/api/qr/:code` | — | QR PNG for a short link |
| GET | `/api/qr/custom` | — | QR PNG for any URL — `?url=`, `?fg=`, `?bg=`, `?size=`, `?style=` |
| POST | `/api/qr/custom` | — | QR PNG with logo overlay — `{url, fg, bg, size, style, logo}` (logo as base64) |
| POST | `/api/links/bulk` | ✓ | Bulk operations — `{action: "delete"\|"tag"\|"expire", codes: […]}` |
| GET | `/api/links/export` | ✓ | Download all links as CSV |
| POST | `/api/links/import` | ✓ | Import links from CSV — `{csv: "…"}` |
| GET | `/api/health` | — | Health check — `{"status":"ok"}` |
| GET | `/:code` | — | Redirect to destination URL |
### Admin
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | `/api/admin/users` | Admin | List all users with link counts, plan, org name, and org plan |
| POST | `/api/admin/users` | Admin | Create user — `{username, password, is_admin, plan}` |
| PATCH | `/api/admin/users/:id` | Admin | Update plan, admin status, and/or org — `{plan?, is_admin?, org_id?}` (set `org_id: null` to remove from org) |
| DELETE | `/api/admin/users/:id` | Admin | Delete user (cannot delete self) |
| PATCH | `/api/admin/users/:id/password` | Admin | Change user password — `{password}` |
| GET | `/api/admin/organizations` | Admin | List all organizations with member counts and plan |
| POST | `/api/admin/organizations` | Admin | Create organization — `{name, plan}` |
| PATCH | `/api/admin/organizations/:id` | Admin | Update organization name and/or plan — `{name?, plan?}` |
| DELETE | `/api/admin/organizations/:id` | Admin | Delete organization — members are unassigned but not deleted |
| GET | `/api/admin/messages` | Admin | List all contact/portal messages, newest first |
| DELETE | `/api/admin/messages/:id` | Admin | Delete a message |
| PATCH | `/api/admin/messages/:id/read` | Admin | Mark a message as read |
### Contact
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | `/api/contact` | — | Submit a contact message — `{name, email, subject, body}` |
---
## Third-party attributions
QRknit is built on open-source components. See [NOTICES.md](NOTICES.md) for full licence texts.
| Library | Licence | Used for |
|---|---|---|
| [Flask](https://flask.palletsprojects.com) | BSD-3-Clause | Web framework & routing |
| [Werkzeug](https://werkzeug.palletsprojects.com) | BSD-3-Clause | Password hashing, WSGI utilities |
| [qrcode](https://github.com/lincolnloop/python-qrcode) | MIT | QR code generation |
| [Pillow](https://python-pillow.org) | HPND | Image processing & QR rendering |
| [Gunicorn](https://gunicorn.org) | MIT | Production WSGI server |
| [Google Fonts](https://fonts.google.com) — Orbitron, Barlow, Share Tech Mono | OFL-1.1 | UI typography |
---
© 2025 QRknit. All rights reserved.