- Add Cloudflare Pages deployment for landing page (snapotter.com) and
docs (docs.snapotter.com)
- Create deploy-landing.yml and update deploy-docs.yml workflows
- Update CI to ignore apps/landing/** paths
- Fix logo transparency (remove white background) across all apps
- Recreate social-preview.png with SnapOtter branding
- Update all docs URLs from GitHub Pages to docs.snapotter.com
- Update VitePress config: light theme default, fix llms.txt paths
- Add .vitepress/cache/ and .env.* to gitignore
When auth was disabled, the backend middleware attached the first admin
user from the database to every request, and the frontend granted all 12
permissions. This gave every unauthenticated visitor full admin access
to user management, settings, teams, branding, and feature installation.
Now both layers use role "user" with user-level permissions so tools,
files, and pipelines still work without login while admin-only routes
correctly return 403.
Closes#72
Several RBAC features from feat/rbac-permissions were silently lost
during the merge into main. This restores and completes them:
- Add permissions and teamName to login/session API responses
- Export Permission and Role types from shared package
- Filter settings tabs by user permissions in frontend
- Extend useAuth hook with role, permissions, and hasPermission
- Restrict teams listing to admin only
- Add admin override for API keys, files, and pipelines listing
- Add ownership scoping to file access, download, and delete routes
- Register userFileRoutes in integration test server
- Mock auth import in unit permissions test to avoid SQLite lock
Centralize duplicated getToken() + Bearer header logic into a single
formatHeaders() helper in lib/api.ts. When no token exists, the
Authorization header is omitted entirely instead of sending an empty
Bearer token, which breaks forward-auth proxies like Authelia behind
Caddy.
Changes:
- Add formatHeaders() with try-catch around localStorage access
- Replace 20+ duplicated getToken() definitions across tool components
- Migrate all call sites including file-details, settings, change-password
- Update tests to verify header omission on empty token
Based on the fix proposed by @jules2689 in #6, with improvements:
file placement (lib/api.ts vs components), localStorage error handling,
simplified truthiness check, and complete call-site coverage.
Co-Authored-By: Julian Nadeau <julian@jnadeau.ca>
The backend sets mustChangePassword=true for all new accounts and
blocks API calls until the password is changed. The frontend was not
handling this flag - it logged the user in and redirected to the
dashboard where every API call silently failed with 403.
Add a /change-password page that is shown when mustChangePassword is
true. The login page now redirects there instead of home, and the
AuthGuard intercepts any direct navigation to force the change first.
checkAuth was defined as a plain function and used as a useEffect
dependency, causing it to fire on every render. Moved it inside the
effect with an empty dependency array so it runs once on mount.
Home page: after uploading an image, shows tool selector on the left
(quick actions + all 37 tools by category) with image preview on the
right. Stays on the main page — no popup overlay.
Auth: when AUTH_ENABLED=true, unauthenticated users are redirected to
/login. Default credentials admin/admin. When auth is disabled (dev
default), no redirect happens.