Built in public
Changelog
Every meaningful change shipped to Pulsyr. We update this page every time we ship.
v1.8.0
April 15, 2026Security hardening, polished UI (modals, date/time pickers, confirm dialogs), and realtime fixes across the dashboard
- FixedMaster-DB RLS hardening — dropped the `FOR ALL USING (true)` policies on licenses, teams, purchases, and user_licenses. The anon key bundled in the browser previously granted any visitor full read/write on those tables, including every customer's supabase_service_role_key and db_password. Server API routes use the service role and continue to work unchanged.
- FixedShared-DB team_members policy drop — `FOR ALL USING (true)` let any authenticated user self-insert into any team. All team_members writes go through server API routes using the service role; the SELECT policy (Users can read own team) is kept.
- Fixedmeeting_guests policy drop — the old `FOR ALL USING (true)` allowed an unauthenticated attacker to forge verified guest session rows with an attacker-chosen session_token, bypassing the OTP flow entirely.
- FixedAssets IDOR — PATCH/DELETE on asset registers and rows now verify the target's team_id matches the caller's before mutating, matching the pattern in support/tickets/[id].
- FixedCross-tenant membership injection — `/api/hosted/register-member` now looks up the calling admin's own team_id from team_members and rejects if the body teamId differs.
- FixedUnauthenticated `/api/submit-credentials` — now requires the license_key to exist, be active, and still be pending provisioning, preventing forged credential submissions.
- Fixed`/api/keep-alive` fail-open — the endpoint now requires CRON_SECRET to be configured and matched (previously when the env var was unset, anyone could fetch the active-customer list).
- FixedNEXT_PUBLIC_CONTACT_WEBHOOK_URL was bundled to every client. Removed the dead webhook code from verify-payment and submit-credentials.
- FixedAdmins couldn't delete or update other users' tasks — the DELETE/UPDATE policies had no admin override, so the write was silently denied and the row reappeared on refetch. Policies now mirror the SELECT admin override.
- FixedTask-request recipients couldn't accept requests — the RLS policy referenced `(SELECT email FROM auth.users WHERE id = auth.uid())`, which authenticated users can't read. Replaced with `lower(auth.jwt() ->> 'email')` so both sender and recipient UPDATEs now pass.
- Fixed`/api/check-user` was admin-only, causing 'no account found' when a non-admin tried to verify a recipient's email while sending a task request. Relaxed to any authenticated user.
- FixedPublic meeting-page realtime connected to the shared DB even when the host wrote to the master DB, so guests only saw host messages after a reload. Realtime client now prefers the master DB (matches where the API routes writes).
- NewWork Tracker — 'All' tab in list view hides completed tasks (they now live exclusively in the Done tab). Count badge reflects the same.
- NewWork Tracker — status icon is now a proper interactive toggle (hover ring, pop animation, tooltip showing the next action: 'Start task' / 'Send for review' / 'Mark as done' / 'Reopen task'). Removed the redundant 'Mark as Done' text button.
- NewWork Tracker — live realtime subscription on tasks. Assignments accepted by a teammate, status changes, or deletions from any device now appear within ~1s without a reload.
- NewRequests — 3-second polling fallback ensures status changes (accept / decline / cancel) propagate to the counterparty's screen quickly without depending on the realtime publication being configured.
- NewCustom DateInput — replaced every `<input type="date">` with a popover calendar (month navigation, today highlight, Today / Tomorrow / Next week quick picks, min/max bounds). Renders through a React portal so it's never clipped inside modals or scrollable panels.
- NewCustom TimeInput — replaced the native time input with a slider-based picker (big 12-hour display, hour slider with AM/PM tick labels, 5-min-step minute slider, 9 AM / 12 PM / 3 PM / 6 PM quick picks). Also portaled.
- NewCustom confirm/alert dialogs — removed all 15 native `window.confirm` / `window.alert` calls across Chat, Notes, Goals, Work Tracker, Finance Tracker, Timesheet, Calendar, Leave Management, Requests, Meeting Rooms, License Tab, User Management, Asset Register, Tools, and the tools marketing page. Unified variants (default / danger / warning / success) with icon, backdrop, escape-to-close, click-outside-to-close.
- NewEvery user-triggered delete now shows a styled confirmation dialog (14 new spots covered: tasks, notes, goals, habits, transactions, time entries, events, messages, channels, leaves, requests, meeting rooms, purchase records, leave cancel).
- ImprovedAdd-entry forms (New Task, New Transaction, New Event, Manual Time Entry, New Goal, New Habit, Send Request, Edit Request, Add User) now render as proper centered modals on desktop (they were inline cards) with bottom-sheet behavior preserved on mobile. Sticky header, close button, Escape to close, backdrop click to close, body scroll locked while open.
- ImprovedForm layouts restructured from cramped 4-5 column rows to a 2-column grid with proper field labels. Fixes 'No Recurrenc…' text clipping and the cramped native select dropdown arrow.
- NewShared Select component — custom chevron icon, consistent styling, matches the other inputs. Replaces native `<select>` in every modal form.
- ImprovedDark mode is now scoped to the dashboard (/app/**). The landing pages (/, /blog, /tools, /meet, /privacy, /terms, /changelog) always render in light mode regardless of the user's theme setting — they're designed for a light palette only.
v1.7.0
April 11, 2026Asset Register — flexible spreadsheet-like tracking for laptops, networks, equipment, anything
- NewAsset Register — create unlimited custom registers (Laptops, Networks, AWS Accounts, Office Equipment, anything) with user-defined columns. No fixed schema.
- NewColumn types: text, number, date, and color-coded select. Define your own dropdown options with colors (e.g. Status = Active/Unassigned/Needs Repair) just like Google Sheets.
- NewImport CSV — paste any CSV or TSV (copy directly from Excel or Google Sheets) to instantly create a new register. Auto-detects delimiter, parses headers, bulk-inserts rows in a single API call. Live preview as you paste shows detected columns and the first few rows.
- NewAggregate cards on top of every register show counts per status — click a card to instantly filter the table to those rows
- NewMulti-column filters — filter by any column, AND together. Click the Filter button to expand a panel with one input per column. Filter count badge shows how many filters are active.
- NewChart view — toggle Table ↔ Chart to see a CSS bar chart breakdown by any column. Pick a 'Group by' column, click any bar to drill into those rows. Bars use the option's color.
- NewCSV export — download the currently filtered rows as a CSV with proper escaping. Filename auto-derived from the register name.
- NewSchema editor — add, rename, or delete columns at any time. Convert column types, add or remove select options, pick colors. Inline UI, no SQL needed.
- NewPer-team caps on hosted plan — 10 registers per team, 500 rows per register. Configurable via PULSYR_MAX_REGISTERS_PER_TEAM and PULSYR_MAX_ROWS_PER_REGISTER env vars. Sized so 10 teams fit comfortably in the free Supabase tier (~13% of 500 MB used by asset data).
- NewSupport tickets — users can file support tickets from a new Support page in the sidebar. Admins see all tickets, can change status (open/in progress/resolved/closed) and post a response. Plan-agnostic — works for hosted, Own DB, and master DB.
- ImprovedLogin page — removed the always-visible 'first time logging in?' notice that no longer applied to most users. The license-key recovery hint now only appears contextually after a failed sign-in attempt.
- ImprovedHosted plan first-login on a new device — verify-payment now pre-registers the email→license mapping at purchase time so customers can sign in with just email + password from any browser, no license key entry required.
- ImprovedTeam member invites — when an admin adds a new team member via the Manage Users page, the new user's email→license mapping is auto-created. They can sign in from any device with just email + password.
- FixedStale license routing cookies (pulsyr_srk, pulsyr_url) from previous sessions could cause API calls to silently route to the wrong database. Cookies are now cleared automatically on logout, license removal, and on first AuthProvider mount when no license is active.
- FixedWipe Team and Reset All Data now also clean up support tickets and asset register data — earlier they left orphan rows behind for newer features.
v1.6.0
April 10, 2026Meeting rooms — end-to-end realtime messaging fix
- FixedMeeting room creation on the hosted plan — removed a broken team_id NOT NULL trigger that depended on auth.uid() (unavailable when the API uses the service role key)
- FixedPublic /meet/[id] page returning 'Meeting room not found' — both meeting room API routes now connect to the shared DB directly via SHARED_SUPABASE_URL instead of dynamic cookie/header routing
- FixedRealtime messages on the public meeting page silently connected to the wrong database — added NEXT_PUBLIC_SHARED_SUPABASE_URL and NEXT_PUBLIC_SHARED_SUPABASE_ANON_KEY env vars so the browser realtime client points at the shared DB
- Fixed'Multiple GoTrueClient instances detected' warning that broke realtime event delivery — the public meet page client now runs at module level with persistSession: false and a unique storageKey, avoiding conflicts with the main app's Supabase client
- FixedHost messages duplicated when pressing Enter rapidly — added a re-entry guard in sendMessage and clear the input before awaiting the insert so multiple submissions can't queue
- ImprovedBoth host and guest now see their own messages instantly via optimistic insert with id-based dedupe so realtime broadcasts don't double-add
- FixedRealtime publication on the shared DB was missing several messaging tables (channel_messages, direct_messages, meeting_messages, channel_members, message_reactions) — new idempotent migration database-fix-realtime-publication.sql adds them all
- FixedWipe Team on the hosted plan was missing newer tables — channel chat (channels, channel_messages, channel_members, message_reactions), meeting rooms, and leave requests were not being deleted. Now explicitly deletes from every team-scoped table in the correct order with errors logged
v1.5.0
April 10, 20266 new browser-based PDF tools + privacy-first /tools marketing site
- NewSplit PDF — break a PDF into individual page files, entirely in your browser
- NewRotate PDF — rotate all pages 90°, 180°, or 270° with a single click
- NewOrganize PDF — delete specific pages (supports ranges like '2,4,7-9')
- NewCrop PDF — trim whitespace margins from all pages uniformly
- NewAdd Page Numbers — stamp sequential 'N / total' numbers in any corner position
- NewWatermark PDF — add diagonal text watermark (CONFIDENTIAL, DRAFT, etc.) with adjustable opacity
- NewStandalone public /tools pages — each converter now has its own SEO-optimized landing page at /tools/{slug} with FAQ, schema markup, and privacy verification instructions
- ImprovedAll converters remain 100% browser-based — zero network requests during conversion, verifiable in DevTools
- Improved13 total tools now available (7 original + 6 new), all running entirely on your device
v1.4.0
April 10, 2026New About page — full transparency on how Pulsyr works
- NewAdded a dedicated About page inside the dashboard explaining how Pulsyr works end-to-end — pick a plan, log in, add your team, own your data
- NewSecurity & Privacy section breaking down exactly how your data is stored, who can access it, and how isolation works on both Hosted and Own DB plans
- NewStep-by-step 'How it works' walkthrough so new team members can understand the product without reading a doc
- ImprovedAbout page is now accessible from the sidebar for every user (no admin required)
v1.3.0
April 9, 2026Smoother navigation + checkout cleanup
- NewAdded a 'Back to Home' link on the login page and a home shortcut in the sidebar/mobile header
- ImprovedSimplified the license purchase form — removed the 'Number of team members' field since the hosted plan supports up to 20 users by default
- ImprovedDefault team size now set to 20 for hosted plans, no need to ask upfront
Want to suggest a feature or report a bug? Get in touch — I read every message personally.