{"id":374,"date":"2026-10-17T15:11:26","date_gmt":"2026-10-17T23:11:26","guid":{"rendered":"https:\/\/rainier-it.com\/blog\/?p=374"},"modified":"2026-10-21T00:06:40","modified_gmt":"2026-10-21T07:06:40","slug":"whats-new-in-the-rainier-it-client-portal-automatic-updates-device-pages-and-whats-coming-next","status":"publish","type":"post","link":"https:\/\/rainier-it.com\/blog\/whats-new-in-the-rainier-it-client-portal-automatic-updates-device-pages-and-whats-coming-next\/","title":{"rendered":"What&#8217;s New in the Rainier IT Client Portal: Automatic Updates, Device Pages, and What&#8217;s Coming Next"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em>You shouldn&#8217;t have to email your IT provider to find out whether last week&#8217;s updates installed, which laptop is which, or where your ticket stands. That should be one click away.<\/em><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/portal.rainier-it.com\">Client Portal<\/a> is where our clients see their computers, tickets, invoices and shared files. This fall it got its biggest round of changes since launch. The headline feature is <strong>automatic weekly updates<\/strong>: you pick a time, and Windows and app updates install themselves, with a reminder the day before and a summary afterwards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This post covers what&#8217;s new, how the update scheduling works behind the scenes, and what&#8217;s coming next.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd04 Automatic weekly updates<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Missed updates are one of the most common ways small offices get breached. They usually don&#8217;t fail loudly. A laptop that was asleep on update night, a restart nobody clicked, or a policy that quietly stopped running can all leave a machine weeks behind without anyone noticing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The new <strong>Updates<\/strong> page puts the schedule in the client&#8217;s hands and the bookkeeping in ours:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>You choose the window.<\/strong> Pick a day, a time (during the workday or after hours) and your time zone. The status shows &#8220;Saving to our patching system\u2026&#8221; and turns <strong>Active<\/strong> within about five minutes.<\/li>\n\n\n\n<li><strong>You choose how restarts work.<\/strong> Restart automatically with a 15-minute warning, never restart during the day, or let staff postpone.<\/li>\n\n\n\n<li><strong>Waiting periods.<\/strong> Windows updates wait 5 days and app updates wait 2, so a bad patch has time to surface before it reaches you.<\/li>\n\n\n\n<li><strong>Machines that were off catch up.<\/strong> A computer that was off at update time picks up its updates the next time it&#8217;s turned on, for up to 6 days.<\/li>\n\n\n\n<li><strong>No surprises.<\/strong> We email a reminder the day before (what&#8217;s being installed and anything staff need to do) and a short summary after each run. On update day, the Overview page shows a banner too.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Big Windows version upgrades and hardware drivers are not automatic. We schedule those with you, because they&#8217;re the updates most likely to need someone in the room.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How it works behind the scenes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The portal stores each client&#8217;s choices as a simple policy. A small service we call <strong>patch-watch<\/strong> runs every five minutes on our monitoring server. It turns each policy into a schedule in our patching platform, sends the reminder and results emails, and watches each run as it happens.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>Client Portal \u2500\u25ba patch policy \u2500\u25ba patch-watch (every 5 min)\n                                     \u2502\n                     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                     \u25bc               \u25bc                \u25bc\n              patching schedule  reminder email   run watch\n              (exact update list)  (day before)   \u2500\u25ba results email\n                                                  \u2500\u25ba portal history<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color:#2e3440ff;color:#d8dee9ff\" tabindex=\"0\"><code><span class=\"line\"><span>Client Portal \u2500\u25ba patch policy \u2500\u25ba patch-watch (every 5 min)<\/span><\/span>\n<span class=\"line\"><span>                                     \u2502<\/span><\/span>\n<span class=\"line\"><span>                     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510<\/span><\/span>\n<span class=\"line\"><span>                     \u25bc               \u25bc                \u25bc<\/span><\/span>\n<span class=\"line\"><span>              patching schedule  reminder email   run watch<\/span><\/span>\n<span class=\"line\"><span>              (exact update list)  (day before)   \u2500\u25ba results email<\/span><\/span>\n<span class=\"line\"><span>                                                  \u2500\u25ba portal history<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The key design choice: <strong>patch-watch owns every schedule<\/strong>. It doesn&#8217;t just create the schedule once and hope. Each tick, it compares what the patching platform has against what the policy says, and puts it back if someone changed it by hand. It also sends an explicit list of approved updates rather than &#8220;install everything,&#8221; so the waiting periods are enforced by us, not by a vendor default.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The timer is plain systemd, the same pattern we use for our other integrations:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly># \/etc\/systemd\/system\/patch-watch.timer\n&#91;Unit&#93;\nDescription=Run patch-watch every 5 minutes\n\n&#91;Timer&#93;\nOnBootSec=2min\nOnUnitActiveSec=5min\nRandomizedDelaySec=30s\n\n&#91;Install&#93;\nWantedBy=timers.target<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #616E88\"># \/etc\/systemd\/system\/patch-watch.timer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Unit<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">Description<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">Run patch-watch every 5 minutes<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Timer<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">OnBootSec<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">2min<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">OnUnitActiveSec<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">5min<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">RandomizedDelaySec<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">30s<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Install<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">WantedBy<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">timers.target<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Picking the update list is the part that has to be right. Here is an excerpt of the actual rule in patch-watch: which kinds of Windows update are allowed, what&#8217;s never automatic, and how long each kind waits:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>WAIT = {\"windows\": timedelta(days=5), \"app\": timedelta(days=2)}\n\n# Windows updates we install; drivers, firmware and OEM updates are skipped.\nWINDOWS_ALLOW = re.compile(\n    r\"^\\d{4}-\\d{2} (Security Update|Cumulative Update|Servicing Stack Update\"\n    r\"|\\.NET)\"\n    r\"|^Security Intelligence Update for Microsoft Defender\"\n    r\"|^Windows Malicious Software Removal Tool\")\nNEVER = re.compile(r\"Preview|Extended Security Updates \\(ESU\\)\"\n                   r\"|Feature update|Enablement Package\")\n\n# ...later, for each missing update:\nif now - since &lt; WAIT&#91;kind&#93;:\n    continue        # too new: it waits for a later run<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D8DEE9FF\">WAIT <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">windows<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">timedelta<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">days<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">5<\/span><span style=\"color: #ECEFF4\">),<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">app<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">timedelta<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">days<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">2<\/span><span style=\"color: #ECEFF4\">)}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #616E88\"># Windows updates we install; drivers, firmware and OEM updates are skipped.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">WINDOWS_ALLOW <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> re<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">compile<\/span><span style=\"color: #ECEFF4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #EBCB8B\">^\\d<\/span><span style=\"color: #81A1C1\">{4}<\/span><span style=\"color: #EBCB8B\">-\\d<\/span><span style=\"color: #81A1C1\">{2}<\/span><span style=\"color: #EBCB8B\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #EBCB8B\">Security Update<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">Cumulative Update<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">Servicing Stack Update<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">\\.NET)<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">^Security Intelligence Update for Microsoft Defender<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">^Windows Malicious Software Removal Tool<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">NEVER <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> re<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">compile<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #EBCB8B\">Preview<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">Extended Security Updates \\(ESU\\)<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">                   <\/span><span style=\"color: #81A1C1\">r<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">Feature update<\/span><span style=\"color: #81A1C1\">|<\/span><span style=\"color: #EBCB8B\">Enablement Package<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #616E88\"># ...later, for each missing update:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">if<\/span><span style=\"color: #D8DEE9FF\"> now <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> since <\/span><span style=\"color: #81A1C1\">&lt;<\/span><span style=\"color: #D8DEE9FF\"> WAIT<\/span><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">kind<\/span><span style=\"color: #ECEFF4\">&#93;:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">continue<\/span><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #616E88\"># too new: it waits for a later run<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Time zones turned out to be the trickiest part. &#8220;Thursday at 7 PM&#8221; has to mean 7 PM in the client&#8217;s time zone, through daylight saving changes, even though the platform underneath stores times its own way. That got its own set of tests, including the spring-forward hour that doesn&#8217;t exist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We also keep an eye on patch-watch itself. If it stops running, or can&#8217;t sync a client, an alert fires in our monitoring before a missed update window could slip by unnoticed.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfab Support tickets in one place<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tickets have their own pages now. From <strong>Support<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Open a ticket<\/strong> with a subject, a description and an urgency (Normal, High or Urgent).<\/li>\n\n\n\n<li><strong>View all<\/strong> your tickets, switch between Open, Closed and All, and search by subject or ticket number.<\/li>\n\n\n\n<li><strong>Reply<\/strong> at the bottom of any ticket. Replying to our emails still works and lands in the same conversation.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udcbb A page for every computer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Click any computer under <strong>Devices<\/strong> and you get its own page, in six sections:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Section<\/th><th>What you see<\/th><\/tr><\/thead><tbody><tr><td>Overview<\/td><td>Online status, last seen, last reboot, who&#8217;s signed in, operating system<\/td><\/tr><tr><td>Hardware<\/td><td>Make, model, serial number, processor and memory<\/td><\/tr><tr><td>Storage<\/td><td>Space used on each drive; the bar turns amber, then red, as it fills<\/td><\/tr><tr><td>Network<\/td><td>IPv4, IPv6 and MAC address of the main connection<\/td><\/tr><tr><td>Security<\/td><td>Microsoft Defender, Windows Firewall and Huntress status<\/td><\/tr><tr><td>Patches<\/td><td>Updates waiting, when the last ones went in, restart pending<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s handy when we ask &#8220;which computer is this?&#8221;, and for warranty calls, where the serial number is right there.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udcca Your environment at a glance<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Overview page now opens with a live summary of your company&#8217;s computers. The headline says how many are online right now, and four cards sit underneath it. Each card is a link to the list behind the number:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Card<\/th><th>What it tells you<\/th><\/tr><\/thead><tbody><tr><td>Computers<\/td><td>How many we manage, how many are online now and how many checked in today<\/td><\/tr><tr><td>Restart due<\/td><td>Computers with updates waiting on a restart<\/td><\/tr><tr><td>Not seen 30+ days<\/td><td>Machines that have gone quiet. Retired one? Tell us and we&#8217;ll remove it<\/td><\/tr><tr><td>Open tickets<\/td><td>What&#8217;s open now, plus how many were opened and closed in the last 30 days<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Under the cards are charts: computers online over the last 7 days, tickets over the last 30, when each computer last checked in, and how up to date they are. The cards at the top of the other pages, like Devices and Account, are clickable now too.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Where the numbers come from<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The charts need history, and our remote management platform only knows what&#8217;s true right now. So a small exporter on our monitoring server asks it, and our patching platform, about each client every five minutes. It writes one line per number, labeled with the client it belongs to. Prometheus keeps the history, and the portal asks only for your company&#8217;s lines. These are our own, from the live file:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>rit_client_devices{trmm_client_id=\"1\",client=\"Rainier IT\"} 7\nrit_client_devices_online{trmm_client_id=\"1\",client=\"Rainier IT\"} 3\nrit_client_devices_restart_due{trmm_client_id=\"1\",client=\"Rainier IT\"} 1\nrit_client_devices_stale{trmm_client_id=\"1\",client=\"Rainier IT\"} 1<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color:#2e3440ff;color:#d8dee9ff\" tabindex=\"0\"><code><span class=\"line\"><span>rit_client_devices{trmm_client_id=\"1\",client=\"Rainier IT\"} 7<\/span><\/span>\n<span class=\"line\"><span>rit_client_devices_online{trmm_client_id=\"1\",client=\"Rainier IT\"} 3<\/span><\/span>\n<span class=\"line\"><span>rit_client_devices_restart_due{trmm_client_id=\"1\",client=\"Rainier IT\"} 1<\/span><\/span>\n<span class=\"line\"><span>rit_client_devices_stale{trmm_client_id=\"1\",client=\"Rainier IT\"} 1<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">If the exporter stops writing, an alert fires, the same way it does for patch-watch.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd11 Passwords, managed from the portal<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For clients on our managed password manager, Bitwarden, there&#8217;s a new <strong>Passwords<\/strong> page. Everyone gets a card on the Overview showing how many people have two-step login turned on. Client admins get the whole page:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>People.<\/strong> Everyone in your company&#8217;s Bitwarden, with their role, status, two-step login, account recovery and when they were last active. Anything that needs a look is listed at the top.<\/li>\n\n\n\n<li><strong>Add a person.<\/strong> Enter a name, work email, role and groups. Bitwarden emails them an invite, they create their account, and you confirm them with one click. We email you when it&#8217;s time.<\/li>\n\n\n\n<li><strong>Out of seats?<\/strong> The invite waits in a queue instead of failing. We add the seat and it goes out on its own.<\/li>\n\n\n\n<li><strong>Who sees what.<\/strong> Shared folders and groups, so you can see which people reach which folders.<\/li>\n\n\n\n<li><strong>Activity.<\/strong> Sign-ins, sharing, people and settings changes, with a &#8220;risky only&#8221; filter and a CSV download.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Admins can change roles and remove people, but never an owner&#8217;s account or their own.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The rule we designed around: <strong>Rainier IT can&#8217;t see anything stored in your vault, and neither can the portal.<\/strong> Bitwarden encrypts every item on your own devices. What its API gives us is the bookkeeping: who&#8217;s a member, which groups exist, and a log of events. When the portal saves an event, it keeps what happened, when, and who was involved. An item only ever shows up as an id, and Activity names the shared folder, never the item:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>function eventRow(e) {\n  const k = (v) => v || '';\n  return {\n    event_key: `${e.date}|${e.type}|${k(e.actingUserId)}|${k(e.itemId)}|` +\n      `${k(e.memberId)}|${k(e.groupId)}|${k(e.collectionId)}|${k(e.policyId)}`,\n    type: e.type,\n    date: e.date,\n    acting_user_id: e.actingUserId || null,\n    member_id: e.memberId || null,\n    collection_id: e.collectionId || null,\n    group_id: e.groupId || null,\n    policy_id: e.policyId || null,\n  };\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">function<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">eventRow<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">v<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">v<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&#39;&#39;<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">event_key<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">`<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">date<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">type<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">actingUserId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">itemId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #ECEFF4\">`<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #ECEFF4\">`<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">memberId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">groupId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">collectionId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #A3BE8C\">|<\/span><span style=\"color: #81A1C1\">${<\/span><span style=\"color: #88C0D0\">k<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">policyId<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #81A1C1\">}<\/span><span style=\"color: #ECEFF4\">`<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">type<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">type<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">date<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">date<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">acting_user_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">actingUserId<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">null<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">member_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">memberId<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">null<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">collection_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">collectionId<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">null<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">group_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">groupId<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">null<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #88C0D0\">policy_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">e<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">policyId<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">||<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">null<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Each client&#8217;s Bitwarden API key is stored encrypted (AES-256-GCM), with the encryption key kept outside the database. And if anyone exports a vault, we get a ticket so we can check it was expected.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u26a1 Smaller things that add up<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>A quicker Overview.<\/strong> The tiles at the top are now links: Open tickets goes to your tickets, Outstanding balance to your invoices, Devices protected to your computer list.<\/li>\n\n\n\n<li><strong>Search everything.<\/strong> Press Ctrl+K (\u2318K on a Mac), or click Search, to jump to any device, ticket or help article.<\/li>\n\n\n\n<li><strong>&#8220;Get help with this computer.&#8221;<\/strong> A button on every device page opens a ticket with the computer name, serial number and last-seen time already filled in.<\/li>\n\n\n\n<li><strong>No more &#8220;Loading\u2026&#8221;.<\/strong> Pages show grey placeholders while your data arrives, and on a phone you can add the portal to your home screen so it opens like an app.<\/li>\n\n\n\n<li><strong>Feels right on a phone.<\/strong> Buttons and links react the moment you tap them, and wide tables scroll inside their box instead of pushing the page sideways.<\/li>\n\n\n\n<li><strong>Choose which emails you get.<\/strong> Under <strong>Settings \u2192 Notifications<\/strong>, switch ticket updates, invoices, security events and the Monday digest on or off.<\/li>\n\n\n\n<li><strong>Security work behind the scenes.<\/strong> We tightened how the portal checks who can see what, and nothing changes in how you sign in.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How we ship portal changes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Every change goes to a separate staging copy of the portal first, and has to pass a regression suite before it reaches production. The suite signs in as our own company, Rainier IT, and checks every page. It also makes sure one client can never see another client&#8217;s tickets, devices or files:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>== Client Portal regression: staging\n-- tenant isolation (must be refused)\n  PASS  #1 other client's ticket                                404\n  PASS  #2 reply on other client's ticket                       404\n  PASS  download-agent other client's site                      404\n  PASS  #6 alerts scoped (no foreign\/orphan)                    200<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color:#2e3440ff;color:#d8dee9ff\" tabindex=\"0\"><code><span class=\"line\"><span>== Client Portal regression: staging<\/span><\/span>\n<span class=\"line\"><span>-- tenant isolation (must be refused)<\/span><\/span>\n<span class=\"line\"><span>  PASS  #1 other client's ticket                                404<\/span><\/span>\n<span class=\"line\"><span>  PASS  #2 reply on other client's ticket                       404<\/span><\/span>\n<span class=\"line\"><span>  PASS  download-agent other client's site                      404<\/span><\/span>\n<span class=\"line\"><span>  PASS  #6 alerts scoped (no foreign\/orphan)                    200<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">It runs again against production after each release. Our own company is always the first client a new feature is tried on. Bigger features ship behind a switch, so on day one only we see them in production, and we widen it once we&#8217;ve used it ourselves. The new Overview went out like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly># Client Portal settings: who sees the new Overview\nP7_CLIENT_IDS=1          # day one: Rainier IT only\nP7_CLIENT_IDS=1,35,37    # an hour later, after our own review: every client<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #616E88\"># Client Portal settings: who sees the new Overview<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">P7_CLIENT_IDS<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">1          <\/span><span style=\"color: #616E88\"># day one: Rainier IT only<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">P7_CLIENT_IDS<\/span><span style=\"color: #ECEFF4\">=<\/span><span style=\"color: #D8DEE9FF\">1,35,37    <\/span><span style=\"color: #616E88\"># an hour later, after our own review: every client<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Coming next<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The next wave is designed and going through the same staging-first process, a few features at a time:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Same-day urgent fixes.<\/strong> When a flaw is on CISA&#8217;s list of vulnerabilities being actively exploited, the fix skips the waiting period and goes out that day, without forcing a restart.<\/li>\n\n\n\n<li><strong>Drive encryption status.<\/strong> BitLocker on or off for every computer. Recovery keys are backed up by us and never shown in the portal: a stolen portal password shouldn&#8217;t unlock a stolen laptop.<\/li>\n\n\n\n<li><strong>Hardware age and warranty.<\/strong> Age, warranty end date and a suggested replace-by quarter for each machine, plus a CSV export for budget planning.<\/li>\n\n\n\n<li><strong>Better tickets.<\/strong> A status timeline, the response-time target next to the actual time, drag-and-drop screenshots, and a quick rating when a ticket closes.<\/li>\n\n\n\n<li><strong>Forgot your password?<\/strong> A self-service reset link on the sign-in page. Lost your phone or authenticator app? That still goes through a phone call to us, on purpose.<\/li>\n\n\n\n<li><strong>Monthly health reports.<\/strong> One PDF per month in the portal: updates installed, security incidents, tickets closed and anything that needs attention.<\/li>\n\n\n\n<li><strong>Offboarding.<\/strong> When someone leaves, a client admin can remove their access from one screen: sign-in blocked everywhere, their computer locked, their files handed to a colleague, with a signed record of every step for HR.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udded Why we build this ourselves<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most of what&#8217;s in the portal comes from tools we already run: remote management, endpoint security, ticketing, billing and file sharing. Each has its own dashboard, and a client shouldn&#8217;t need to learn five of them. The portal pulls the parts that matter into one place, in plain English, with each client seeing only their own data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re a Rainier IT client, sign in at <a href=\"https:\/\/portal.rainier-it.com\">portal.rainier-it.com<\/a> to try it. If you&#8217;re not yet, and want IT that shows its work, <a href=\"https:\/\/rainier-it.com\/contact.html\">get in touch<\/a> or email support@rainier-it.com.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Rainier IT Client Portal now schedules updates automatically, with device pages, an at-a-glance Overview, Bitwarden passwords and Ctrl+K search.<\/p>\n","protected":false},"author":1,"featured_media":445,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,7,8],"tags":[35,47,40,41],"series":[],"class_list":["post-374","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices","category-it-management","category-managed-it-services","tag-cybersecurity","tag-monitoring","tag-patch-management","tag-small-business"],"_links":{"self":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/374","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/comments?post=374"}],"version-history":[{"count":3,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/374\/revisions"}],"predecessor-version":[{"id":391,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/374\/revisions\/391"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/media\/445"}],"wp:attachment":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/media?parent=374"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/categories?post=374"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/tags?post=374"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/series?post=374"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}