Commit Graph
10 Commits
Author SHA1 Message Date
maziggy df66924066 feat(onboarding): BB welcome modal + 25-step guided tour
Closes the recurring "I added the printer but it isn't connecting" +
  "where is X feature" cluster that drove ~1/3 of invalid-tagged issues.
  New users now see a friendly welcome modal on first load and can take
  a guided walkthrough that highlights the load-bearing UI surface
  step-by-step.

  Backend: two new nullable columns on users (onboarding_status
  VARCHAR(64), onboarding_snoozed_until TIMESTAMP) added via inline
  migration with a one-shot backfill that marks every existing user as
  dismissed_at_migration -- pre-existing installs never see the welcome
  modal. GET + PATCH /api/v1/users/me/onboarding round-trip the state;
  OnboardingUpdate schema rejects dismissed_at_migration from the API
  (migration-internal only), validates the tour_in_progress:<step_id>
  form, and enforces snooze coherence (snoozed_until required only when
  status is snoozed). _users_column_exists helper mirrors
  _api_keys_column_exists and gates the backfill so restarts after
  new-user signups do not clobber the welcome-eligible NULL state.
  SQLite and Postgres both verified end-to-end.

  Frontend architecture: OnboardingProvider wraps the app inside
  AuthProvider; reads from the backend when auth is on, falls back to
  localStorage (bambuddy.onboarding_status + onboarding_snoozed_until)
  when auth is off so no-auth installs still get the welcome
  experience. A loadFailed gate prevents the welcome modal from popping
  over a backend outage -- we cannot distinguish "new user" from "GET
  errored" so we stay silent. OnboardingFlow driver picks between the
  Phase 0 welcome modal, the Phase 0.2 about modal, and the
  step-by-step TourEngine based on persisted status. Mounted inside
  BrowserRouter so the route guard's useLocation has its context (a
  sibling-of-Router placement crashed at runtime).

  Route guard: the overlay never renders on /setup, /login,
  /spoolbuddy/*, /camera/*, /overlay/*, or while requiresSetup is
  true -- fresh installs walk through the existing /setup flow
  uninterrupted, and the SpoolBuddy kiosk / OBS overlay / camera-popout
  windows never get a modal slapped over them.

  Tour engine: 25 steps targeting existing data-tour anchors --
  add-printer -> verify-connection -> printer-card sub-tour x5 (status
  row, AMS row, camera, controls, customize menu) -> add-spool ->
  bambu-cloud-sync -> sidebar overview x6 -> vp -> slicer-api ->
  makerworld -> obico -> integrations -> notifications -> users ->
  groups -> sso -> outro. Per-step route navigation via useNavigate,
  anchor polling at 100ms intervals with a 3-second cap (pages need a
  beat after navigation; never spin forever), box-shadow dimmed-
  spotlight cutout that pointer-events-through so the user can still
  interact, smart modal positioning (sidebar anchors to the right;
  page anchors below or flipped above based on viewport room),
  Back/Next/Skip with Escape as Skip, persistence on every Back/Next
  so mid-tour reloads resume at the same step.

  Conditional skip: each step exposes a skipIf(ctx) evaluated against
  at least one printer exists; verify-connection + the entire card
  sub-tour skip when no printer exists; makerworld skips when the user
  lacks makerworld:view (the sidebar entry is permission-gated and the
  anchor would not resolve); users / groups / sso skip when auth is
  off. Pre-render gate means the user never sees a flash of a step
  that is about to skip.

  Phase 1.1 "Lock the front door" auth step explicitly removed from
  the live tour -- /setup already prompts for the auth choice on fresh
  installs, and users who deliberately chose no-auth must not be
  nudged to enable it. The auth-card anchor stays for any future
  privacy-checkup surface.

  BB mascot: hero pose + 5 named poses (started / walk / almost /
  allset / help) sliced from the character sheet via Pillow into
  public/img/bb_*.webp. MascotIcon component takes a pose prop;
  per-step pose mapping in tourSteps.ts. TourLauncher sits in the
  sidebar footer as a BB icon that relaunches the tour from step 0
  and consumes the [data-tour="help-icon"] selector.

  WikiHelpIcon component lands the per-page question-mark icon on
  Queue / Archives / Stats / Maintenance / Files / Projects /
  Inventory -- opens the matching wiki.bambuddy.cool/{path}/ page in
  a new tab (chose new-tab over iframe because the wiki sets
  X-Frame-Options: DENY).

  27 new data-tour anchors across PrintersPage / SettingsPage /
  ProfilesPage / InventoryPage / Layout. i18n: 138 new keys under a
  new onboarding.* namespace, real translations in every locale
  (de/en/es/fr/it/ja/ko/pt-BR/tr/zh-CN/zh-TW) -- no
  IDENTICAL_TO_EN_ALLOWED entries added.

  Backend tests: 12 in TestOnboardingAPI cover the round-trips and the
  validator branches. Frontend tests: 61 across 7 files -- anchor
  presence backstop, Phase 0 modal interaction, tour engine + step
  helpers, provider state machine (auth-on/off split, PATCH error
  fall-through, localStorage round-trip), route guard for every
  suppress path, WikiHelpIcon href/target/aria. Backend pytest
  5723/5723; frontend vitest 2154/2154; ESLint clean; frontend build
  clean; i18n parity clean at 5233 leaves x 11 locales.

  Companion docs: docs/onboarding-tour-plan.md carries the design
  (Phase 0-5 step inventory, anchor selector list, state model, asset
  inventory, resolved decisions, Implementation Status section that
  is authoritative for current shipped state).
2026-06-10 10:06:42 +02:00
maziggy 18d534c945 feat(orca-cloud): integrate Orca Cloud profile sync across UI, slicer and SpoolBuddy
Reads, lists, and slices with profiles from a user's Orca Cloud account
  (OrcaSlicer 2.4.0-alpha's Supabase-backed sync) alongside the existing
  Bambu Cloud integration. Four sign-in providers (Google / Apple / GitHub /
  email+password); password defaults. Paste-flow PKCE because Orca's
  Supabase project only allowlists localhost redirect_to — open feature
  request at OrcaSlicer/OrcaSlicer#14028.

  Surfaces:
  - Profiles tab: new "Orca Cloud" tab next to "Bambu Cloud" with the same
    rich layout (search + 5 filter dropdowns + 3-column grouped grid +
    read-only detail modal)
  - SliceModal: 4-tier preset picker (orca_cloud > local > bambu cloud >
    standard); separate status banner per cloud; metadata-aware pre-pick
    scores Orca filaments above local (Orca's sync_pull returns full
    content inline so filament_type / filament_colour come for free, no
    per-setting fetch rate-limit dance)
  - ConfigureAmsSlotModal: orca_cloud as a new preset source (prefixed
    orca_<UUID> to match local_/builtin_); generic Bambu filament-ID
    derivation from parsed material (printer firmware can't grok Orca
    UUIDs); slot mapping persists preset_source='orca_cloud'
  - SpoolForm / SpoolBuddyWriteTagPage: Orca filaments merge into the
    cloud preset list via Promise.allSettled (OrcaProfileMeta is
    structurally identical to SlicerSetting)

  Backend:
  - services/orca_cloud.py: OrcaCloudService with PKCE / token exchange /
    single-use refresh rotation / get_user_info / list_profiles via the
    bare /sync/pull bootstrap path
  - routes/orca_cloud.py: 7 endpoints (auth/start, auth/finish,
    auth/password, status, logout, profiles, profiles/{id}); router-level
    _cloud_api_key_gate + per-route cloud_caller() so API-keyed callers
    (SpoolBuddy kiosk) properly resolve their owner User; just-in-time
    refresh with atomic persist-before-API-call
  - routes/slicer_presets.py: _fetch_orca_cloud_presets mirrors the Bambu
    Cloud fetcher (status vocabulary, 5min cache, permission shortcut);
    _dedupe_by_name extended to 4 tiers; UnifiedPresetsResponse gains
    orca_cloud + orca_cloud_status
  - services/preset_resolver.py: PresetRef.source extended with
    "orca_cloud"; _resolve_orca_cloud walks list + filters
  - 8 columns on users table for tokens (5 persistent) + transient PKCE
    handshake state with 10-min TTL (3); dialect-branched DATETIME /
    TIMESTAMP; auth-disabled mode falls back to Settings table
  - orca_cloud:auth permission folded into can_access_cloud API-key scope
    (same trust dimension)
2026-06-04 15:50:44 +02:00
Minidoracat baf0716a9a feat(cloud): support China region for token-based login (#1013)
feat(cloud): support China region for token-based login

The /cloud/token endpoint always used the global Bambu API endpoint,
so users with China-region access tokens could not validate their
token. The password login flow already exposes a region selector; this
brings the token flow to parity.
2026-04-18 12:30:01 +02:00
Sn0rrii ba1c97c808 feat: Two-Factor Authentication (TOTP, Email OTP) and OIDC/SSO – full implementation with admin UI (#933)
feat: Two-Factor Authentication (TOTP, Email OTP) and OIDC/SSO – full implementation with admin UI (#933)
2026-04-13 13:24:28 +02:00
maziggy b6599dd419 Add LDAP/Active Directory authentication (#794)
Users can authenticate against an LDAP/AD server with configurable
  server URL, bind DN, search base, and user filter. Supports StartTLS
  and LDAPS — plaintext is not allowed. Both Active Directory (memberOf)
  and POSIX groups (memberUid) are mapped to BamBuddy groups on each
  login. Auto-provisioning creates local accounts on first LDAP login.
  Local admin accounts remain as fallback when LDAP is unreachable.
  Password management is disabled for LDAP users.
2026-04-08 10:41:27 +02:00
Thomas Rambach 9562d66b6b Feature: Advanced Authentication User Email Notifications (#693)
Feature: Advanced Authentication User Email Notifications (#693)
2026-03-17 12:01:18 +01:00
maziggy f1eb375964 Fix cloud profiles shared across all users (#665)
Cloud credentials were stored globally — one Bambu Cloud account per
  Bambuddy instance. When auth was enabled, any user logging into Cloud
  overwrote everyone else's credentials. Credentials are now stored
  per-user: each user gets their own independent Cloud login.

  Also fixed cloud data endpoints (settings, fields, preset CRUD)
  requiring settings:read/settings:update permissions instead of
  cloud:auth — users who had "Cloud Auth" enabled but "Settings"
  disabled couldn't load profiles after logging in.
2026-03-12 13:02:13 +01:00
copilot-swe-agent[bot]andcadtoolbox 1058f3fd5c Add backend support for advanced authentication
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
2026-02-08 15:23:38 +00:00
maziggy 89229a5ecc Add group-based permissions system with granular access control
Implement a full permissions system replacing simple admin/user roles:

Backend:
- Add Group model with many-to-many user relationship
- Add 50+ granular permissions (resource:action pattern)
- Create default groups: Administrators, Operators, Viewers
- Add permission-checking dependencies for route protection
- Add groups API endpoints (CRUD, user assignment)
- Add change password endpoint for users
- Update backup/restore to include groups
- Migrate existing users to groups on startup

Frontend:
- Add GroupsPage for managing groups and permissions
- Add permission helpers to AuthContext (hasPermission, hasAnyPermission)
- Add PermissionRoute component for protected routes
- Disable buttons/features based on permissions (with tooltips)
- Add change password modal in sidebar for all users
- Add forgot password info modal on login page
- Show user groups in UsersPage with group assignment

Testing:
- Add integration tests for groups API
- Add tests for user-group assignments
- Add tests for change password endpoint
- Seed default groups in test fixtures

Closes #28 #161
2026-01-31 12:50:15 +01:00
JesseFPV f8857ba666 Added optional authentication and user management 2026-01-21 14:10:06 +01:00