Simple web app for creating packing lists for alpine adventures
|
|
2 týždňov pred | |
|---|---|---|
| admin | 2 týždňov pred | |
| img | 5 mesiacov pred | |
| migrations | 2 týždňov pred | |
| screenshots | 5 mesiacov pred | |
| .gitignore | 3 týždňov pred | |
| .htaccess | 3 týždňov pred | |
| README.md | 2 týždňov pred | |
| config.sample.php | 3 týždňov pred | |
| db.php | 3 týždňov pred | |
| favicon.ico | 5 mesiacov pred | |
| index.php | 2 týždňov pred | |
| list.php | 3 týždňov pred | |
| manifest.webmanifest | 5 mesiacov pred | |
| offline.html | 3 týždňov pred | |
| packing.php | 2 týždňov pred | |
| schema.sql | 2 týždňov pred | |
| sw.js | 3 týždňov pred |
PackIt is a smart packing list generator for outdoor activities. Select the activities you're planning — camping, skiing, kayaking, and more — and PackIt produces a deduplicated, grouped checklist of everything you need to bring.
| Activity selection | Packing list |
|---|---|
![]() |
![]() |
sw.js) caches the app shell and every list you have opened, which is what makes an installed PackIt useful at the trailhead. Pages are network-first, so an online visit always reflects the latest admin changes and falls back to the cached copy only when the network is gone. A list never opened on the device shows offline.html instead. The admin panel is deliberately never cached./admin/ lets you manage all content:
HttpOnly, SameSite=Strict, scoped to /admin/, and marked Secure over HTTPSschema.sql)manifest.webmanifest plus icons in img/Create the database by running schema.sql:
mysql -u <user> -p < schema.sql
Copy the config template and fill in your database credentials:
cp config.sample.php config.php
config.php is git-ignored and excluded from deploy.sh — it never belongs in the repository. On a real server, place it one directory above the web root.
Serve the project with any PHP-capable web server (Apache, Nginx, PHP built-in server). The included .htaccess ensures the .webmanifest MIME type is served correctly, denies HTTP access to config.php, config.sample.php and .sql files, and keeps sw.js out of the browser cache.
Open the site in a browser and start selecting activities. On mobile, use the browser's "Add to Home Screen" option to install PackIt as an app.
Offline support needs a secure context: browsers only register a service worker over HTTPS (or on localhost). Everything else works over plain HTTP.
config.php sets $appEnv. Leave it at production on a live site: errors are written to the PHP error log and visitors see a generic message. Set it to development to get the detail on screen instead. Anything other than the exact string development is treated as production, so a typo fails closed.
Run any migrations your database predates, in order:
mysql -u <user> -p <your-database> < migrations/001_hardening.sql
mysql -u <user> -p <your-database> < migrations/002_hidden_activities.sql
mysql -u <user> -p <your-database> < migrations/003_zombie_items_german.sql
It adds the login_attempts table, narrows selection_hashes.hash to VARCHAR(16), and indexes activity_ids. It also deletes any rows still holding a 64-character hash from the original link scheme — those links have been unreachable since links were shortened to 5 characters, and the table is only a cache of selection → hash, so anything deleted is recreated by re-picking the activities.
002 adds the activities.hidden column and the hidden zombie activity. Its item lookups only match the English sample-data names, so on a database with its own item groups the activity ends up empty. 003 fixes that and renames everything to German (Zombie-Apokalypse in Überleben). Each item goes into its German group (Kleidung, Essen, Küche, Elektronik, Sicherheit, Kleinzeug) or, if that group doesn't exist, into a new Zombie-Abwehr group. Items you already have, such as Stirnlampe or EH-Set, are reused, and the English items 002 created are removed. It is safe to run more than once.
Admin credentials live in the admin_users table, not in config.php. The password_hash column stores a bcrypt hash produced by PHP's password_hash(); admin/login.php verifies the submitted password against it with password_verify().
schema.sql seeds a default account:
| Username | Password |
|---|---|
admin |
packit-admin |
Change it after first login. There is no UI for this yet, so update the row directly — generate a new hash and replace it in the database:
php -r "echo password_hash('your-new-password', PASSWORD_BCRYPT), PHP_EOL;"
UPDATE admin_users
SET password_hash = '<paste-hash-here>'
WHERE username = 'admin';
Failed logins are recorded in login_attempts. After 10 failures from one IP within 15 minutes that IP is refused until the window passes. Repeated failures against a username add a growing delay (up to 5 seconds) instead of a lockout — locking the username would let anyone shut the real admin out of their own panel. A successful login clears that IP's history, and rows older than a day are pruned on each write.
index.php Activity selection page
list.php Processes selection, stores hash, redirects
packing.php Displays the shareable packing list
db.php Bootstrap: error handling + PDO connection helper
config.php Database credentials (git-ignored, create from the sample)
config.sample.php Documented config template
schema.sql Database schema and sample data
migrations/ One-off SQL upgrades for existing databases
sw.js Service worker (offline support)
offline.html Shown when an unvisited list is opened offline
manifest.webmanifest PWA manifest (installable web app)
.htaccess Manifest MIME type, blocks config/SQL, no-cache for sw.js
img/ App icons (192/512, plus maskable variants)
admin/
index.php Dashboard
activities.php Manage activities
activity_groups.php Manage activity groups
items.php Manage items
item_groups.php Manage item groups
mappings.php Manage activity-to-item mappings (with quantities)
layout.php Shared admin layout
login.php / auth.php Authentication, CSRF helpers, login throttling