Cambios
Qué ha cambiado en los últimos parches. El más nuevo arriba.
RSShace 2 semanasThree tiers · 30-day Pro trial for every signup · Founders Program
4Nuevo3Cambiado
Three tiers · 30-day Pro trial for every signup · Founders Program
- Nuevo New Pro tier at $99/€99/£84/CA$134/MX$1849 per month. Same single-user feature set as Solo with 4× the Bob token allowance (8M/month). Sits between Solo and Team for operators who run Bob as their main surface.
- Cambiado Sign-up now starts a 30-day Pro trial automatically — no card, full Pro feature access including Bob. After 30 days you pick Solo, Pro, or Team. The "free for the first 100" cohort is closed to new signups; existing Founding-100 members keep their permanent free access.
- Nuevo Founders Program at /founders. Apply if you're still building your MSP — get a 90-day Pro trial (instead of 30) and an optional "free until your first paying customer" arrangement. Every application reviewed by hand within 5 business days.
- Nuevo Trial-end emails. We send a heads-up 7 days before, 1 day before, and on the day your trial expires — each with the link to pick a plan. The workspace flips to locked-status automatically once the trial is over; your data stays intact.
- Cambiado /pricing rebuilt as a three-card grid (Solo / Pro / Team) with Founders Program and Founding Members (50% lifetime discount for the first 100 paid signups) cards below. Currency switcher above repricing all three with one click.
- Cambiado /billing upgrade picker shows three cards instead of two; active-tier banner now recognises Pro alongside Solo and Team.
- Nuevo Landing page got two new sections — three short "Bob does X" use-case cards (quick invoice, customer lookup, assessment-to-quote) and a three-step "how it works" walkthrough above the feature list.
hace 3 semanasTeam time-sheet · /assistant is one page now
1Nuevo1Cambiado
Team time-sheet · /assistant is one page now
- Nuevo Team time-sheet at /time. Log billable hours per project — type them in yourself, or ask Bob ("log 2h on Acme for cabling"). Each entry carries date, hours, hourly rate, and an optional note; totals roll up per customer for invoicing. (DE/EN/ES)
- Cambiado /assistant is one page now. Pick a conversation from the sidebar and it opens in the right rail — no more full-page reload between conversation switches. Old /assistant/<id> links keep working (they redirect).
hace 3 semanasInvoices, workspace timezone, Network → Pro · big quality pass
2Nuevo2Cambiado3Arreglo1Security
Invoices, workspace timezone, Network → Pro · big quality pass
- Nuevo Invoices. Accept a quote, hit "Create invoice", get a numbered invoice ready to send. Gap-free numbering (RE-YYYY-NNNN), DIN-5008 layout, per-period VAT block, reverse-charge handling — all inherited from the quote PDF. Send as PDF in one click, mark paid; sent invoices lock against further edits. Structured e-invoice / ZUGFeRD output is the next step. (DE/EN/ES)
- Nuevo Workspace timezone setting. Workspace owners can pick the org's IANA zone in Settings → Workspace; the date on outgoing quote PDFs now pins to it, so a quote issued at 23:30 local doesn't print yesterday's date. Leave it on "Automatic" to derive from your Country. (DE/EN/ES)
- Cambiado Partner Network is a Pro feature now. A Free workspace clicking "Network" lands on /billing with a short explanation; Solo and Team get the directory + lead-forward flow as before.
- Cambiado Free tier is now capped at 3 quotes per month — Solo and Team stay unlimited. A small counter on the quote list shows what you've used, and the wall enforces at every create path (manual, from a Checkup, from the wizard auto-quote).
- Arreglo Big sweep — roughly 70 fixes across the app. Highlights: the customer portal no longer crashes on a project with task comments; the iOS app no longer hits a redirect loop after the trial ends; the embed and self-check questionnaires finally show their conditional follow-up questions (they were silently dropped); the email-send modal now surfaces a real error when delivery fails instead of pretending it worked; the AI summary overlay no longer hangs on a failed generation.
- Arreglo Checkup-derived quotes (the ones without a linked project) now show up everywhere they should — operator quote list, customer portal, share link, PDF and CSV export. They used to disappear silently when a project was deleted or when the quote came from a project-less Checkup.
- Arreglo PDF and portal dates render the right calendar day across timezones now. Audit dates on Checkup reports stay anchored to the day you picked in the date input, regardless of where you or your customer sit.
- Security Hardened the partner-network's lead-forwarding flow and tightened a few authenticated-session checks.
hace 3 semanasFixes - square app icon, cleaner changelog feed
1Cambiado1Arreglo
Fixes - square app icon, cleaner changelog feed
- Arreglo The PWA / home-screen / taskbar icon showed the wide MSP banner shrunk onto a white square, so it read as a tiny floating logo. It is now a proper square app icon — a green tile with the MSP mark centred. If your device still shows the old one, remove and re-add the app (OS icon caches are stubborn).
- Cambiado Each change in the /changelog RSS feed is now its own line with a kind marker (added / changed / fixed …) instead of one run-on paragraph — so Discord feed embeds and desktop RSS readers render it as a scannable list.
hace 3 semanasSettings rebuilt - collapsible sections, mobile & iOS-app polish
1Nuevo1Cambiado
Settings rebuilt - collapsible sections, mobile & iOS-app polish
- Nuevo Settings is now organised into collapsible sections — tap one to open it instead of scrolling a single long page. On desktop the sidebar still jumps straight to any section.
- Cambiado Settings got a mobile and iOS-app pass: bigger tap targets, no zoom-jump when you focus a field, safe-area spacing, a haptic tap when a change saves, and fields that scroll clear of the on-screen keyboard.
hace 3 semanasDark-mode color-safety audit · automated check + token rules
2Nuevo1Arreglo
Dark-mode color-safety audit · automated check + token rules
- Nuevo Dark-mode color-safety audit script (npm run check:darkmode). Scans every .astro/.tsx/.ts file for stock Tailwind palette uses (stone-, gray-, emerald-, rose- etc.) that have no paired dark: variant. Strict mode (check:darkmode:strict) exits non-zero, ready to wire into CI as a pre-build gate once the existing offender count drops.
- Nuevo Color-token rules documented as a tall comment block at the top of src/styles/global.css — the six rules covering surfaces, text, borders, inverted buttons, accent, and pills. Every developer (and AI assistant) touching styles sees the rules at the source-of-truth file.
- Arreglo Ticket system pages (/superadmin/tickets list + detail, /help/tickets list + thread, support FAB dialog) render correctly in dark mode — conversation bubbles, status pills, reply composers, and modal backdrops no longer leak white-on-white or black-on-black text.
hace 3 semanasCustomer support overhaul · ticket system v1 · in-app chat widget · /help hub
6Nuevo1Cambiado
Customer support overhaul · ticket system v1 · in-app chat widget · /help hub
- Nuevo Help & Support hub at /help — single discoverable entry point for docs, changelog, feedback, Discord community, and direct support. Replaces four separate AppNav entries with one card grid. Shows a count badge when you have open tickets.
- Nuevo Sticky support-chat widget in the bottom-right corner of every authenticated page. Click the bubble, write a subject + message, pick a category (Support / Billing / Privacy). Submits land instantly in /superadmin/tickets and trigger an operator notification email — no IMAP roundtrip, no page reload.
- Nuevo Customer-facing ticket views at /help/tickets (list of your own threads, sorted by last activity) and /help/tickets/[id] (full conversation with inline reply composer + "mark as resolved" option). Strictly isolated per user by from_email; cross-tenant access redirects to the list without leaking existence.
- Nuevo Built-in support ticket system in /superadmin/tickets. A background worker polls support@, billing@ and privacy@ inboxes every 60 seconds, ingests new mail as tickets, auto-tags by destination mailbox, and auto-links to a tenant when the sender email matches a known workspace.
- Nuevo Operator reply path supports both web and Outlook: the inline composer on /superadmin/tickets/[id] sends a threaded reply through noreply@mspercury.com (RFC 5322 In-Reply-To + References headers). Replying from the operator personal mailbox (l.flores@it-flores.de) is also recognised by the IMAP ingest and forwarded onward to the customer transparently.
- Cambiado Customer-facing email Reply-To moved from the operator personal inbox to support@mspercury.com. The mailbox forwards onward to the operator at the provider level, so the routing change is transparent to senders. Mentions in the blog and one-off operator replies updated to match.
- Nuevo Reply-blocklist for send-only / loop-prone addresses (noreply@, support@, billing@, privacy@). The reply UI shows a warning banner instead of accepting a reply that would silently bounce at the destination MTA. Prevents the most common operator foot-gun: replying to a smoke-test ticket whose from_email is noreply@.
hace 3 semanasPublic-CheckUp asks for phone too · stale items pruned from roadmap + known-issues
2Cambiado1Eliminado
Public-CheckUp asks for phone too · stale items pruned from roadmap + known-issues
- Cambiado Public-CheckUp contact form (DE/EN/ES) now requires a phone number alongside email. Operator feedback was that email-only leads were too easy to ignore on the prospect side; a number lets the MSP call back the moment a high-score lead lands. Applies to both /check/{slug}/questions and the iframe embed at /check/{slug}/embed/questions.
- Eliminado Stale entries pruned from /docs known-issues (DE/EN/ES): "5 MB iOS photo cap" (actual cap is 8 MB), "custom footer not in PDF yet" (renders since the May 2026 quote-PDF refresh), "no bulk customer import" (CSV import lives at /customers/import), "SVG logo breaks branding" (SVG is in the allowed-mime list), "AI ChatGPT path untested" (both Claude + OpenAI providers ship at parity).
- Cambiado Roadmap (DE/EN/ES) refreshed: Stripe direct-key integration moved from "Now (in flight)" to "Already shipped" — that one already lives at /settings/integrations. Public Read API + Webhooks slipped from Q2 to Q3 2026 to match reality. Native iOS app entry kept.
hace 3 semanasTiered pricing · Solo €29/mo · Team €49/mo · Mexican peso support
3Nuevo4Cambiado
Tiered pricing · Solo €29/mo · Team €49/mo · Mexican peso support
- Nuevo New "Solo" tier at €29/$29/CA$39/MX$549 per month, unlocking every Pro feature for single-operator MSPs (CRM, marketplace, branding, advanced reporting, AI with BYO key, multiple Public-CheckUp URLs, Stripe direct-key integration, API). Existing Pro features now start at Solo.
- Nuevo "Team" tier at €49/$49/CA$65/MX$929 per month — everything in Solo plus multi-user workspace (additional admin + member seats). Existing Pro subscribers at €49 are grandfathered onto Team via the migration.
- Nuevo Mexican peso (MXN) added as a supported billing currency across /pricing, /billing, and the Stripe checkout flow. Locale + CF-IPCountry pick MXN by default for Mexican workspaces.
- Cambiado /pricing rebuilt as a three-card layout (Free / Solo / Team) with a central currency switcher above the cards so a single click re-prices both paid tiers. FAQ updated to explain Solo vs Team and the Stripe Customer Portal tier-switch path.
- Cambiado /billing rebuilt: shows the active tier (Free / Solo / Team) with a status pill, two side-by-side upgrade cards for unsubscribed workspaces, and a "Manage subscription" link for active subscriptions (where the Stripe Customer Portal handles tier changes pro-rata).
- Cambiado Plan-gating helpers (`isPro` / `getPlan` / `getLimits` / `requirePro`) updated to recognise three tiers. `isPro` stays true for Solo + Team (so every pre-existing call-site keeps working). New `requireTeam` gate added for future multi-user features.
- Cambiado Stripe webhook now decodes the active price ID into a tier (Solo / Team) on every subscription event and writes it to `organizations.subscription_tier`. Tier changes via the Stripe Customer Portal are reflected within seconds of the event arriving.
hace 1 mesSignup is open · branded error pages · welcome tour · multi-admin lead alerts · per-invite question set
2Nuevo4Arreglo2Eliminado
Signup is open · branded error pages · welcome tour · multi-admin lead alerts · per-invite question set
- Eliminado Workspace-signup invite codes are gone. Anyone can create a workspace at /signup with email + PIN, no code required. The old gate was broken anyway — codes were never marked used, the beta-flag never propagated, and the gate was bypassable by POSTing the action URL directly. /superadmin/invites and /settings/invites pages were deleted.
- Nuevo Welcome modal on first signup now shows a 4-card feature tour (Public CheckUp, CheckUp wizard, Service catalog, Quotes + PDFs) above the setup form, each linking to the surface so you can click around before filling anything in. Listens for the canonical ?welcome=signup cue from the post-signup redirect (was ?welcome=1, which also triggers a fresh Google Ads conversion event).
- Nuevo Branded English error pages for /check/{slug}/* and /self-check/{token} when the link is dead or revoked. Replaces the bare-text "Diese Seite ist nicht verfügbar." 404 that prospects in EN/ES locales used to see. Inline-CSS, MSPercury logo, noindex.
- Arreglo Lead-alert emails (DE/EN/ES) now fan out to every admin in a multi-admin workspace, not just one inbox. Each admin's subject + body is rendered in their own preferredLanguage, matching the per-admin push-notification fan-out behaviour. Same for the new-lead push title and body — those were hard-coded German.
- Arreglo Customer self-check is now pinned to a specific question set at invite-time (DE/EN/ES). If you flip your default catalog after sending an invitation, the customer still sees the catalog you originally meant — no surprise mid-flight changes. Existing pending invitations keep the previous behaviour (fall back to the org default).
- Arreglo Operator flash messages + AI quote-draft titles localised across the leads, customers, customer-contacts, and AI surfaces (DE/EN/ES). Removed the leftover German strings that flashed on EN/ES workspaces ("Ansprechpartner aktualisiert.", "Bereits konvertiert.", "Lead im Marketplace veröffentlicht.", quote titles starting with "Angebots-Entwurf aus CheckUp", etc.).
- Arreglo Post-signup redirect chain collapsed: /signup/complete now lands directly on /dashboard?welcome=signup instead of bouncing through /onboarding?welcome=1. One redirect, correct cue, no wasted hops.
- Eliminado Dead defensive code around i18n key lookups: stripped the `t("nav.leads" as any) ?? "Leads"` fallback pattern in AppNav + the settings sidebar. The keys exist in every locale; the dead fallbacks had German strings ("Netzwerk", "CheckUp-Einstellungen") that would never activate but represented a latent silent-German risk.
hace 1 mesPublic pages default to English · redesigned changelog layout
2Cambiado
Public pages default to English · redesigned changelog layout
- Cambiado Every public surface (landing, /imprint, /legal/*, /pricing, /blog, /docs, /changelog, /feedback) now defaults to English when the visitor isn't signed in. The Accept-Language browser-locale auto-detect path was removed — a visitor who actively wants a different language uses the picker in the footer (English · Deutsch · Español) or appends `?lang=de` / `?lang=es` to the URL. The explicit pick persists across navigation via a dedicated marker cookie. Signed-in users keep their saved language unchanged.
- Cambiado /changelog layout reworked for both desktop and mobile. Desktop gets a wider canvas (~1152 px), a sticky year-jump rail on the left, and a year-header rhythm above the first entry of each year. Mobile stacks date + title with a short-date label and bigger tap targets. New sticky toolbar offers per-kind filter chips (Added / Changed / Fixed / Removed / Security with live counts), expand-all / collapse-all buttons, and a copy-link affordance per entry that writes the deep-link URL to the clipboard. Hash navigation (e.g. `#2026-05-12` from the RSS feed) now force-opens the linked entry and scrolls it into view.
hace 1 mesInline-expand forms moved into modals — no more layout-sprenger when adding contacts, catalogs, tasks
1Nuevo4Cambiado
Inline-expand forms moved into modals — no more layout-sprenger when adding contacts, catalogs, tasks
- Nuevo New reusable `<FormModal>` component (same `<dialog>`-based pattern as the existing EmailSendModal / OnboardingWizardModal / PdfModal). Trigger button + native modal, ESC + backdrop close, auto-reopen with an error banner if the previous submit returned a validation error, optional URL cancel-href for unwinding edit-state-in-URL.
- Cambiado Customer detail (/customers/[id]): "Add contact" + per-row "Edit contact" no longer expand inline and rip the card header apart. Both now open a proper modal. Same field set, same validation; the card layout stays put.
- Cambiado Settings → CheckUps (/settings/checkups): "New question set", "New landing", "Edit landing", "New question" (per category), "Edit question" (per row), "Rename set", "Reset set to defaults" all moved into modals. The question-editor list is now a clean read-only stream with hover-reveal Edit/Delete actions; the giant multi-locale form only takes up screen space when you actually need it.
- Cambiado Project detail (/projects/[id]): "Add task", "New service report", "Edit service report (draft)", "Propose maintenance window", "Edit maintenance window" all moved into modals. The Maintenance tab is now full-width with a single composer card above the list instead of a cramped left-column form that kept the right-column list narrow.
- Cambiado Settings → Integrations: Stripe key rotation moved into a modal.
hace 1 mesIndustry templates for the public CheckUp — law, tax, finance, healthcare
2Nuevo1Arreglo
Industry templates for the public CheckUp — law, tax, finance, healthcare
- Nuevo Four ready-to-use question sets when you create a new public-CheckUp catalog: Healthcare (medical practice / MVZ), Law firm, Tax / Accounting firm, Financial services. Each ships 29 questions in all three locales (DE/EN/ES) — the standard cross-industry set plus four sector-specific add-ons per template (retention rules, regulator / court-filing portals, secure client portals, confidentiality training). The Settings dropdown localises the template's display name to the operator's UI language; the underlying question text is trilingual.
- Nuevo Pick the workspace language on signup. The email step now has a DE / EN / ES flag picker; whichever you choose sets the workspace language and seeds the default CheckUp questions in that locale (DE/EN/ES). Changeable later in settings.
- Arreglo Creating a second question set silently 403'd for early-access workspaces — the form redirected to the Landings tab and the catalog never appeared. Plan-cap check now recognises superadmin + early-access correctly. Error banners surface real failures instead of silent redirects.
hace 1 mesHotfix: industry-template questions showed up as raw keys in the lead transcript + PDF
3Arreglo
Hotfix: industry-template questions showed up as raw keys in the lead transcript + PDF
- Arreglo Questions from the Healthcare / Law / Tax / Finance industry templates (DE/EN/ES) rendered as their internal keys — e.g. `patient_record_access_hc`, `bea_active_law` — in three places: the operator's lead-detail transcript, the prospect's emailed PDF report, and the AI quote-drafter context. Three read-side renderers were resolving question text against the Standard seed only; anything outside the Standard catalog fell back to the raw identifier. Resolution now walks the slug's assigned question set → any other set the workspace owns → the static seed union of all five catalogs. Prospect-facing PDFs are the most visible win.
- Arreglo Fix applies to all three locales (DE/EN/ES) at once — the resolver returns the full translation triple for every key and the call-site picks the active locale. English and Spanish workspaces that run the law / tax / finance / healthcare templates get the same correct rendering as German ones; no separate per-locale patch was needed.
- Arreglo Prospect-facing surfaces verified clean: the /check/{slug}/questions form (both standalone and embed variants) and the customer self-check at /self-check/{token} were already reading translations directly from the DB row, so they never hit the bug. The patch above only touches the three back-office / PDF / AI render paths that had been hard-coded against the Standard seed array.
hace 1 mesCheckUp settings unified, formal Sie in German, multiple question sets per workspace
4Nuevo2Cambiado1Arreglo1Security
CheckUp settings unified, formal Sie in German, multiple question sets per workspace
- Nuevo One home for all CheckUp settings at /settings/checkups with three tabs: Public landings, Question sets, Findings library. Replaces the scattered surfaces that used to live under public-checkup, questions, and findings separately. The old Findings entry was removed from the sidebar nav.
- Nuevo Multiple question sets per workspace (Pro). Name a catalog ("Healthcare campaign", "Retail audit"), assign it to one or more public-CheckUp URLs. Each URL can run its own question list — /check/your-msp-medical with 12 healthcare questions, /check/your-msp-retail with PCI-flavoured ones. Free stays at one catalog.
- Nuevo Clone a public-CheckUp landing in one click. The landings table now has a copy action that duplicates the slug + intro text + audience label + question-set assignment; you get a new draft URL ready to rename.
- Nuevo Leads count in the sidebar. The Leads nav item now shows the same red badge as Customers / Quotes, so unread leads are visible without opening the page.
- Cambiado Public-CheckUp wording (DE only) switched from informal "du" to formal "Sie" across all 63 default questions and tooltips. Existing prospect-facing copy on /check/[slug] now matches the tone most German MSPs use with their customers. English and Spanish translations were unaffected — they already used the formal address ("you" / "usted").
- Cambiado Self-CheckUp result page polish: the score number and the maturity badge no longer crowd each other on narrow screens (they stack on mobile, sit side-by-side on desktop). The "Back to home" button now goes to the MSP's own landing page if one is configured, instead of always returning to mspercury.com.
- Arreglo Active MSPs counter on the admin dashboard was over-counting — ghost organisations that never finished signup were being tallied. Counter now matches the actual paying-or-trialing workspaces. (Visible only to superadmin; reported by an operator who noticed the math didn't add up.)
- Security Hardened the password, passkey and 2FA login paths. No user action required.
hace 1 mesSignup friction crushed: email + PIN, done — workspace/password/2FA move into the wizard. Plus PIN login, passkey nudge, PIN-gated account deletion, tenant-branded public CheckUp, OG image + SEO overhaul
6Nuevo3Cambiado1Arreglo
Signup friction crushed: email + PIN, done — workspace/password/2FA move into the wizard. Plus PIN login, passkey nudge, PIN-gated account deletion, tenant-branded public CheckUp, OG image + SEO overhaul
- Cambiado Signup collapsed from three pages to two. Was: /signup (email) → /signup/verify (PIN) → /signup/complete (workspace + name + password + password-confirm + 2 consent checkboxes) → /dashboard. Now: /signup with inline consent ("By clicking Send code you agree to Terms + Privacy") → /signup/verify → /onboarding wizard. The `confirmEmailVerification` action creates the org + admin user the moment the PIN matches: workspace name derived from the email prefix (renamable in the wizard), passwordHash=NULL, consent timestamps stamped, session cookie minted. The friction layer that was killing Reddit-traffic conversion is gone.
- Nuevo Passwordless login on /login: new "Email me a sign-in code — no password needed" button next to the classic password form. The button posts to `startEmailVerification` and bounces to /signup/verify; `confirmEmailVerification` detects the existing user, mints a fresh session and lands on /dashboard. That keeps the PIN-only cohort (anyone who signed up post 2026-05-09 in the friction-reduced flow and hasn't set a password yet) able to get back in. The login action now returns a readable error for `passwordHash=null` accounts instead of "Invalid credentials".
- Cambiado Onboarding wizard is now a popup modal on the dashboard instead of a hard middleware redirect. The `enforceOnboarding` middleware is neutered (no-op); new `OnboardingWizardModal.astro` renders the full setup form (workspace + finance + branding + about) as a centred `<dialog>` with a backdrop, closeable via X / ESC / backdrop click. Auto-opens on first dashboard paint when `onboardingCompletedAt` is null; stays dismissible (soft nag) — ESC + Close don't change server state, the footer's "Maybe later" link explicitly sets `onboardingCompletedAt`. /onboarding standalone URL becomes a legacy redirect to /dashboard.
- Nuevo Password card at the top of /settings/security — single form, branched server-side on hasPassword. With `passwordHash=null` the UI shows "Set a password" with just New password + Confirm fields; the `changePassword` action now accepts `currentPassword` as optional and only verifies it when a hash already exists. On initial set the success notice reads "Password set — next login can use email + password OR keep using the email code". Plus a tooltip noting that a passkey is the phishing-resistant option vs a password. The existing /settings/password page is untouched (slated for consolidation into /settings/security).
- Nuevo Passkey-recommendation banner on the dashboard — small accent-tinted card pitching Touch ID / Windows Hello / Yubikey. Renders only when the user has 0 passkeys AND onboarding is done AND the `mspc_passkey_nudge_dismissed` cookie isn't set. Setup button links to /settings/security#passkeys; X sets a 365-day dismiss cookie. PIN-only signups now have an immediate path to hardware-bound passwordless sign-in once they finish (or skip) the wizard.
- Nuevo PIN-gated account deletion for passwordless accounts. /settings/account/delete now detects whether the user has a password set. If not, the password field is replaced with an "Email me a delete code" button; click fires the new `requestDeleteAccountCode` action, which sends a 6-digit PIN to the account email (15-minute TTL, 5 attempts, IP-rate-limited like the signup PIN flow). Once sent, the page reveals the PIN input plus the email-verbatim confirm. The `deleteAccount` action now accepts either `password` OR `pin`, branches on `passwordHash` state and verifies the PIN against the `email_verifications` table (same infra as signup, reused).
- Cambiado Public CheckUp /check/{slug}/* (standalone variant) now shows ONLY the MSP's branding, not MSPercury's. Before, the three pages (index/questions/result) wrapped themselves in `MarketingLayout` — leads saw the MSPercury logo, Pricing/Partners/Blog nav and the full MSPercury footer with Imprint/Terms/Privacy/DPA/Cookies links. New minimal `TenantPublicLayout.astro` shows only the org name (or uploaded logo) in the header and a tiny "Powered by MSPercury" footer link. Plus `noindex,nofollow,noarchive` so per-MSP slug URLs don't rank on the MSPercury domain. The embed routes were already clean.
- Nuevo Open-Graph image (1200×630) plus square variant (1200×1200) generated via Sharp from `public/og.svg`. Full meta-tag overhaul in `MarketingLayout.astro`: og:image:secure_url + type + alt, twitter:domain + url + image:alt, application-name, apple-mobile-web-app-* suite, format-detection (no auto-tel linking), referrer policy strict-origin, DNS-prefetch + preconnect for googletagmanager, theme-color split light/dark. The English landing SEO is decoupled from DE/ES: title + description rewritten around the US/Canada Google Ads messaging (MSP CRM, quoting, lead tracking, no spreadsheets, free tier), GDPR / EU-hosted language stripped. JSON-LD now carries alternateName + dual applicationCategory + a curated featureList + locale-aware priceCurrency (USD for EN).
- Arreglo Multiple DE-string leaks in the EN UI fixed. Dashboard MRR chart showed "Projekte (einmalig)" hardcoded across every locale; now three i18n keys (`chartOneTime`, `chartLblOneTime`, `chartRangeMonths`) DE/EN/ES. Range toggle buttons ("3 / 6 / 12 Monate") now go through the template-i18n. AiOverlay component (used everywhere): aria-label "Schließen", Cancel + Error-Close strings switched to locale-aware via SSR front-matter; inline-JS error strings for the local-AI path via an injected `window.__mspcAiI18n` bag (DE/EN/ES). Plus: dashboard 500 ReferenceError fixed (`isDe`/`isEs` were never declared at the top of the page), Checkup AI-tasks modal localised, Quotes AI-reply-draft overlay localised via define:vars. Settings/admin customer-edit had a DE-example address placeholder (`Hauptstraße 1`), now US-shaped (`1500 Market St`).
- Nuevo New patchnote RSS feed at `/changelog/rss.xml` — pre-rendered, locale-aware (defaults English), newest entry first. Up to seven bullets per entry summarised into the `description` field. Mirrors the same `@astrojs/rss` pattern the blog feed at /blog/rss.xml uses.
hace 1 mesMehrere Ansprechpartner pro Kunde + Self-Check-Einladung per Token an einzelne Kontakte
6Nuevo
Mehrere Ansprechpartner pro Kunde + Self-Check-Einladung per Token an einzelne Kontakte
- Nuevo Mehrere Ansprechpartner pro Kunde. Statt einem Single-Contact-Feld auf der customers-Row (contactPerson + email) gibt es jetzt eine eigene customer_contacts-Tabelle mit beliebig vielen Kontakten je Kunde — jeder mit Name, E-Mail, Telefon, Rolle (IT-Leitung / Geschäftsführung / Buchhaltung …) und Notizen. Auf der /customers/[id]-Seite eingebettet als kollabierbare Liste mit Add/Edit/Delete-Forms; ein Eintrag kann als Hauptkontakt markiert werden. Lazy-Backfill: beim ersten Öffnen wird der bestehende customers.contactPerson + customers.email als erste Kontakt-Row angelegt — keine Daten gehen verloren, alte Reads funktionieren weiter.
- Nuevo Token-gegate Self-Check-Einladung. Pro Ansprechpartner mit E-Mail-Adresse zeigt die Kontakt-Liste einen Self-Check-senden-Button. Klick erzeugt einen 30-Tage-gültigen Token, persistiert eine customer_self_assessment_invites-Row und schickt eine E-Mail an den Kontakt mit dem Subject: customerName lädt Sie zum IT-Selbstcheck ein. Die Mail ist im Branding des MSP gerendert (Wordmark + Footer = workspace name, nicht MSPercury). Optionale Operator-Opener-Nachricht wird oberhalb des CTA als italic-Block eingefügt.
- Nuevo Public-Page /self-check/{token} drei-stufig: Welcome → Questions → Done. Vor-pop-up keine E-Mail-Re-Erfassung, da Customer schon bekannt. Locale-aware aus invite.locale. Mit ?step=questions / ?step=done query-state. Submit erzeugt eine checkups-Row mit status=draft, notes=JSON mit Score und Antworten, plus Push-Notification an alle Workspace-Admins.
- Nuevo Submit-Action submitSelfAssessment validiert Token (existence + nicht-completed + nicht-expired), parst Antworten, computet Score, legt CheckUp-Row an, markiert Invite als completed mit completed_checkup_id. Idempotent: zweiter Submit auf dieselbe Invite returnt success-shape ohne Duplikat-CheckUp.
- Nuevo Invite-History-Block auf der Kunden-Detailseite. Pro Eintrag: E-Mail, Versanddatum, Status (offen / abgelaufen / abgeschlossen). Offene Invites haben Link-kopieren + Widerrufen-Buttons. Completed-Invites haben einen Link auf den resultierenden CheckUp.
- Nuevo Drizzle-Migration 0005 legt zwei neue Tabellen an: customer_contacts und customer_self_assessment_invites. FK-Cascades sauber: Customer-Delete cascadet auf Contacts und Invites; Contact-Delete setzt invite.contact_id auf NULL; CheckUp-Delete setzt invite.completed_checkup_id auf NULL.
hace 1 mesMehrere maßgeschneiderte Public-CheckUp-Landingpages pro Workspace (Pro-Feature) mit per-Slug Frage-Filter und Lead-Attribution
5Nuevo2Cambiado
Mehrere maßgeschneiderte Public-CheckUp-Landingpages pro Workspace (Pro-Feature) mit per-Slug Frage-Filter und Lead-Attribution
- Nuevo Pro-User können jetzt mehrere /check/-URLs pro Workspace betreiben — eine pro Zielgruppe. Schema: .unique() auf public_checkup_slugs.organization_id gedroppt, drei neue per-Slug-Spalten ergänzt (name für den internen Operator-Label wie "Healthcare-Kampagne", audience_label für sichtbares "Speziell für Arztpraxen", question_keys_json als JSON-Array zum Einschränken des Frage-Sets pro Slug). Plus prospect_leads.source_slug_id zur Lead-Attribution. Migration 0004_multi_slug_public_checkup.sql ist additiv-only mit IF-NOT-EXISTS-Guards plus Backfill der bestehenden Single-Slug-Rows auf name='Default'.
- Nuevo Plan-Limits: Free behält den Cap auf 1 Slug pro Workspace; Pro hat unlimited. Ein neues publicCheckupCustomQuestionSet-Flag erlaubt Pro zusätzlich pro Slug ein eingeschränktes Frage-Set (z.B. nur die 12 Healthcare-relevanten Fragen für die /check/dein-shop-medical-Variante statt aller 30). Validation server-side stripped die Filter-Daten bei Free-Submits stillschweigend, kein 403.
- Nuevo Settings → Public-CheckUp komplett umgebaut: statt einem Single-Slug-Editor jetzt eine Liste aller Slugs als Cards mit Link, iframe-Snippet und kollabierbarem Edit-Form pro Slug. Plus "Neue Landingpage anlegen"-Block am Ende, Pro-gated wenn Limit erreicht — zeigt sonst einen Upgrade-Pitch. Frage-Set-Filter ist als Checkbox-Picker pro Slug eingebaut: scrollbare Liste aller Workspace-Fragen, Häkchen setzen, Hidden-JSON-Input wird beim Submit autosynchronisiert.
- Nuevo Lead-Attribution: jeder neue Lead trägt jetzt die source_slug_id der Landingpage, über die er reingekommen ist. Damit kannst du im /leads-Inbox nach Kampagne filtern. Bei Slug-Löschung bleibt die ID erhalten als toter Verweis (kein CASCADE), die Lead-Karte rendert dann "(deleted slug)" statt des Kampagnennamens — historische Daten gehen nie verloren.
- Nuevo Question-Set-Sicherheit: bei einem aktiven Filter pro Slug werden Submit-Antworten server-side auf die im Filter erlaubten Keys reduziert + die Score-Berechnung läuft nur auf der gefilterten Subset. Damit kann ein Angreifer nicht via tampered Form-Payload Antworten zu Fragen einreichen, die der Visitor real nie zu sehen bekam — sonst wäre der Score über die Filter-Schwelle manipulierbar gewesen.
- Cambiado Pricing-Page Pro-Feature-Liste erweitert um Mehrere Public-CheckUp-URLs pro Workspace plus Stripe-Integration auf eigenem Konto. FAQ-Eintrag in DE/EN/ES ergänzt mit Use-Case-Beispielen.
- Cambiado Features-Doku auf docs.mspercury.com (DE/EN/ES) bekommt einen neuen Abschnitt Mehrere Public-CheckUp-URLs pro Workspace direkt unter dem Standard-Public-CheckUp-Block, mit Beispiel-URLs für Healthcare/Retail/Legal und Erklärung des Frage-Filters.
hace 1 mesStripe-KB-Artikel + AGB komplett überarbeitet (monatlich kündbar, kein Mindestlauf, Beta-Schutzklauseln) + Datenschutz mit allen Sub-Auftragsverarbeitern (Hetzner / Stripe / NinjaOne / BYO-AI / Apple / Google), alles trilingual
2Nuevo2Cambiado
Stripe-KB-Artikel + AGB komplett überarbeitet (monatlich kündbar, kein Mindestlauf, Beta-Schutzklauseln) + Datenschutz mit allen Sub-Auftragsverarbeitern (Hetzner / Stripe / NinjaOne / BYO-AI / Apple / Google), alles trilingual
- Nuevo Neuer Knowledgebase-Artikel „Stripe-Integration & Kundenabrechnung" auf docs.mspercury.com (DE/EN/ES, order=3.7). Zehn Abschnitte mit Hints + Tooltips: Stripe-Konto vorbereiten + Stripe-Tax aktivieren + Restricted-Key statt Secret-Key, Workspace- und Kunden-Steuerstammdaten, Schritt-für-Schritt Quote→Stripe-Push, Mapping-Tabelle der Periode-Typen, Reverse-Charge bei EU-B2B mit Beispielen, Tropezones-Tabelle (häufige Fehler + Behebung), klare Abgrenzung „was MSPercury macht / nicht macht", Roadmap. Markdown mit Frontmatter-Order (3.7), wird automatisch in der Docs-Nav zwischen Public-CheckUp und Known-Issues einsortiert.
- Cambiado AGB komplett überarbeitet auf das aktuelle Free+Pro-Pricing-Modell. Pro €49 / $49 / CA$65 monatlich — explizit „keine Mindestlaufzeit, monatlich kündbar zum Ende des laufenden Abrechnungsmonats" (Ziffer 5). 14-tägige kostenfreie Probezeit ohne Card on signup. Founding-100-Cohort dauerhaft Free, mit Garantie dass Preisänderungen am Pro-Plan diese Plätze nicht zwangsweise deaktivieren (Ziffer 4.1+4.4). Beta-Status-Disclaimer als eigene Ziffer 3 mit Hinweisen auf Funktionsänderungen, Bug-Fix-Priorität und Backup-Verantwortung. Neue Acceptable-Use-Klausel (Ziffer 12) gegen Spam, Phishing, Malware-Distribution, Reverse-Engineering. BYO-API-Key-Verantwortlichkeit klar geregelt: Operator haftet für Stripe/Anthropic/OpenAI-Konfigurationen + Kosten + Compliance. Haftungsbegrenzung verschärft: dreifacher Monatsbetrag pro Schaden, mind. 100 €; ausdrücklich ausgeschlossen sind Datenverluste bei nicht-erfüllter Backup-Pflicht, KI-Output-Schäden, indirekte Schäden, Beta-Phase-Beeinträchtigungen ohne Vorsatz/grobe Fahrlässigkeit. Spanische Fassung neu ergänzt (vorher fehlend, fiel auf EN zurück).
- Cambiado Datenschutzerklärung um alle aktuellen Sub-Auftragsverarbeiter erweitert: Hetzner mit detailliertem Zweck (VPS + Postgres + SMTP-Relay über mail.your-server.de + Storage-Box-Off-site-Backup), NinjaOne (Server-Monitoring + Patch-Management, EU-US-DPF-zertifiziert), Stripe in zwei separaten Rollen (a) MSPercury-Subscription-Billing (b) MSP-eigene Stripe-Integration für Kundenrechnungen — wichtige Klarstellung dass der MSP in Fall (b) selbst Verantwortlicher ggü. Stripe ist und wir nur transportieren. Anthropic / OpenAI / Ollama / OpenAI-kompatibel als BYO-Key-Provider mit explizitem Datenfluss pro AI-Funktion (was wann an wen geht: Executive-Summary, Quote-Drafter, Lead-Outreach, Quote-Reply, Service-Report u.a.). Apple bleibt für iOS-Distribution. Google Ads nur auf Marketing-Landing nach Cookie-Consent. Drittland-Übermittlung (Section 6) erweitert. Spanische Fassung neu ergänzt (vorher fehlend).
- Nuevo Neuer Sub-Abschnitt 5a „Datenfluss bei BYO-AI-Funktionen" in der Datenschutzerklärung, der pro AI-Feature transparent macht welche Felder an den konfigurierten AI-Provider geschickt werden. Bei Self-hosted-Endpoints (Ollama auf eigenem Server) verlässt nichts das Operator-Netz; bei Cloud-Providern gelten deren AVV-Bestimmungen. AI-Funktionen sind komplett deaktivierbar via Einstellungen → AI → Provider auf „—".
hace 1 mesCohorts-500 gefixt + Country-aware VAT/USt-IdNr/EIN/GST-HST in Angeboten, Rechnungen und Stripe-Push
4Nuevo1Arreglo
Cohorts-500 gefixt + Country-aware VAT/USt-IdNr/EIN/GST-HST in Angeboten, Rechnungen und Stripe-Push
- Arreglo /superadmin/cohorts warf 500. Ursache: postgres.js kann ein JS-Date nicht direkt durch ein raw sql\\`...\\`-Template-Literal serialisieren — der Drizzle-typed gt()-Operator löst das in .where(), raw-SQL-Strings nicht. Fix: earliestCohort.toISOString() mit explizitem ::timestamptz-Cast in den beiden raw-SQL-Blöcken (CTE-Self-Join für Aktivitäts-Grid + signup-Aggregat). Selbe Bug-Klasse hatte uns bei der Postgres-Migration mehrfach erwischt; Inline-Code-Comment dokumentiert den Trade-off.
- Nuevo Country-aware Tax-ID-Handling für Angebote + Rechnungen. Kunde + Workspace haben jetzt je country (ISO-3166-1 alpha-2) und tax_id_type (Stripe-aligned: eu_vat/us_ein/ca_gst_hst/ca_qst/gb_vat/ch_vat/au_abn/ae_trn/...). Bisher rendete die Quote-PDF immer ein hartcodiertes USt-ID — jetzt wechselt das Label automatisch auf den Begriff den die Behörde im jeweiligen Land erwartet (USt-IdNr für DE, VAT für andere EU-Länder, EIN für USA, GST/HST für Kanada-Bund, QST für Quebec, …). Per-locale-i18n: deutsche Operatoren sehen USt-IdNr., englische VAT ID, spanische NIF/IVA. Auto-Default vom Land: pickst du DE, springt der Type-Picker automatisch auf eu_vat; pickst du US, auf us_ein. Mehrere kanadische PSTs sind als Override verfügbar (BC/MB/SK).
- Nuevo Quote-PDF zeigt die Kunden-Steuer-ID jetzt in der Bezugszeichenzeile (DIN 5008-konform), die Workspace-Steuer-ID weiterhin im Page-Footer — beides mit dem gleichen country-aware Label. Bei Empfängern in einem anderen EU-Land wird oben über den Posten ein gelb umrandeter Reverse-Charge-Banner gerendert mit Verweis auf Art. 196 MwSt-RL / §13b UStG, in der Kundensprache. Wird automatisch unterdrückt bei innerdeutscher (gleiches Land) oder Drittland-Lieferung.
- Nuevo Stripe-Push (createStripeInvoiceFromQuote) hängt Adresse + tax_id_data an die Stripe-Customer-Erstellung. Damit kann Stripe-Tax die richtige Jurisdiktion auflösen (DE → 19% MwSt, EU-cross-border-B2B → 0% mit Reverse-Charge-Annotation, US → state-level sales tax). Bei bereits existierendem Stripe-Customer wird die Adresse synchronisiert und neue Tax-IDs nachgereicht via customers.createTaxId(), ohne Duplikate zu erzeugen. Strukturierte Adresse (line1/city/postal_code/country) statt der freitext-address-Spalte, damit Stripe-Tax sauber arbeitet.
- Nuevo Customer-Edit + -Create-Form bekommen Country-Dropdown (DACH + US/CA + UK gepinnt oben, Rest A-Z) und Tax-ID-Type-Dropdown. JS auto-fillt den Type wenn das Land geändert wird und der Type leer oder vom alten Standard war. Settings → Workspace genauso für die MSP-eigenen Daten. Drizzle-Migration 0003_add_country_tax_id_type.sql (4 ALTERs, additiv-only).
hace 1 mesStripe-Architektur korrigiert: direkter API-Key statt „on-behalf-of" Connect, end-to-end Quote→Invoice
2Nuevo1Cambiado1Eliminado
Stripe-Architektur korrigiert: direkter API-Key statt „on-behalf-of" Connect, end-to-end Quote→Invoice
- Cambiado Stripe-Integration komplett neu gedacht. Statt Stripe Connect Express („MSPercury rechnet on-behalf des MSP ab") läuft jetzt der saubere Direct-API-Key-Pfad: der MSP trägt unter Einstellungen → Integrationen seinen eigenen Stripe-Secret- oder Restricted-Key (sk_*/rk_*) ein, MSPercury verschlüsselt ihn AES-256-GCM at rest (gleiche Helper wie für TOTP- und AI-Keys) und ruft stripe.invoices.create() direkt gegen das MSP-Konto auf. Geld fließt zwischen MSP und Endkunde — MSPercury sieht nie Geld, weder als Treuhänder noch als „Plattform". Kein Stripe-Connect-Onboarding-Flow, keine Express-Account-Erstellung, kein „on-behalf"-Header mehr. Konzeptionell wesentlich sauberer und in der Praxis flexibler: jeder MSP, der bereits Stripe nutzt, bringt seinen Account direkt mit.
- Nuevo End-to-End Quote→Stripe-Invoice live. Auf jedem akzeptierten Angebot taucht jetzt — sofern Stripe verbunden ist — ein violetter Block „Stripe-Rechnung erstellen" auf, mit Zahlungsfrist (default 14 Tage) und „Sofort schicken"-Checkbox. Klick erzeugt: 1) Stripe-Customer auf dem MSP-Konto (find-by-metadata oder neu anlegen, getaggt mit mspercury_customer_id), 2) ein InvoiceItem pro MSPercury-Quote-Line-Item mit Beschreibung + Stückpreis + Menge, 3) eine Stripe-Invoice mit collection_method=send_invoice und einem Footer „MSPercury reference: Q-2026-XXXX". Bei aktiver Sofort-Versand-Checkbox wird zusätzlich finalizeInvoice() + sendInvoice() gerufen; Stripe schickt die Hosted-Invoice-Mail aus der eigenen Stripe-Adresse. Tenant-Isolation strikt: Quote, Customer und Line-Items werden alle auf ctx.locals.organization.id re-geladen, der Stripe-Key wird pro Request frisch entschlüsselt (kein Modul-Cache).
- Nuevo Verbindungsverwaltung in /settings/integrations: Restricted-Key-Empfehlung mit Scope-Hinweis (Customers Write + Invoices Write), automatische Erkennung von Test-vs-Live-Modus aus dem Key-Prefix, Account-Display-Name + Account-ID werden via accounts.retrieve() direkt nach dem Paste gefetcht und gecached. Test-Connection-Button ruft erneut accounts.retrieve() und aktualisiert das „last verified"-Timestamp; Disconnect-Button löscht alle Felder. Test-Mode-Warnung wird prominent angezeigt, damit niemand versehentlich Test-Rechnungen an echte Kunden schickt. Pro-only, Admin-only, alle Felder verschlüsselt.
- Eliminado Alte Stripe-Connect-Foundation entfernt: src/actions/stripe-connect.ts, /api/stripe/connect/return.ts, der account.updated-Webhook-Handler und die Connect-Account-Onboarding-UI sind weg. Die Drizzle-Spalten stripe_connect_account_id + stripe_connect_charges_enabled aus Migration 0001 bleiben dormant in der DB (additive-only Migration-Disziplin) und werden in einer späteren Cleanup-Migration gedroppt. Roadmap (DE/EN/ES) auf docs.mspercury.com angepasst — „Stripe Connect" durch „Stripe-Integration (eigener Account, kein on-behalf)" ersetzt.
hace 1 mesi18n-Audit: Findings-Library, CheckUp-Wizard, PDF-Report — keine deutschen Enum-Werte mehr für EN/ES-Tenants
5Arreglo
i18n-Audit: Findings-Library, CheckUp-Wizard, PDF-Report — keine deutschen Enum-Werte mehr für EN/ES-Tenants
- Arreglo Findings-Library-Editor zeigte für EN- und ES-Workspaces die Priority/Effort-Dropdowns mit deutschen Werten („hoch / mittel / niedrig") an, obwohl alle Labels und Buttons sonst lokalisiert waren. Ursache: die Werte sind in der DB kanonisch deutsch (FINDING_PRIORITIES = [„hoch",„mittel",„niedrig"]) und wurden 1:1 als Option-Labels gerendert. Fix: drei neue Helper localizePriority / localizeEffort / localizeTaskPriority neben dem bestehenden localizeCategory in lib/checkups/wizard.ts, plus i18n-Schlüssel checkup.priorities.*, checkup.efforts.*, checkup.taskPriorities.* in DE/EN/ES.
- Arreglo Gleicher Bug auf der Findings-Library-Listenseite — Filter-Pills und Item-Chips zeigten rohe deutsche Kategorie-Strings („Sicherheit", „Berechtigungen", „Sonstiges") und Priority-Badges („hoch", „mittel", „niedrig") für nicht-deutsche Operatoren. Im CheckUp-Wizard-Review (/checkups/wizard/.../review) ebenso: Priority-Chip + Effort-Inline-Text + Add-Finding-Dropdowns. Alles auf die neuen Helper umgestellt.
- Arreglo CheckUp-PDF-Report (kundenseitiges PDF!) leakte deutsche Priority/Effort-Werte in den Findings-by-Category-Listen, Risiko-Matrix-Achsenbeschriftungen und im Anhangs-Tabelle. Ist ein WeasyPrint-Worker, hat keinen Zugriff auf die Request-t()-Funktion — Lösung: per-Locale-Maps direkt im PDF-Template (PRIORITY_LABELS, EFFORT_LABELS, PDF_CATEGORY_LABELS), gespiegelt zur i18n-Datei. Plus Spanisch-Übersetzungen für alle Cover-Page-, TOC-, Methodology-, Appendix-Strings, die vorher beim ES-Locale auf Englisch zurückfielen (CheckUp-Bericht / Audit-Datum / Inhalt / Risiko-Matrix / Anhang etc.).
- Arreglo Inline-CheckUp-Findings-Form (CheckupFindingsForm.astro) — Vanilla-JS-Island, das Card-für-Card die Findings rendert — hatte die gleichen rohen deutschen Werte in allen Dropdowns + Priority-Chips. Server-side label-Maps werden jetzt via define:vars ins Script injiziert; priorityChip(...) + categorySelect + priSel + effSel benutzen sie.
- Arreglo AI-generierte Tasks (Tier-1G-CheckUp-zu-Tasks) zeigten ihre priority-Property im Operator-UI als rohe englische Werte „high / medium / low" — auch im DE-Workspace. Eigene Lokalisierungsschicht via checkup.taskPriorities.*, da das Enum unabhängig vom Findings-Schema-Enum (DE) ist (LLM-Output).
hace 1 mesStripe Connect-Foundation, Roadmap-Refresh, Lexware/Polar/sevDesk-Pipeline
3Nuevo1Cambiado
Stripe Connect-Foundation, Roadmap-Refresh, Lexware/Polar/sevDesk-Pipeline
- Nuevo Stripe Connect (Phase 1) — Schema, Actions, Webhook-Hook und Settings-Seite stehen. Unter Einstellungen → Integrationen können Pro-Workspaces ihr eigenes Stripe-Konto via Express-Onboarding verbinden, MSPercury stellt danach Kundenrechnungen und -Subscriptions on-behalf aus. Auszahlungen gehen direkt aufs MSP-Konto, Stripe übernimmt die komplette USt-Logik (DE 19 %, EU-Reverse-Charge mit USt-IdNr., 0 % Drittland). Tenant-Isolation strikt: Connect-Account-ID lebt pro Org-Row, Webhook-Handler und Return-Callback gleichen sie bei jedem Event gegen die signed-in-Workspace ab — kein cross-tenant-Leak möglich. Onboarding-Status-Pill (Bereit / Stripe prüft / Onboarding offen / Nicht verbunden) plus Express-Dashboard-Login-Link plus Disconnect-Knopf.
- Nuevo Roadmap auf docs.mspercury.com (DE/EN/ES) komplett refresht. „Jetzt" ist jetzt Public Read API + API-Keys, Stripe Connect, Webhooks, native iOS App. „Nächst" ist Per-Tenant-DB-Snapshot+Restore, Cohort-Heatmap-Drilldown, AEO/GEO-SEO-Push. „Später" listet Lexware Office, sevDesk, Polar.sh, DATEV-Schnittstelle, FastBill/Billbee/Faktura+ und ein paar weitere Long-Tail-Wünsche. „Bereits umgesetzt" enthält das volle Mai-2026-Inventar — Pricing-Modell, Partner-Netzwerk + Marktplatz, KI-Tier 1A–1G, Lead-Gen + Marketing, Customer-Branding, Workspace/Quotes/CheckUps, Auth/Security, Operations.
- Cambiado Settings-Sidebar hat einen neuen Eintrag „Integrationen" zwischen „Specialty-Profil" und Superadmin-Block. Sub-Label „Stripe Connect · API" macht klar wo es hingeht. Aktuell nur Stripe Connect; Public Read API + Webhooks landen in derselben Page sobald sie shippen.
- Nuevo Drizzle-Migration 0001_add_stripe_connect.sql committed: zwei neue Spalten auf organizations (stripe_connect_account_id, stripe_connect_charges_enabled). Konflikt-frei mit dem bestehenden Stripe-Customer-/Subscription-Setup für die MSPercury-Pro-Subscription — Connect bezahlt der KUNDE des MSPs, die Pro-Subscription bezahlt der MSP.
hace 1 mesPublic-CheckUp ohne PIN-Gate, AI-Features mit BYO-Key, Beta-Hinweis, Cohort-Heatmap
4Nuevo2Cambiado1Eliminado
Public-CheckUp ohne PIN-Gate, AI-Features mit BYO-Key, Beta-Hinweis, Cohort-Heatmap
- Cambiado Public-CheckUp-Funnel: das PIN-Eingabe-Schritt nach der E-Mail ist weg. Lead tippt Adresse, klickt „CheckUp starten“, landet direkt bei den Fragen — keine 6-Stellen-aus-dem-Postfach-tippen-Friction mehr. Anti-Spam-Floor weiterhin in Place: 3 Starts/h pro E-Mail, 10 Starts/h pro IP, plus die natürliche Friction der 20 Fragen + Privacy-Consent am Submit. Alte /pin-URLs in gecachten E-Mails forwarden sauber zur richtigen Stelle.
- Nuevo AI-Features dokumentieren ihren Bring-your-own-Key-Ansatz jetzt prominent auf der Landingpage. Anthropic, OpenAI oder beliebiger OpenAI-kompatibler Endpoint (Ollama, vLLM, LiteLLM, Self-Hosted-LLM-Proxy) — kein Token-Markup auf MSPercury-Seite, kein Vendor-Lock-in. Wer kein Modell hinterlegt, läuft im Klassik-Modus ohne KI.
- Nuevo Beta-Hinweis-Banner auf /login und Dashboard: erinnert dezent daran, dass wir während der Beta fast täglich kleine Fixes shippen — kurze Unterbrechungen können passieren. Per-Device dismissable, Default sichtbar bis zum ersten Klick auf X.
- Cambiado Partner-Netzwerk und Lead-Marktplatz sind jetzt klar als künftige Pro-Features markiert (Sidebar-Tag „Bald · Soon“, Banner oben in /network/*, Tag in der Marktplatz-Card auf /leads/[id]). Während der Beta für alle freigeschaltet — der Pro-Gate kommt mit dem GA-Pricing.
- Nuevo Superadmin → Cohorts ist nicht mehr „Coming Soon“: Retention-Heatmap pro Signup-Kohorte (12 Wochen × 12 Offset-Wochen) mit Week-0-Activation und Week-4-Retention KPIs oben drüber. CSV-Export an Bord für Board-Decks.
- Eliminado Pricing-Modell-Migration ist fertig: PWYW („pay what you want“)-Reste sind aus dem User-facing Surface raus. /superadmin/pwyw bleibt für historische Pledges erreichbar, ist aber nicht mehr in der Sidebar.
- Nuevo Multi-Region-Hreflang: Marketing-Layout liefert jetzt zusätzlich zu en/de/es auch en-US, en-CA, de-DE, es-ES und es-MX an die Suchmaschinen aus — eigene SERPs für die Märkte, die wir aktiv targeten, derselbe Content-Pfad pro Sprache.
hace 1 mesPublic-CheckUp-Embed-Bugfixes, Bell auch auf Mobile + Lead-Stream, neue Push-Surface „newLead", iframe-Snippet auf /leads, Embed-Quelle automatisch getaggt
6Nuevo3Cambiado6Arreglo
Public-CheckUp-Embed-Bugfixes, Bell auch auf Mobile + Lead-Stream, neue Push-Surface „newLead", iframe-Snippet auf /leads, Embed-Quelle automatisch getaggt
- Arreglo Public-CheckUp-Iframe lief in einer Endlosschleife: nach Email + PIN landete der Besucher wieder auf dem Email-Step. Ursache war doppelt: (1) der signierte PIN-Cookie hatte `SameSite=Lax`, also wurde er von modernen Browsern in iframe-Kontext (= Drittanbieter) gar nicht mehr mitgeschickt — die `/embed/questions`-Seite sah kein Cookie und redirectete zurück. (2) Selbst nach erfolgreichem Submit wurde der User wieder auf Schritt 1 geworfen, weil die `submitPublicCheckup`-Action den Cookie am Ende absichtlich löscht (Single-Use), aber der Page-Handler den Cookie-Check VOR dem Submit-Result-Check laufen ließ — der Erfolgs-Redirect zum Result wurde nie erreicht. Beide Fixes: (1) Cookie auf `SameSite=None; Secure` in Prod (Lax bleibt als Dev-Fallback, weil `None` über HTTP silent dropped wird), (2) Page-Handler-Reihenfolge gedreht: Submit-Result wird zuerst geprüft, Cookie-Gate erst danach. Gilt analog für UTM-Cookie und Lead-Detail-Seite (Delete-Action löscht den Lead-Row → 404 statt Redirect-zur-Liste, gleicher Reihenfolge-Bug).
- Arreglo PIN-Eingabe im Iframe-Embed wurde mit „Bitte halten Sie sich an das vorgegebene Format" abgewiesen, sobald iOS-Autofill oder Copy-Paste ein Leerzeichen mitbrachte. Das Eingabefeld hatte `pattern="\d{6}"` als Native-Browser-Validierung, der Server akzeptiert aber bereits 4-8 Ziffern. Pattern entfernt, stattdessen ein `oninput`-Stripper der nicht-Ziffern direkt aus dem Wert raushaut — Paste mit Leerzeichen, Bindestrichen, etc. funktioniert jetzt. Server-Validierung bleibt unverändert als zweite Linie.
- Arreglo Notification-Bell auf iOS-PWA war nicht antippbar. Drei kombinierte Ursachen: (1) der `<script is:inline>`-Block in `NotificationBell.astro` wurde pro Bell-Instanz dupliziert (Mobile + Desktop = 2 Skripts) und hat doppelt Listener auf dieselben Buttons attached — Klick toggelte 2× und endete bei „geschlossen". Auf hoisted `<script>` umgestellt, Astro emittet jetzt genau einmal pro Page. (2) Das Badge-Span auf dem Button war absolut positioniert ohne `pointer-events:none` — Tap auf den Counter wurde von iOS nicht zum Button durchgereicht. (3) `touch-action: manipulation` auf dem Bell-Container deaktiviert iOS' 300ms-double-tap-zoom-Verzögerung.
- Arreglo Push-Aktivierungs-Button in `/settings/notifications` hatte keine Funktion — der zentrale `<Button>`-Component reichte `data-*`-Attribute nicht ans `<button>`-Element durch, also fand das Wiring-Skript `document.querySelector("[data-push-enable]")` nichts und der Early-Return brach das gesamte Push-Setup ab. Button.astro spreaded jetzt `Astro.props` per `...rest` aufs Element — alle data-/aria-/hidden-Attribute kommen durch. Effekt: Push-Subscribe-Flow funktioniert ab sofort auf jeder Plattform inkl. iOS-PWA.
- Arreglo Notification-Center-Panel rutschte auf Mobile komplett aus dem sichtbaren Bereich nach links. Ursache: der Bell-Button steht auf Mobile in der Mitte der Button-Reihe (Search → Bell → Theme → Menu), nicht am rechten Rand. Mit `position: absolute; right: 0` ankerte das Panel an der Bell-Wrapper-Rechtskante, die 360px-Panel-Breite zog dann ~50–100px past the viewport. Behoben durch JS-basierte Positionierung beim Öffnen: `position: fixed`, `right: 8px` (immer 8px vom Viewport-Rand), `top: bell-bottom + 8px`. Plus `max-width: calc(100vw - 2rem)` clampt das Panel auf engen Geräten (320px → 288px Breite, 414px → 360px Breite).
- Arreglo Lead-Karte zeigte „(direkt)" als Quelle, sobald der Besucher den Iframe auf einer Site mit `Referrer-Policy: no-referrer` gesehen hat — dann fehlt sowohl Referer-Header als auch URL-UTM. Embed-Endpoint setzt jetzt automatisch einen Fallback `utm_source=embed_iframe`, `utm_medium=iframe`, sobald nichts anderes erfasst wird. Echte UTMs in der Iframe-URL und ein vorhandener Referer überschreiben den Fallback weiterhin. In der Lead-Liste taucht das als „Embed (Website)" auf statt im Direct-Bucket. Tipp: für saubere Per-Landing-Auswertung trotzdem eigene UTMs an die iframe-`src` hängen.
- Nuevo Notification-Bell ist jetzt auch in der mobilen Top-Bar verfügbar (vorher nur auf md+ sichtbar) — der Bell-Aggregator wurde in `lib/notifications/bell-feed.ts` extrahiert, beide Top-Bars (Desktop `TopHeader`, Mobile `AppNav`) ziehen die identischen 5 Streams: Quote-Messages, Task-Comments, Service-Bericht-Comments, Status-Update-Comments, neue Public-CheckUp-Leads.
- Nuevo Neuer Bell-Stream + Push-Surface „Neuer Lead". Sobald ein Public-CheckUp-Lead in der Pipeline `new` liegt, taucht er in der Glocke oben rechts mit Score, Branche und Größe auf — verschwindet automatisch, sobald der Lead auf „Kontaktiert" gezogen wird. Parallel feuert die submitPublicCheckup-Action einen Web-Push an alle Workspace-Admins mit `surface: "newLead"` — opt-in/-out wie alle anderen Push-Kategorien unter `/settings/notifications`. iOS-PWA muss einmalig installed sein + im Settings-Notifications die Subscription registrieren, Voraussetzung wie bei jedem Web-Push auf Apple.
- Nuevo Public-CheckUp-Iframe trägt jetzt einen subtilen „Powered by MSPercury"-Footer (border-top, kleine graue Schrift, klickbarer Link auf mspercury.com). Nur auf den Embed-Pages (alle 4 Steps), nicht auf den standalone-Landings — die nutzen die normale Marketing-Layout-Footer-Chrome. Plus auf dem Email-Step ein dezentes Datenschutz-Hinweisband: „Mit ‚Code anfordern' akzeptierst du unsere Datenschutzerklärung" mit Link nach `/legal/privacy`. Kein gating Checkbox — die hard binding consent bleibt am Submit-Schritt am Flow-Ende.
- Nuevo Spam-Folder-Hint im Email-Step („Bitte ggf. auch im Spam-Ordner nachsehen") in DE/EN/ES — half users finden den 6-stelligen Code, wenn er von strenger Mailfilter-Heuristik aussortiert wird. Erscheint sowohl auf der Iframe-Variante als auch auf der standalone Landing.
- Nuevo Auf `/leads` ist der Iframe-Embed-Snippet jetzt auch außerhalb der Settings copy-fertig zu sehen — als einklappbarer „Als Widget auf eigener Website einbetten"-Block direkt unter dem Public-Link. Mit eigenem Copy-Button und einem UTM-Beispiel als Tipp. Wer sich neu in den Lead-Funnel einarbeitet sieht beide Varianten (direkter Link + Iframe) in einem Blick.
- Nuevo Drei neue Doku-Seiten auf docs.mspercury.com (DE/EN/ES): „Public-CheckUp & Widget einrichten". 8-stufige End-to-End-Anleitung von leerem Workspace bis zur Iframe-Integration auf der eigenen Marketing-Site, inkl. UTM-Tracking-Beispiele, RGPD-Notes, häufige Stolpersteine. Verlinkt im Docs-Index auf Position 3.5.
- Cambiado „Abgelehnt"-Spalte im Lead-Kanban hat eine semantisch passendere rosé-rote Farbe (vorher unauffälliges Grau, das visuell mit „Neu" konkurriert hat). Sortiert sich klar in die Pipeline-Farbpalette ein: Violett (Neu) → Sky (Kontaktiert) → Amber (Angebot) → Emerald (Kunde) → Rose (Abgelehnt).
- Cambiado Side-Nav auf der `/settings`-Seite ist jetzt auch auf Mobile sichtbar (vorher `hidden lg:block`, also nur auf Desktop ≥1024px). Damit erreicht man von der iOS-PWA die Sub-Pages „Sicherheit", „Push-Benachrichtigungen", „Vereinbarungs-Vorlagen" usw., die vorher de facto unauffindbar waren. Auf Desktop bleibt's bei der gewohnten Sidebar-Position links.
- Cambiado Service-Worker-Cache von `mspercury-v4` auf `v5` gebumpt — sorgt dafür dass installierte PWAs (Desktop + iOS) nach diesem Deploy einmalig die neuen Assets ziehen statt am alten JavaScript zu hängen. Wer eine PWA hat: einmalig aus dem App-Switcher killen und neu öffnen, dann ist alles gleich aktuell.
hace 1 mesKI-Tier-1C/1D/1E, Lead-Source-Tracking + UI, Stundensatz, MRR pro Kunde, Embed-Snippet, Web Push live, PDF DIN 5008 fix
10Nuevo4Cambiado2Arreglo1Security
KI-Tier-1C/1D/1E, Lead-Source-Tracking + UI, Stundensatz, MRR pro Kunde, Embed-Snippet, Web Push live, PDF DIN 5008 fix
- Nuevo KI-Meilenstein-Generator (Tier-1C) — auf jedem Projekt im Status-Tab aufklappbar als „✨ KI-Meilenstein-Entwurf". Sie tippen das Projektziel in 1–2 Sätzen ein („50 Endpoints auf Win11 migrieren, fertig bis Ende Q3") plus optional eine Gesamtdauer in Tagen, die KI liefert 3–7 geordnete Meilensteine mit groben ETAs zurück. Sie sehen die Vorschläge als Liste mit Checkboxen + editierbaren Labels und Datumsfeldern, deselektieren was nicht passt, korrigieren wo nötig, und „Ausgewählte einfügen" schreibt alle in einer atomaren Bulk-Insert-Aktion. Der Meilenstein-Tracker im Kundenportal zeigt sie sofort als Fortschrittsbalken.
- Nuevo Meilenstein-Reorder per Tastendruck — bei Hover über einen Meilenstein erscheinen rechts ↑/↓-Pfeile, die ihn um eine Position nach oben oder unten schieben. Die Reihenfolge im Kundenportal-Fortschrittsbalken folgt sofort. Beim ersten Eintrag ist ↑ deaktiviert, beim letzten ↓ — die Pfeile springen visuell aus, wenn das Ende erreicht ist. Hilfreich nach KI-generierter Reihenfolge oder wenn ein neuer Meilenstein nachträglich eingeschoben wird.
- Nuevo KI-Antwortvorschlag im Quote-Thread (Tier-1D) — direkt unter dem Antwort-Textfeld auf jeder Angebots-Detailseite ein neuer Button „✨ Antwort entwerfen". Klick liest die letzten ~10 Nachrichten zwischen Ihnen und der Kundschaft und liefert einen höflichen, sachlichen Antwort-Entwurf in der Sprache der Kundschaft (DE/EN/ES — folgt `customer.preferredLanguage`). Tonalität: kein Anrede/Verabschiedung (Chat-Bubble-Format), max. 4 Sätze, geht konkret auf die letzte Kundennachricht ein. Operator prüft + sendet immer manuell — nichts geht autonom raus, der Audit-Trail bleibt sauber. Wenn Sie schon was getippt haben, fragt der Button vor dem Überschreiben.
- Nuevo Service-Bericht → Status-Post Brücke (Tier-1E). Auf jedem versendeten oder bestätigten Service-Bericht steht jetzt ein „✨ Auch als Status posten"-Button. Klick destilliert die KI den Bericht zu einem 1-Zeilen-Status-Post mit der passenden Kategorie (meist „erledigt"), wechselt automatisch in den Status-Tab, befüllt den Komposer (Textarea + Kategorie-Radio) mit kurzem violetten Outline-Flash, und Sie senden ihn nach Review mit einem Klick raus. Sie müssen denselben Einsatz nicht mehr zweimal formulieren — einmal als ausführlichen Bericht, einmal als knappen Statusfeed-Eintrag.
- Nuevo Stundensatz wird pro Workspace gespeichert. Unter Einstellungen → Finanzen gibt es ein neues Feld „Standard-Stundensatz" — einmal setzen, dann bei jedem KI-Aufwand-Angebot aus einem CheckUp vorbefüllt. Leer lassen heißt: jeder Operator gibt den Satz pro Angebot manuell ein, wie bisher. Praktisch für MSPs mit einem festen Tarif (z. B. 120 €/h Standard, vereinzelt überschrieben für Großkunden) — kein Doppel-Tippen mehr.
- Nuevo Kunden-MRR jetzt direkt sichtbar in der Kundenliste UND auf der Detailseite. Auf der Listenseite eine neue Spalte „MRR" rechts mit dem effektiven Wert pro Kunde + einem ●-Badge wenn ein manueller Override gesetzt ist. Auf der Detailseite eine neue MRR-Karte mit dem Headline-Betrag, der Quelle (manueller Override oder berechnet aus N akzeptierten Angeboten) UND einer Zeilen-Aufstellung der beitragenden Angebote inkl. monatlichem Anteil pro Angebot. Jede Zeile ist klickbar zum Angebot oder direkt zur Bearbeitung — wenn die Kundschaft 5× RMM angenommen hat und Sie wollen das auf 7× hochziehen, klicken Sie „Bearbeiten", passen die Menge an, und der MRR auf der Kundenseite + im Dashboard reflektiert es sofort. Override für Vertragspauschalen bleibt verfügbar (jetzt collapsed unter eigenem Toggle).
- Nuevo Lead-Quellen-Attribution für den öffentlichen CheckUp. Jeder neue Lead trägt jetzt die volle First-Touch-Attribution: Source-URL (mit Query-String), Referrer-Host und alle fünf UTM-Parameter (`utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`). Erfassung läuft über ein signiertes Cookie auf der ersten Seite des Flows — überlebt den Multi-Step (Email → PIN → Fragen → Submit), wird beim Lead-Insert in die DB geschrieben, dann gelöscht. First-touch gewinnt: ein wiederkehrender Besucher mit anderer UTM überschreibt nicht den Original-Kanal. Kein Setup nötig außer `?utm_source=google&utm_medium=cpc&...` an die iframe-/Landing-URL anhängen.
- Nuevo Lead-Quellen-Operator-UI. Auf `/leads` über dem Kanban gibt es jetzt einen „Top-Quellen"-Strip mit den 5 wichtigsten Channels (Lead-Anzahl + Prozentanteil), und jede Lead-Karte trägt eine kompakte 📈-Source-Badge wenn UTM oder Referrer-Daten da sind. Die Pills im Strip sind klickbar — filtern den Kanban auf einen einzigen Channel; „Alle" rechts zum Reset. URL-driven (`?source=google · cpc`), also bookmarkbar/teilbar. Auf der Lead-Detailseite eine neue „Quelle"-Karte mit allen UTM-Feldern, Referrer-Host und der vollen Landing-URL als klickbarer Link, plus expliziter Erklärtext wenn (direkt).
- Nuevo Iframe-Embed-Snippet jetzt copy-fertig direkt im Settings-Block. Unter Einstellungen → Public-CheckUp wird der vollständige `<iframe src="…/embed" …>`-Snippet inline im grünen Link-Block angezeigt mit eigenem „Kopieren"-Button — vorher steckte er hinter einem `<details>`-Aufklapper und wurde übersehen. Der Embed-Endpoint (`/check/{slug}/embed`) ist iframe-optimiert (CSP `frame-ancestors *`, X-Frame-Options ALLOWALL), trägt den Multi-Step-Flow inkl. PIN-Eingabe komplett innerhalb des Iframes, und passt sich responsive an die Container-Breite an.
- Nuevo Web Push aktiviert. VAPID-Schlüssel sind in die Server-Konfiguration eingebaut, der `/api/push/key`-Endpoint antwortet jetzt 200 mit dem Public Key, und der Service-Worker kann Subscriptions registrieren. In `/settings/notifications` lässt sich pro Event-Typ (Kundennachricht-empfangen, Quote-Entscheidung, Vereinbarung-signiert, Service-Bericht-Kommentar, Status-Update-Kommentar, Task-Kommentar, Wartungsfenster-Antwort, Billing) opt-in. Browser-natives Push, kein Drittanbieter-Gateway, VAPID-Keys workspace-scoped.
- Cambiado Hilfe-Section in der Sidebar startet jetzt by default eingeklappt — egal welcher Viewport. Die meisten Operator-Aufrufe gehen an Kunden / Angebote / Projekte; Docs / Changelog / Feedback nutzt man unregelmäßig. Der Aufklapp-Zustand wird weiter pro Browser gespeichert: einmal geöffnet bleibt geöffnet, bis Sie ihn wieder zumachen.
- Cambiado Conversion-Funnel auf dem Dashboard: pro Stufe steht jetzt der Drop-off-Hinweis IMMER sichtbar als Mini-Zeile unter dem Balken — vorher musste der Operator mit dem Cursor draufstehenbleiben und auf den nativen Browser-Tooltip warten (mit ~1s Verzögerung, je nach OS auch gar nicht angezeigt). Ohne Drop-off ist der Hinweis grau („Kein Drop-off"), bei tatsächlichem Verlust rot-italic („↓ 12 verloren ggü. Engaged (-30%)"). Der Operator sieht beim Reinkommen aufs Dashboard sofort wo's hakt, ohne zu hovern.
- Cambiado Komplette Localization-Audit: 241 i18n-Keys in DE/EN/ES verifiziert, 0 fehlend. Alle vorher noch hartcodierten deutschen Strings auf dem Dashboard (KPI-Tooltips, MRR-Override-Hinweis, Chart-Hover-Delta-Phrasen, Funnel-Texte), in den Quote-Detail- und Edit-Seiten (Post-Accept-Banner und -Hinweis) und im Projekt-Status-Inline-JS (KI-Strukturierer- und KI-Bericht-Helper-Meldungen) wurden auf `t()`-Aufrufe umgestellt. Die spanischsprachigen Operatoren bekommen jetzt die kompletten KI-Helper- und Dashboard-Texte auf Spanisch — vorher rutschten an einigen Stellen deutsche Originalstrings durch.
- Cambiado Doku-Seite (docs.mspercury.com) komplett aktualisiert in DE/EN/ES. Die Funktionsliste erweitert von 12 auf 24+ Blöcke und reflektiert den jetzigen Stand inkl. KI-Tier-1A bis 1D, Sprint-4-Dashboard, Public-CheckUp-Lead-Gen, Iframe-Embed, UTM-Attribution, Manual MRR Override, Quote-Post-Accept-Editing, Vereinbarungs-Vorlagen, Web-Push, Branchen-Routung. Roadmap restrukturiert in „Jetzt / Nächst / Später / Bereits umgesetzt" mit Mai-2026-Daten für die neuen Features. Getting-Started erweitert von 7 auf 8 Schritte (explizites Onboarding, KI-Aufwand-Pfad neben Katalog-Pfad, optionaler Public-CheckUp-Schritt mit UTM-Beispiel). FAQ-Cancel-Frage spiegelt das tatsächlich shipped Self-Service-Löschen statt der Roadmap-Versprechung.
- Arreglo Angebots-PDF-Folgeseiten (Seite 2 und folgende) hatten nahezu keinen Top-Margin — Inhalt klebte am oberen Seitenrand und brach DIN 5008. Ursache: die @page-Margin-Regel hatte `top: 0` als Default mit einer `@page :left, :right`-Override-Gruppe, deren Cascade in WeasyPrint nicht greift. Behoben: Default ist jetzt 25mm Top, nur die `:first`-Page (mit eigener `.din-header`-Padding-Logik) überschreibt auf 0. Bestehende, bereits exportierte PDFs sind nicht rückwirkend betroffen — neu generierte Angebots-PDFs respektieren ab sofort die DIN-konforme Top-Margin.
- Arreglo Manueller MRR-Override + Quote-Post-Accept-Editing-Audit (eigentlich schon im Code seit 2026-05-03) waren ohne die zugehörigen DB-Migrationen ausgerollt — die Spalten `customers.manual_monthly_revenue` + `_note` und `quotes.last_edited_at_post_accept` + `last_edited_by_user_id` existieren jetzt tatsächlich auf prod und der Override + die Audit-Spalten funktionieren. Plus die heute neuen Migrationen für `organizations.default_hourly_rate` und sieben neue Spalten auf `prospect_leads` für UTM-/Source-Capture.
- Security SSH-Server-Endpoint ist von Port 22 auf Port 2222 migriert worden, um Hetzner-Edge-Anti-DDoS-Filter dauerhaft zu umgehen. Der Filter ziehlt auf `(src_ip, dst_port=22)`-Tupel und hat in der Vergangenheit den Deploy-Pfad mehrfach für Stunden lahmgelegt. Phase 1 (Port 2222 zusätzlich aufnehmen) ist live und verifiziert; Phase 2 (Port 22 entfernen) folgt nach 24h-Soak. Für Sie als Kunde keine Auswirkung — nur ein Operator-/Deploy-Pfad-Detail.
hace 1 mesCustomer-Communication-Hub: Service-Berichte, Wartungsfenster, Status-Stream + Diskussion
9Nuevo1Cambiado1Arreglo1Security
Customer-Communication-Hub: Service-Berichte, Wartungsfenster, Status-Stream + Diskussion
- Nuevo Status-Stream pro Projekt — kurze Updates an Ihre Kunden ohne den Umweg über E-Mail-Texte. Auf jedem Projekt gibt es einen neuen Reiter „Status & Meilensteine". Sie wählen eine Kategorie (Info, Bestellt, Geliefert, Geplant, In Arbeit, Wartet auf Kunde, Erledigt — jede mit eigenem Icon und Farbe) und schreiben einen Satz wie „18× Lenovo M70q bestellt, geplante Lieferung 15.05.". Ihr Kunde bekommt sofort eine E-Mail im MSPercury-Branding mit direktem Link ins Portal und sieht den Eintrag dort als chronologischen Verlauf zu seinem Projekt. Über einen Toggle „Im Kundenportal sichtbar" können Sie auch interne Notizen für Ihr Team posten, die nie nach außen gehen.
- Nuevo Meilenstein-Tracker pro Projekt — die „Pizza-Tracker"-Variante für IT-Projekte. Sie definieren die linearen Stufen Ihres Projekts (z. B. „Vertrag unterzeichnet → Hardware bestellt → Hardware geliefert → Installation → Übergabe") mit optionalem Soll-Datum, hakeln sie mit einem Klick ab, sobald sie erledigt sind. Im Kundenportal wird das als horizontaler Fortschrittsbalken mit nummerierten Stufen sichtbar — der Kunde fragt nicht mehr nach „wie weit sind wir denn jetzt?", er sieht es. Manuelles Umsortieren per Drag funktioniert; ein freier Sortier-Index lässt Sie auch nachträglich Stufen einschieben, ohne alles neu nummerieren zu müssen.
- Nuevo Service-Berichte — der digitale Servicebericht ersetzt den Zettel nach dem Vor-Ort-Termin. Sie tippen nach einem Einsatz Titel, Einsatzdatum, Aufwand in Stunden und einen Beschreibungstext (was wurde gemacht, welche Geräte, Auffälligkeiten, Empfehlungen). Erst als Entwurf speichern, dann mit einem Klick „An Kunde senden" — der Kunde bekommt eine E-Mail und liest den Bericht im Portal. Auf seiner Seite kann er „Erhalten bestätigen" (für die Soft-Quittung, dass er den Bericht gesehen hat) oder mit einem getippten Namen rechtsverbindlich unterzeichnen. Status-Linie: Entwurf → Gesendet → Erhalten → Unterzeichnet, mit IP-Audit beim Signieren. Drafts können Sie noch beliebig bearbeiten oder löschen; gesendete Berichte bleiben als Audit-Trail erhalten und sind nicht mehr nachträglich änderbar.
- Nuevo Diskussion direkt am Service-Bericht. Wenn Ihr Kunde nach dem Lesen eine Rückfrage hat („War die SSD im Server 1 oder 2?", „Können wir die nächsten Reboots auf abends 19:00 legen?"), schreibt er das als Kommentar direkt am Bericht — kein Mail-Tennis mehr, alles bleibt dokumentiert am richtigen Objekt. Sie sehen die Antwort als ungelesene Markierung in der Glocke oben rechts und antworten ebenfalls inline. Auf der Kunden-Seite ist der Verlauf als Chat dargestellt (Ihre Antworten links grau, seine Nachrichten rechts in Ihrer Markenfarbe). Lese-Markierungen automatisch beim Öffnen — kein Klick auf „als gelesen" nötig.
- Nuevo Wartungsfenster-Workflow — geplante Wartung mit Kunden-Bestätigung. Auf jedem Projekt gibt es einen neuen Reiter „Wartung". Sie schlagen einen Termin vor (Titel, Start- und Endzeit über datetime-Picker, optionale Beschreibung wer erreichbar ist während der Wartung) und entscheiden, ob mit Service-Unterbrechung zu rechnen ist (das blendet beim Kunden ein Warn-Icon ein). Der Kunde bekommt eine E-Mail mit Termin und Detailinfo, kann im Portal entweder bestätigen oder einen anderen Termin vorschlagen — letzterer mit einem freien Begründungstext, den Sie dann auf Ihrer Seite als „Kunde wünscht Verschiebung" eingeblendet sehen. Wenn Sie das Datum nachträglich verschieben, springt der Status automatisch zurück auf „Vorgeschlagen", damit der Kunde erneut bestätigt — Metadaten-Änderungen am gleichen Slot triggern keine erneute Bestätigung. Vier Lifecycle-Mails: Vorschlag, Verschoben, Aktualisiert, Abgesagt — alle in der Sprache Ihres Kunden (DE/EN/ES).
- Nuevo Diskussion direkt am Status-Update. Genauso wie bei Service-Berichten kann Ihr Kunde jetzt auch unter jedem Status-Stream-Eintrag eine Rückfrage hinterlegen — kein extra Telefonat, kein eigener Ticket-Loop. Inline-`details`-Aufklappbereich pro Eintrag mit Composer und chronologischem Verlauf. Interne (nicht-kundensichtbare) Status-Posts haben naturgemäß keinen Diskussions-Faden; die Funktion erscheint dort nicht. Beidseitige Lese-Markierungen wie bei Berichten.
- Nuevo Persönlicher Ansprechpartner pro Kunde. Auf der Kunden-Detail-Seite gibt es ein neues Dropdown unter den Kontaktdaten („Ansprechpartner (MSP-Seite)"), in dem Sie aus den Mitgliedern Ihres Workspaces einen für diesen Kunden zuweisen können. Im Kundenportal erscheint daraufhin oben auf der Übersichtsseite eine „Ihr Ansprechpartner"-Karte mit dem Namen Ihres Mitarbeiters statt des allgemeinen Firmennamens — der Kunde sieht namentlich, wer für ihn zuständig ist, mit direktem Mailto-Link. Ohne Zuweisung bleibt es bei den allgemeinen Workspace-Kontaktdaten.
- Nuevo Glocke oben rechts zeigt jetzt vier Quellen statt zwei: Quote-Nachrichten, Task-Kommentare, Service-Bericht-Diskussionen (grün) und Status-Update-Diskussionen (hellblau) — alles in einem Badge mit der Gesamtzahl. Klick auf einen Eintrag landet direkt am richtigen Surface (Bericht aufgeklappt, Status-Post aufgeklappt) und markiert den Eintrag automatisch als gelesen, damit Sie ihn nicht zweimal sehen. Der Operator hat damit eine zentrale Inbox für jede Kunden-Reaktion in jedem Kanal — kein Suchen mehr durch Tabs.
- Nuevo „Aktuelles" auf der Kundenportal-Übersicht erweitert. Die chronologische Activity-Liste zeigt zusätzlich zu Vereinbarungen, Angeboten und CheckUp-Berichten jetzt auch Service-Berichte (mit „neu — bitte bestätigen"-Badge wenn ungelesen) und Wartungsfenster (orange-amber wenn Bestätigung ausstehend, grün wenn bestätigt) — sortiert nach Aktualität, max. 8 Einträge. Der Kunde sieht beim Reinkommen ins Portal auf einen Blick, was es Neues gibt und was er noch tun soll.
- Cambiado Polish im Kundenportal-Status-Feed: jeder Eintrag hat jetzt eine farbige Emoji-Icon-Spalte links (kategorie-getönt, halbtransparenter Hintergrund), das Kategorie-Label oben in CAPS-Letterspacing — das Layout liest sich als Timeline, die Kategorie ist auf einen Blick erkennbar.
- Arreglo Info-Kategorie-Chip im Status-Stream-Composer war im Dark-Mode unleserlich (heller Hintergrund mit hellem Text). Ursache: das Tone-Token `dark:bg-ink-800` war versehentlich gesetzt — das semantische Token `ink-800` wird im Dark-Mode automatisch invertiert, der `dark:`-Override hat das nochmal umgekehrt und so einen weißen Hintergrund produziert. Die `dark:`-Modifier auf der `info`-Tone wurden entfernt; die anderen Kategorien (Amber, Sky, Violet, Rose, Emerald) nutzen echte Tailwind-Farben und brauchen ihre `dark:`-Varianten weiterhin.
- Security Portal-Token-Sperre wirkt jetzt sofort. Beim Audit der neuen Customer-Portal-Endpoints (Acknowledge, Sign, Maintenance-Accept/Reschedule, Comment-Posts) ist aufgefallen, dass alle fünf Token-Validierungen einen Lifecycle-Check auf eine Spalte `expiresAt` machten — die es auf `customer_portal_tokens` aber gar nicht gibt (das Schema kennt nur `revokedAt`, gesetzt beim Operator-seitigen Rotate / manuellen Widerruf). Der Check war damit toter Code und hat nie ausgelöst, gerollte oder widerrufene Tokens blieben technisch nutzbar. Tenant-Isolation durch `customerId`-Binding war davon nicht betroffen — kein Cross-Customer-Leak möglich. Aber ein Operator, der einen Token rotiert hat, konnte sich nicht darauf verlassen, dass der alte Link sofort tot ist. Behoben: alle fünf Endpoints (inkl. der älteren task-comments-Aktion mit derselben Bug-Quelle) prüfen jetzt `revokedAt` und werfen 401, sobald gesetzt. Zusätzlich wurden in derselben Runde defense-in-depth `organizationId`-Doppel-Bindings in alle UPDATE/DELETE-Statements der neuen Actions eingezogen — falls ein zukünftiger Schema-Drift jemals Customer/Org-IDs entkoppelt, fehlschlagen die Writes laut statt leise.
hace 1 mesSign-flow + signed-PDF fixes, customer status auto-promotion, maintenance banner
2Nuevo7Arreglo
Sign-flow + signed-PDF fixes, customer status auto-promotion, maintenance banner
- Nuevo Customer pipeline status now updates itself when reality moves the deal forward. First quote that goes out to a customer with no classification yet → Warm prospect. First accepted quote (operator-side flip OR customer accepts via the share link) or signed agreement → Active customer. The funnel-stage promotions (cold/warm/hot → active) only happen when there's a clear conversion signal — manually-set values otherwise stick, so a deliberate "cold" or "hot" doesn't get clobbered by an unrelated quote going out. Archived customers are never auto-revived; if an archived customer signs a one-off addendum, that's the operator's call to reactivate, not the system's. Promotion runs as fire-and-forget — failures are logged to journalctl but never block the action that triggered them, so a customer signing an agreement always succeeds end-to-end even if the promotion update hits a transient lock.
- Nuevo Maintenance banner. Configurable via three env vars on the systemd unit — MAINTENANCE_BANNER_TEXT for the message, MAINTENANCE_BANNER_UNTIL for an optional ISO timestamp that renders a server-computed countdown alongside the text, MAINTENANCE_BANNER_TONE for info / warning / danger colour. Visible at the top of every page including the login screen and marketing pages, so an unauthenticated visitor also sees "Wartung in 15 Minuten" before they try to sign in. Activate by adding the vars to mspercury.service and `systemctl restart mspercury`; deactivate by clearing the text var and restarting again. No DB row, no client JS — countdown is fresh on each page load by re-reading the timestamp at request time.
- Arreglo Customers were getting "Link not found" after successfully signing an agreement. The DB row was correctly flipped to status=signed and the signed-PDF email actually went out, but the page they landed on couldn't see any of that because Astro's default form-action redirect uses the Referer header — and modern browsers (Strict-Origin-When-Cross-Origin is the default) strip the query string from Referer on POSTs. The page reloaded as `/agreements/<id>/sign` with no `?token=…`, the token-based lookup returned nothing, and we rendered the not-found state. Fixed: the action now returns the token in its success payload so the page handler can do an explicit Astro.redirect with the query string preserved. After the redirect the page sees status=signed and renders the green confirmation panel + Download CTA. On error paths the token is also recovered from `result.input` so "Already signed" / "Token expired" messages render properly instead of the generic not-found.
- Arreglo Submit button on the public agreement-sign page was rendering white-on-white and effectively invisible. Cause: the button used the workspace's brand colour as background — a near-white brand colour combined with white button text turns the only call-to-action on the page into nothing. The branded header banner above the document can stay accent-coloured, but the actionable buttons — Sign and Download signed PDF — are now hard-coded to a dark slate so they're always readable regardless of brand-colour choice.
- Arreglo Signed-agreement PDF metadata block was laying out wrong: "Datum 30. April 2026 um 21:49" was wrapping into a tall column, "Kunde ACME GmbH" was running into "IP-Adresse 209.198.153.96", and the document hash was splitting into 4 stacked chunks. Cause: the meta `<dl>` used `display: table` with `display: table-cell` on each `<dt>` and `<dd>` — without explicit row wrappers all eight cells were crammed onto a single CSS-table row, getting ~1/8th of the page width each. Fixed by wrapping each label/value pair in a row container with `display: table-row`, plus `white-space: nowrap` on the labels so they can't wrap into multi-line columns. Existing already-signed PDFs are baked to disk and won't change retroactively; only newly-signed agreements pick up the fix.
- Arreglo Signing email's sign-link was pointing at http://127.0.0.1:4327. The detail page was building the URL from `Astro.url.origin`, which behind nginx is the upstream Node socket — useless to the recipient. Now uses the publicBaseUrl helper (PUBLIC_APP_URL → X-Forwarded-Host → request URL fallback chain), and the sendAgreement action also rebuilds the canonical URL server-side from the freshly minted token, so even a stale URL the operator pasted in can't ship a broken host.
- Arreglo Agreement emails arrived as plain text in some inboxes. Cause: the body was wrapped in raw `<p>` tags but had no full HTML document — Outlook (and a few others) fell back to text/plain. Now both the sign invite and the signed-confirmation mail go through the existing branded renderTransactional shell (full <!doctype>, MSPercury wordmark, IT Systeme Flores UG legal footer, dark CTA button), with a localised "Jetzt unterzeichnen" / "Sign now" / "Firmar ahora" button pointing at the canonical sign URL on the invite. URL auto-linkification in operator-authored email bodies was also added in the same pass, so any URL typed into a quote / agreement / customer-thread reply renders as a clickable `<a>` regardless of which client the recipient uses.
- Arreglo Native <details> disclosure marker was leaking outside the styled card on the /changelog page in some browsers, showing a stray triangle next to one of the rows. Hidden globally via summary::-webkit-details-marker + summary::marker, so the only chevron is the SVG one rendered inside the summary.
- Arreglo Filter pills on /customers were unreadable when selected in dark mode — the active state used bg-ink-900 text-white, but ink-900 flips to a near-white token in dark mode while text-white doesn't, producing white-on-white. Switched the active pill to the brand accent (bg-accent-700 text-white), which has fixed contrast in both themes.
hace 1 mesNotification dismiss, customer pipeline status, internal team notes, branded agreement emails
5Nuevo
Notification dismiss, customer pipeline status, internal team notes, branded agreement emails
- Nuevo Notification bell can be cleared without opening every quote. Each item in the dropdown has a small × button on hover that marks just that one as read; the header gained a "Mark all read" link that drains the entire unread queue in one click. Both actions are idempotent — clicking dismiss on something that's already read is a no-op, so a stale tab can't undo a fresh action. Localised in DE/EN/ES ("Alle als gelesen" / "Mark all read" / "Marcar todo leído").
- Nuevo Customer pipeline status. Customers now carry an optional classification — Cold prospect, Warm prospect, Hot prospect, Active customer, Archived — surfaced as a coloured pill on the customer detail page and as a new column on the customer list. The new/edit form has a dedicated picker with an empty default of "Unclassified" so fresh imports don't get a fake "active" status. The list page has a pill-row filter (All · each status · Unclassified) above the table that composes with the existing search field, so you can answer "which warm prospects haven't I followed up on?" in two clicks instead of scrolling. DB column is nullable + additive — existing customers default to Unclassified until you pick something.
- Nuevo Internal notes thread on the customer detail page. Operator-only — no public surface, no email dispatch — meant for the team's running conversation about the relationship: who's the champion, why the deal stalled, when the renewal date hits, who you spoke to last. Multi-author, timestamped, with a pin-on-post checkbox so the high-signal stuff ("renewal 2026-08", "champion left, talk to Jana now") floats to the top. Pinned/unpinned by anyone in the workspace; only the original author can delete their own notes. Author name is captured both as a foreign key (so future filters work) and as a snapshot string, so a note still renders the original author's name even after they leave the workspace. DE/EN/ES throughout.
- Nuevo MSPercury-branded HTML template for agreement emails. The DPA-sign invite + the signed-PDF confirmation now go through the same renderTransactional shell quote-thread mails already use: full <!doctype> document, white card on a warm grey background, MSPercury wordmark on top, IT Systeme Flores UG legal footer at the bottom. Sign invitations get a prominent black CTA button — "Jetzt unterzeichnen" / "Sign now" / "Firmar ahora" — pointing at the canonical sign URL.
- Nuevo Auto-linkification in transactional email bodies. The plain-text-to-HTML helper (used by every operator-authored email) now detects http/https URLs in the body and wraps them in clickable <a> tags with proper styling and target="_blank". Without this, Outlook in particular leaves bare URLs un-clickable; now the link works regardless of which client the recipient uses. Three duplicate copies of the helper were consolidated into one src/lib/mail/format.ts.
hace 1 mesCheckUp wizard, customer language, AI summary controls, sender branding, PDF page breaks
10Nuevo3Cambiado5Arreglo1Eliminado1Security
CheckUp wizard, customer language, AI summary controls, sender branding, PDF page breaks
- Nuevo "Nicht zutreffend" on every CheckUp wizard question. Skip is no longer gated by a per-question flag — any question (Firewall on a solo-self-employed customer, server hardening on a 0-server site, you get the idea) can be marked irrelevant. Skipped questions create no findings, so they're score-neutral, and they're listed under "— nicht zutreffend" on the review screen + PDF report so the audit trail stays honest.
- Nuevo Score badge in the /checkups list. Finalised CheckUps now show a coloured score pill (0–100 %) right next to the status badge, using the same emerald → amber → rose palette as the report. Drafts stay unchanged because their finding set isn't frozen yet.
- Nuevo Customer-level preferred language. Customer create/edit form has a new "Preferred language" picker (Org default · Deutsch · English · Español). When set, it overrides the workspace default for every customer-facing artefact: the email-draft default, the share-link CTA copy, the rendered PDF locale on quote and CheckUp report sends. Empty value ⇒ falls back to the workspace's brand language.
- Nuevo Language picker in the email-send modal. Above subject + body, a small DE/EN/ES tab row lets you swap the entire draft to a different language with one click. Per-language edits are remembered while the modal is open, so flipping back to the original tab restores what you wrote there.
- Nuevo Sender branding: "<Your name> via MSPercury". Customer-facing emails (quote PDF, quote share link, CheckUp report) now arrive with the From-display-name set to the operator's name (or workspace name if the user has no display name on file) — so the recipient sees who the email is from immediately, not a generic "MSPercury". The mailbox stays at noreply@mspercury.com so DKIM/DMARC keep aligning. System mails (password reset, verify, invites, Stripe webhooks) are unchanged on principle.
- Nuevo AI executive summary modal with language + detail-level controls. The old one-click button is gone, replaced by a proper modal: pick the output language (defaults to your brand language but freely overridable per generation), pick a detail level — Brief (~150 words, scannable for the C-suite), Standard (~300 words, the v1 default), or Detailed (~700 words, structured with numbered recommendations and a 30/90/180-day plan). On submit the modal shows a foreground progress overlay with elapsed-time counter and rotating stage labels ("Calling Anthropic" → "Streaming response" → "Polishing" → "Saving") so you actually see that the AI is working, instead of just the browser-tab spinner.
- Nuevo Standalone executive-summary PDF — accompanies the full CheckUp report. New endpoint at /checkups/{id}/summary.pdf renders a single-page A4 with letterhead, recipient block, audit-date + score pill, and the AI-generated prose. Download button on the CheckUp detail page next to the saved-summary preview, plus a small DE/EN/ES locale pill so you see at a glance which language the saved text is in.
- Nuevo "Also attach summary as PDF" toggle in the CheckUp send-to-customer modal. When the CheckUp has a saved AI summary, the modal grows a checkbox (default-on) that ships the standalone summary PDF as a second attachment alongside the main report. Renderer fails hard rather than silently dropping the attachment — you opted in, so a half-delivered envelope would be more confusing than a clear error you can retry.
- Nuevo AI integrations card redesign. Settings → AI integrations now shows a structured connection panel (provider, model, masked API key, encryption note, scope-is-this-tenant-only note) with a dedicated red "Disconnect" button that wipes provider, model and the encrypted key from the workspace row in one click. The free-text "Currently connected to anthropic." line that used to sit under the description is gone — it's the panel now.
- Nuevo Settings → Language now syncs to workspace brand language for admins. Until today, picking Deutsch in Settings only updated your personal UI language (users.preferredLanguage); the workspace brand language (organizations.preferredLanguage, used for outgoing letters and AI summaries) stayed wherever it was. They drifted. Now an admin language change updates both at once, so "my workspace is in German" and "emails go out in German" stop disagreeing. Non-admins still only flip their own UI.
- Arreglo AI executive summary was English even when the workspace was set to German. Two bugs piled on each other: the action read ctx.locals.locale (which a stale `mspercury_locale=en` cookie could pin to English even after you'd set Deutsch in Settings), and admin language changes never propagated to the workspace row. Fixed both. AI generation now follows organizations.preferredLanguage explicitly, with a per-call override exposed via the new modal — and the tag is baked into the saved summary marker (`--- AI-SUMMARY:de ---`) so the embedded section in the main report and the standalone summary PDF render labels in the same language the AI wrote in.
- Arreglo AI executive summary errors used to vanish — the action threw ActionError but the page never read the result, so a click did nothing visible. The detail page now reads getActionResult and renders a red banner with the actual Anthropic response (model name typo, revoked key, rate limit) under the button. Server-side, the catch path also writes to journalctl for debugging without re-running.
- Arreglo AI executive summary was blocked on finalised CheckUps. Lifted: the summary lives on `notes` and only feeds the executive-summary section of the PDF — it doesn't change findings, scores, or any audit-bearing data, so the freeze rule that protects findings doesn't apply. Generating one on a frozen CheckUp now works.
- Arreglo PDF reports cut content off at the page edge. The CheckUp report cover used a hard-set 297mm height that clipped overflow, and the findings sections forced page-break-inside: avoid on whole categories — categories with many findings then bled past the bottom edge. Same family of issues on the quote PDF (line-group avoid-break) and the internal monthly report (kpi/chart/health cards). All three templates now use targeted break-inside: avoid on the smallest meaningful units (cover stat row, individual finding card, single line row, kpi card, chart frame, health card), repeat <thead> on continuation pages via display: table-header-group, and let categories / line groups break naturally across pages with the heading break-after: avoid'd to its first row.
- Arreglo ecosystem.config.cjs in the repo implied PM2 was the prod process supervisor. It isn't — production runs the Astro build under a systemd unit (mspercury.service), which is what restarts now go through. The pm2 path on the server returns "command not found". The repo file is left intact for the moment to avoid breaking any unknown dev-side workflow but should be considered cosmetic.
- Cambiado Email-draft default language now follows the tenant's effective system language. Previously every workspace got drafts in the org's preferredLanguage regardless of which language the operator was reading the UI in. Now the cascade is: customer.preferredLanguage (if set as an explicit override) → user.preferredLanguage → org.preferredLanguage → en. Net effect: the modal opens in whatever language you're currently using, with one click to switch per-customer.
- Cambiado Email-drafts code consolidated. The 4 inline switch-by-locale blocks (PDF / share-link / CheckUp-report) that lived in two detail pages — ~120 lines of nearly-identical copy-paste — moved to lib/mail/drafts.ts with one helper per delivery mode. Each page now does six lines instead of fifty, and tweaking the greeting copy is a one-place change.
- Cambiado Customer language picker extracted to a shared component. The select markup was duplicated between customers/new and customers/[id]/edit; now it's one CustomerLanguageField.astro that both pages consume.
- Eliminado Unused `skip` translation key from de/en/es locale files. The wizard switched to the always-available `notApplicable` button last cycle, so the old key was just sitting there.
- Security AI tenant isolation audit. The action path was already structurally clean — every read goes through ctx.locals.organization (session-bound), providerForOrg() builds the HTTP client only from that one org row, AES-256-GCM encryption at rest with a SESSION_SECRET-derived master key, random per-message IV, auth tag included. The Settings card now visibly says it: provider, model, masked key with "encrypted at rest, AES-GCM" hint, scope line "This workspace only — tenant-isolated". One Disconnect click wipes the row.
hace 1 mesAccount security overhaul: 2FA, passkeys, sessions, trusted devices, email + password change, account delete, GDPR export
12Nuevo4Arreglo5Security
Account security overhaul: 2FA, passkeys, sessions, trusted devices, email + password change, account delete, GDPR export
- Nuevo Forgot password? — finally. /login has a 'Forgot password?' link that sends a single-use reset link by email. After you choose a new password, every existing session and trusted device on your account is wiped, so a leaked password can't keep being used. Link is valid for 60 minutes.
- Nuevo Active sessions panel on Settings → Security. Every device that's currently signed in to your account is listed with the browser, IP and last-active time. Sign out a single session, or 'Sign out everywhere else' to nuke every cookie except the one you're holding.
- Nuevo Trusted devices for 2FA. On the /login/2fa prompt you can tick 'Trust this browser for 30 days' — that browser then skips the code on every sign-in for the next month. Manage and revoke individual trusts on Settings → Security. Trusts are wiped automatically when you reset your password or disable 2FA. Backup-code logins never set trust on principle (you're on an emergency device by definition).
- Nuevo New-device sign-in alert email. Whenever someone signs in to your account from a browser/IP combination we've never seen, we send you an email with the device, IP, time and a one-click 'Reset my password now' button. Browser auto-updates don't trigger false alerts (we strip version numbers from the fingerprint), and the very first device on a fresh signup is silently enrolled.
- Nuevo Recent activity feed on Settings → Security shows the last 10 security events on your account: sign-ins, 2FA changes, passkey changes, password resets, support resets. If something happened that you didn't do, you'll see it here.
- Nuevo Support-reset hatch for lost 2FA. If a customer loses both their authenticator app AND all backup codes, we (operator) can now reset their 2FA from /superadmin/users after out-of-band identity verification — the action requires a ticket reference and writes a permanent audit trail. Previously the only recovery was direct DB editing.
- Nuevo Settings → Security link in the /settings sidebar. The page existed but wasn't reachable from anywhere — fixed.
- Nuevo Change email address. Settings → Profile → Change. Type your new address + current password, we send a 6-digit code to the new inbox; once you confirm it, the address is updated and the old one gets a security notice (so a hijacker who learned your password can't silently swap the email out from under you).
- Nuevo Change password while signed in. Settings → Profile → Change password. Verify current password, set a new one. Other sessions on your account are signed out automatically; this device stays signed in. Trusted-device cookies are preserved (re-trusting your laptop on every quarterly rotation would be hostile UX). Distinct from forgot-password, which wipes everything as a recovery measure.
- Nuevo Self-service account deletion. Settings → Profile → Delete account…. Two-factor confirmation (current password + typing your email verbatim), with a blast-radius preview that calls out the exact counts (X customers, Y projects, Z quotes) for sole-user workspaces, or 'data stays with the other N members' for multi-user. Single users delete their workspace alongside; otherwise just the user goes. Notice email + audit event fire BEFORE the data is wiped (the only window we have).
- Nuevo Download my personal data. Settings → Profile → Download .json. Single-file dump of every byte we hold for your account: profile, sessions with UA/IP, 2FA + passkey state (without the secrets), trusted + known devices, email-change + password-reset history, full security event log. Excludes workspace data (separate export for that), encrypted secrets, and other users' info. GDPR Article 15.
- Nuevo Workspace-level 2FA enforcement (admins only). Settings → Workspace → Require two-factor for everyone. When on, every member without TOTP is bounced to /settings/security on every page until they enrol. Lock-out-guard refuses to enable unless the toggling admin already has 2FA on their own account; the action requires the admin's password as defence in depth.
- Arreglo Adding a passkey was failing with 'Could not verify the credential. Try again.' The server was passing only the inner attestation response to the WebAuthn verifier instead of the full credential envelope. Adding a passkey now works end-to-end on Touch ID, Windows Hello, YubiKeys, etc.
- Arreglo Buttons on Settings → Security were inconsistent: some were ghosted/transparent in dark mode, others used a hard-coded green that ignored your workspace's accent color. All eight buttons now go through the unified Button component, which means they pick up the brand color you set in Settings → Branding automatically.
- Arreglo Backup codes after enabling 2FA were unreadable in dark mode — the code chips had a hard-coded white background that turned them into invisible white-on-light text. Now use the same surface tokens as the rest of the app and adapt to both themes. Same fix applied to the TOTP setup-key chip.
- Security Rate-limiting on every auth endpoint. Login (form + JSON), TOTP completion, passkey assertion, signup PIN issuance + confirmation, and password-reset start + complete all have per-IP and (where applicable) per-email/per-uid throttles. Bcrypt is rejected before the slow check runs, so an attacker can't burn CPU. Successful logins reset the bucket so a typo or two doesn't lock anyone out.
- Security Successful password reset wipes EVERY session on the account, not just the cookie that triggered the reset. Same for trusted devices. This closes the 'attacker had a stale session, victim resets password to recover, attacker session keeps working' gap.
- Security Audit events for every security-relevant change: 2FA enable/disable, backup-code regeneration, passkey added/removed/renamed, password reset + change, support reset, new-device sign-in, email change, account deletion, workspace-2FA enforcement toggle, personal-data export. Surfaced both in the user's own Recent activity feed and in the operator's superadmin event log.
- Security Migration safety rail: deploys now go through scripts/safe-migrate.ts, which captures drizzle-kit's planned SQL and refuses to apply it if it contains DROP TABLE, DROP COLUMN, RENAME COLUMN, DELETE FROM <table>, or TRUNCATE — unless the operator explicitly opts in with ALLOW_DESTRUCTIVE=1. Replaces the prior `drizzle-kit push --force` deploy step.
- Security PRAGMA foreign_keys = ON now runs on every DB connection. SQLite ships with FK enforcement OFF by default; without this, a stray DELETE FROM <parent> would silently leave orphan rows in every dependent table. Now cascades work correctly for runtime ops; the safe-migrate rail prevents accidental destructive ops at the migration layer.
- Arreglo Honesty note from this morning: a drizzle-kit migration on the new workspace-2FA-enforcement column emitted an unexpected `delete from organizations;` before the ALTER, which wiped the org metadata for both production workspaces (workspace name, branding, AI provider config, contact details, billing fields). Recovered within ~10 minutes by reconstructing the org rows from the surviving orphan data (users, customers, projects, quotes, sessions, events all kept their original org_id pointers because FKs were OFF). The migration safety rail and FK pragma above are the structural fixes that prevent a repeat. If your workspace contact info, branding color, AI provider key, or logo upload reference looks blank in Settings — please re-enter; the actual files (logo, customer data) are intact.
hace 1 mesAngebote per Link teilen
5Nuevo2Cambiado
Angebote per Link teilen
- Nuevo Angebote lassen sich jetzt per Link mit Kunden teilen. Der Kunde klickt in der E-Mail auf den Button und sieht das Angebot direkt im Browser — mobilfreundlich, druckbar, als PDF speicherbar. Funktioniert ohne MSPercury-Account.
- Nuevo Optionaler PLZ-Schutz: ist in der Kundenkartei eine Postleitzahl hinterlegt, fragt die Share-Seite diese ab, bevor das Angebot sichtbar wird. So wird der Link nutzlos, falls er an falsche Adressaten weitergeleitet wird.
- Nuevo Neuer "Copy link"-Button auf der Angebots-Detailseite: erzeugt den Share-Link und legt ihn bereit, damit ihr ihn in euer eigenes Mailprogramm einfügen könnt, statt über MSPercury zu versenden.
- Nuevo Öffnet der Kunde den Link, seht ihr das — Zeitpunkt des ersten Öffnens und die Anzahl der Aufrufe werden mitgezählt. Links laufen nach 30 Tagen automatisch ab und können jederzeit manuell entzogen werden.
- Nuevo Neues PLZ-Feld im Kundenformular — dient als Verifikations-Code für die Share-Link-Freigabe.
- Cambiado Angebots-PDF kommt jetzt im DIN-5008-konformen Briefkopf (korrekte Position für Fensterkuverts, Bezugszeichenzeile, Betreffzeile).
- Cambiado Steuern im Angebot jetzt klar nach §14 UStG aufgeschlüsselt: pro Periode Netto, Rabatt, Netto nach Rabatt, MwSt-Satz und -Betrag, Brutto-Gesamt.
hace 1 mesSecurity audit + hardening, docs site, SEO pass
4Nuevo6Security
Security audit + hardening, docs site, SEO pass
- Security Fixed an open-redirect on login. A crafted link like /login?next=https://evil.example would send the user to the attacker's site after they signed in. Only same-origin paths are accepted now; anything else falls back to /dashboard. Same fix applied to the Microsoft SSO callback.
- Security Signup no longer leaks which emails are customers. Trying to register an existing email used to return a visible '409: account exists' error; now the response looks identical to a new signup and the real account holder gets a 'someone just tried to create an account with your email' notification instead.
- Security Login now rotates the session cookie. Any leftover session token is invalidated before a fresh one is issued, neutralising a narrow 'pre-plant a cookie in the victim's browser' attack.
- Security Superadmin DPA flow could be abused, in the worst case, to delete arbitrary files on the server via a malicious path value. The field now only accepts a safe filename pattern.
- Security SQLite database file permissions tightened from 644 to 600 (owner-only). Legacy TLS 1.0/1.1 lines removed from the main nginx config (the stricter TLS 1.2/1.3-only policy was already in effect at the vhost level).
- Security Independent code-level security audit run across the whole app: session handling, multi-tenant isolation, Stripe webhook signature validation, PDF template XSS escaping, secret handling, CSP, middleware bypass guards — all came back clean. Findings above were the complete actionable set.
- Nuevo NinjaOne monitoring and patch-management agent installed on the VPS. Reports to the EU datacenter; no application data leaves the server.
- Nuevo Documentation subsite launched at docs.mspercury.com. Seven pages in English, German and Spanish (What it is / Getting started / Features / Known issues / Status / Roadmap / FAQ). The Status page has a live health widget, the header has coloured shortcut pills for the three high-traffic pages, and each page has its own collapsible table of contents in the sidebar.
- Nuevo Landing-page SEO + AI-search pass: hreflang alternates for all three languages, richer OpenGraph + Twitter Card metadata, JSON-LD structured data with SoftwareApplication + Organization + WebSite + FAQ nodes optimised for AI answer engines. New /robots.txt explicitly allows GPTBot, ChatGPT-User, ClaudeBot, PerplexityBot, etc. and a dynamic /sitemap.xml lists the public pages.
- Nuevo App nav reshuffle: Docs / Changelog / Feedback moved to a dedicated 'Help' section pinned to the bottom of the sidebar, always one click from the bottom regardless of how much scrolls above. Docs opens the external subdomain in a new tab.
hace 1 mesFeedback form, superadmin overview, cookie notice, signup consent
5Nuevo3Cambiado3Arreglo
Feedback form, superadmin overview, cookie notice, signup consent
- Nuevo In-app feedback form at /feedback. Pick Bug / Feature request / Other, write a message, send. It lands in the superadmin dashboard and fires an email to the operator, with Reply-To set to the submitter so replies go directly to the user.
- Nuevo Superadmin dashboard at /settings/admin with a cross-tenant overview: stat cards for Tenants / Users / CheckUps / Quotes / Pay-what-you-want / Feedback, per-workspace counts (users, customers, projects, services, findings, quotes), DPA signing status, and a 'Seed sample data' button for workspaces that haven't loaded the starter catalog yet. Recent-users and recent-feedback tables below.
- Nuevo Cookie notice banner on every page. MSPercury only sets strictly-necessary cookies (session + language + banner acknowledgement) — the banner is transparency, not a consent gate. The Cookie Policy page lists every cookie by name, purpose and lifetime.
- Nuevo GDPR-required explicit consent on signup: two separate checkboxes for Terms of Service and Privacy Policy, both mandatory, both open the policy in a new tab. Acceptance timestamps are stored on the user record for audit purposes.
- Nuevo Starter CheckUp findings library: 43 ready-made finding templates covering Security / Updates / Backup / Network / Compliance / Hardware / Permissions / Other. Each entry includes a description and suggested remediation in English, German and Spanish, a default severity + effort, and where applicable a link to the matching catalog service so a finding flows straight into a quote.
- Cambiado Catalog seed is now locale-aware. When you click 'Load sample data', service names, descriptions and the default package name are picked in your workspace's language.
- Cambiado English is now the default language for unauthenticated visitors, regardless of their browser's Accept-Language header. Logged-in users still get their saved language preference.
- Cambiado Landing-page CTAs changed from 'Request invite' to 'Start free' — signup is open, no invite code needed.
- Arreglo PDF cover page had the company logo overlapping the company name (a WeasyPrint rendering bug). Fixed with a table-based header layout; the logo, name and address now sit cleanly next to each other.
- Arreglo Every POST form hit a CSRF false-positive under nginx-terminated TLS. Root cause: Astro's built-in CSRF check compared an https Origin header to an http request URL. The session cookie's SameSite=Lax attribute already blocks the underlying attack, so the Astro check has been disabled with a note so it's not silently re-enabled later.
- Arreglo Email delivery was broken for a week because Hetzner Cloud blocks outbound SMTP on port 465 for new accounts, and our mailer was pinned to that port. Switched to port 587 with STARTTLS; welcome, feedback and invite emails now go through.
hace 1 mesProduction deployment package + codebase audit
6Nuevo1Cambiado
Production deployment package + codebase audit
- Nuevo deploy/ folder with complete go-live package: README, DEPLOY master guide, ENVIRONMENT reference (20+ env vars), M365_SSO walkthrough (Entra app registration + multi-tenant), HETZNER (VPS + SMTP + Storage Box + DNS), STRIPE (products + tax + webhook), SSL_DNS (certbot + CAA + HSTS), PRE_LAUNCH_HARDENING (5 gap-closing features), RUNBOOK (day-2 ops + incident playbook)
- Nuevo deploy/nginx/mspercury.conf — reverse proxy with security headers, HSTS, gzip, long-cache for fonts + _astro assets, upstream timeouts tuned for WeasyPrint PDF rendering
- Nuevo deploy/systemd/mspercury.service — sandboxed unit running dist/server/entry.mjs as the mspercury user, strict NoNewPrivileges + ProtectSystem + ReadWritePaths limited to data/ + /tmp, restart-on-failure with backoff
- Nuevo deploy/scripts: deploy.sh (pull/build/migrate/restart with health check), backup-sqlite.sh (nightly SQLite .backup + tgz of uploads/attachments/dpa-signed → Hetzner Storage Box, 30-day retention), firewall.sh (UFW + fail2ban)
- Nuevo deploy/.env.production.template — sanitised env file with every variable documented inline, grouped by required / optional / third-party
- Cambiado package.json: added start:prod running node ./dist/server/entry.mjs for production (existing start is dev-only)
- Nuevo Full codebase audit: no dead links, no orphan actions, all action imports verified in src/actions/index.ts, every href traced to an existing page, API endpoints cross-referenced with their callers, translation keys sample-verified
hace 1 mesDSGVO launch-readiness: self-hosted fonts, rewritten privacy policy, Art. 28 DPA + download flow
9Nuevo1Eliminado
DSGVO launch-readiness: self-hosted fonts, rewritten privacy policy, Art. 28 DPA + download flow
- Eliminado Google Fonts / Gstatic completely eliminated. Every <link rel='preconnect|stylesheet'> that pointed at fonts.googleapis.com or fonts.gstatic.com is gone — BaseLayout, MarketingLayout, AuthLayout, the onboarding page and the standalone CheckUp report. Source tree `grep googleapis` returns 0 hits
- Nuevo Self-hosted Geist variable woff2 under /public/fonts/ (plus a Mono variant for <code>) with one @font-face declaration in global.css and a font-display: swap. Each layout now <link rel='preload'> the font and ships a CSP meta tag locking font-src to 'self' data:
- Nuevo Privacy policy fully rewritten (DE + EN, same-file bilingual). 11 numbered sections with stable #anchor ids — Verantwortlicher, Datenschutzbeauftragter, Zwecke + Rechtsgrundlagen, Datenkategorien, Empfänger (Hetzner / Stripe / Microsoft / Apple), Drittlandübermittlung, Speicherdauer, Betroffenenrechte, Cookies (only technisch notwendig), PWA / iOS, Stand. Every company fact pulled from src/lib/legal/company.ts — no hardcoded placeholders
- Nuevo Auftragsverarbeitungsvertrag (AVV) / DPA at /legal/dpa — full Art. 28 Abs. 3 DSGVO coverage: Parteien, Gegenstand + Dauer, Weisungsrecht, Pflichten, Unterauftragsverarbeiter-Liste (Hetzner / Stripe / Microsoft), Kontrollrechte, TOMs (Zutritt / Zugang / Zugriff / Weitergabe / Eingabe / Verfügbarkeit / Trennung), Meldepflicht, Drittland, Rückgabe/Löschung, Unterschriftenfeld
- Nuevo GET /legal/dpa.pdf?lang=de|en — WeasyPrint-rendered PDF via the same pipeline as CheckUp / quote reports, with ?controller=<tenant> pre-filling the controller line on the signing page. Every download writes a dpa_records row so Settings / Superadmin can show status
- Nuevo Settings card 'Datenschutz & Auftragsverarbeitung' — two download buttons (AVV Deutsch / DPA English), Upload-signed-PDF dropzone that stores the countersigned file under data/dpa-signed/{orgId}/dpa-signed.pdf and advances the record to status='signed', plus a reset button for re-signing after TOM changes
- Nuevo Superadmin-only /settings/dpa-admin — table of every tenant with DPA status (not_signed / sent / signed), download + signing timestamps, and a 'Mark signed' shortcut for the common case where the customer emails the signed copy back
- Nuevo dpa_records schema + dpaActions (uploadSignedDpa, resetDpa, markDpaSignedForOrg) + upsertDpaRow helper with monotonic status progression (a re-download never demotes a 'signed' back to 'sent')
- Nuevo README §8 rewritten as a proper DSGVO go-live checklist: attorney review hard-gate, Hetzner / Stripe / Microsoft AVV checklist with archive paths, fonts/CSP verification, customer AVV workflow documentation, DNS CAA reminder
- Nuevo Smoke test: 13 new DSGVO assertions — no googleapis / gstatic strings on /, /fonts/geist-variable.woff2 200 + font/woff2 content-type, /legal/privacy?lang=de contains Verantwortlicher / Hetzner / Art. 6, /legal/privacy?lang=en contains controller / Article 6 variants, /legal/dpa.pdf?lang=de returns 200 (WeasyPrint) or 503 (graceful), /settings shows 'AVV herunterladen' + links to /legal/dpa.pdf
hace 1 mesHealth score, infrastructure wizard step, PDF photos, OS-scoped quote engine
6Nuevo2Arreglo
Health score, infrastructure wizard step, PDF photos, OS-scoped quote engine
- Nuevo 0–100 % health score on every CheckUp — shared helper drives an SVG ring hero on both the HTML report and the WeasyPrint PDF. Weights: −8 per high, −4 per medium, −2 per low finding, floored at 0; five color bands (excellent → critical) with locale-aware labels (EN/DE/ES)
- Nuevo Wizard infrastructure step at /checkups/wizard/{id}/infrastructure — captures per-OS workstation counts (Windows / macOS / Linux / ChromeOS / Other), server breakdown (Windows / Linux / Other), total users, infra notes and on-site photos before question 1. Runs first for every new wizard CheckUp; creates or updates the linked project transactionally
- Nuevo OS-scoped quantity types on the quote engine: per_windows_ws, per_macos_ws, per_linux_ws, per_chromeos_ws, per_windows_srv, per_linux_srv. buildQuoteFromCheckup resolves each finding's linked service against the OS counts captured in the infrastructure step, so service items whose unit says "Windows workstation" generate exactly the right line-item quantity
- Nuevo PDF report now embeds all attached photos as base64 data URLs in a dedicated "Photo appendix" section — 2-up grid, captioned with the question scope (infrastructure vs. question-id), printed at up to 95 mm height on A4 so they stay crisp
- Nuevo Report HTML redesigned mobile-first: class-based responsive CSS, meta grid collapses 4→2 columns under 640 px, action bar stacks on mobile and sits row-wise on desktop, title no longer breaks at em-dash (text-wrap: balance). Print CSS forces desktop layout back so PDFs stay compact
- Nuevo Wizard desktop layout: sticky top progress row, question content, and fixed bottom action bar share a consistent max-w-3xl inner column; fixed bottom bar gets md:left-60 so it starts past the 240 px sidebar instead of centering on the viewport
- Arreglo Image upload 400 error — null-tolerant schemas (questionId / caption) let multipart photo uploads succeed again. Verified end-to-end with a 631-byte test JPEG
- Arreglo enforceOnboarding middleware now skips beta accounts so demo / seed data always reaches the app without getting bounced to /onboarding
hace 1 mesGuided CheckUp wizard with adaptive questions, photos, EN/DE/ES i18n
8Nuevo
Guided CheckUp wizard with adaptive questions, photos, EN/DE/ES i18n
- Nuevo Prominent 'Start a new CheckUp' CTA card at the top of the dashboard — one tap kicks off the guided wizard
- Nuevo /checkups/wizard/{id}/step/{n} — mobile-first step page with sticky progress bar, type-aware inputs (yesno / single / multi / scale / text), keyboard shortcuts (Enter, J/N), optional note field, and camera-aware photo uploader with client-side canvas compression + EXIF strip
- Nuevo Adaptive conditional routing: questions with unmet `showIf` clauses are skipped server-side, so step numbers always point to the next visible question
- Nuevo Auto finding-rule engine: answers trigger deterministic findings (description + priority + effort + optional linked service code), tagged with sourceQuestionId so re-answering regenerates them in place without touching manual findings
- Nuevo /checkups/wizard/{id}/review — collapsible category groups, editable executive summary (auto-drafted from top-3 findings), add/remove findings, one-click Finalize, and Finalize+Quote when the CheckUp is on a project with service-mapped findings
- Nuevo 30 default questions across all 7 categories (Sicherheit / Updates / Backup / Netzwerk / Compliance / Hardware / Berechtigungen) — every prompt, context, option label and generated finding text in EN / DE / ES, stored as { en, de, es } JSON and resolved at render time via pickI18n()
- Nuevo /api/checkup-attachments/{id} streams uploaded photos with auth + org-ownership checks; uploads land under data/checkup-attachments/{orgId}/ and keep EXIF-stripped copies only
- Nuevo Smoke test: 12 new wizard + i18n assertions (catalog seeded with { en, de, es } JSON, pickI18n resolves across locales, conditional hiding, finding rules fire, EN/DE/ES wizard pages render locale-appropriate copy)
hace 1 mesPay-what-you-want, setup wizard, breadcrumbs, backup disclosure
5Nuevo1Cambiado3Arreglo
Pay-what-you-want, setup wizard, breadcrumbs, backup disclosure
- Cambiado Rebranded away from 'closed beta': product is now Free + Pay-what-you-want, forever. No trial, no gated plans, no upgrade nags — voluntary contributions only
- Nuevo Pay-what-you-want form (Settings → Billing + public /pay): set a net amount, pick one-time / monthly / yearly, live 19 % VAT calc + gross total, collapsible invoicing-details block (legal name, address, country, VAT ID, tax no.) so Lucas can issue a §14 UStG-compliant invoice without back-and-forth
- Nuevo Two PWYW submit paths: email inquiry (from noreply@mspercury.com → info@it-flores.de for manual arrangement) + Stripe Checkout with custom-amount price_data + Stripe Tax when configured
- Nuevo Setup wizard at /onboarding — new workspaces are gated here until they confirm workspace name, language, currency, VAT rate and optional brand color
- Nuevo Breadcrumb navigation on every menu-driven page (Dashboard → Customers → Acme GmbH etc.) — auto-derived from route, with per-page tail overrides for detail entities; never leaks raw IDs
- Nuevo Terms of Service & DPA now explicitly disclose the backup policy: daily full-server backups DO happen; per-tenant snapshots / workspace restore points DO NOT EXIST YET. Users are urged to use the built-in ZIP export
- Arreglo PWYW form: amount input and interval select are now baseline-aligned on desktop (long label no longer wraps and pushes the input below its neighbour)
- Arreglo "Save project" / "Save CheckUp" / "New quote" forms no longer silently fail when a required select had no preselected value — forms now default to the first available record
- Arreglo Stale service worker cleanup in dev mode now does ONE forced reload per tab so in-flight SW handlers stop intercepting form POSTs after the purge
hace 1 mesDocs + Changelog nav, SW dev-unregister, Post-Redirect-Get polish
2Nuevo3Arreglo
Docs + Changelog nav, SW dev-unregister, Post-Redirect-Get polish
- Nuevo Sidebar links to /docs and /changelog under a new Help section
- Nuevo /changelog page with date-grouped collapsible entries
- Arreglo Service worker is now disabled in dev mode and actively unregistered — stale caches no longer hide form-submit redirects
- Arreglo Settings actions (language, finance, branding, profile, AI) self-redirect after save so the page re-renders with fresh middleware locals, not stale ones
- Arreglo Primary buttons (New quote / New customer / New project / New CheckUp) get a dark-mode-aware accent variant so they're readable after theme inversion
hace 1 mesDark mode, Cmd+K search, AI integration, CSV + ZIP exports, /docs
10Nuevo
Dark mode, Cmd+K search, AI integration, CSV + ZIP exports, /docs
- Nuevo Three-state theme toggle (system / light / dark) in the top header, no-flash-on-load
- Nuevo Global command palette via Cmd/Ctrl+K — searches customers, projects, CheckUps, quotes, finding templates, services, packages
- Nuevo Desktop top header with search trigger + theme toggle; mobile top bar gets matching icons
- Nuevo AI integration: Anthropic (Claude) + OpenAI (GPT) providers, AES-GCM-encrypted API keys, "Generate executive summary" button on CheckUp editor, auto-embedded into PDF reports
- Nuevo CSV export per entity (/api/export/<entity>.csv) for customers, projects, quotes, CheckUps, findings, services, packages
- Nuevo Workspace ZIP export (GDPR Art. 20) — full workspace or per-customer, streamed via archiver, contains JSON + CSV + uploaded logo
- Nuevo /docs page with 12-section feature walkthrough in English
- Nuevo Logo upload + primary-color picker in Settings → Branding; both flow through to PDF templates
- Nuevo Spanish locale (es) in addition to English and German
- Nuevo Settings → Finance: workspace-level currency picker and default VAT rate
hace 1 mesCheckUp module, WeasyPrint PDF reports, invite-only beta
5Nuevo1Cambiado
CheckUp module, WeasyPrint PDF reports, invite-only beta
- Nuevo CheckUp audit module: finding templates library, priority + effort grading, quote generation from mapped findings, immutable snapshots on finalize
- Nuevo WeasyPrint-rendered PDF reports for CheckUps (cover + TOC + risk matrix + findings by category + methodology + appendix) and quotes (letterhead + line items per billing period + VAT breakdown + terms)
- Nuevo Invite-only beta signup gate: superadmin issues codes, signup requires ?invite=CODE, invited workspaces are flagged is_beta_account and exempt from Stripe lockout
- Nuevo Custom confirm modal replacing browser confirm() dialogs (mobile-first bottom-sheet, safe-area-insets)
- Nuevo PWA manifest + service worker + offline fallback + installable icons
- Cambiado Pricing model paused during closed beta — free for beta participants, Stripe code retained for later activation
hace 2 mesesMobile-first redesign, i18n, marketing + legal pages
7Nuevo
Mobile-first redesign, i18n, marketing + legal pages
- Nuevo Mobile-first nav: desktop sidebar + mobile top bar with drawer + bottom tab bar
- Nuevo EN/DE translation system with per-user preferredLanguage and Accept-Language fallback
- Nuevo Public marketing pages: landing, pricing, imprint, terms, privacy, DPA, cookies (EN + DE)
- Nuevo Design tokens: Geist font, warm stone-neutral ink scale, emerald accent, motion easing, shadow scale
- Nuevo Microsoft 365 OAuth login flow (multi-tenant, optional Graph organization read for auto-named workspace)
- Nuevo Hetzner SMTP mailer abstraction with EN/DE transactional templates (welcome, trial-ending, seat invite, payment receipt)
- Nuevo Stripe billing scaffolding: seat-based subscription, Customer Portal, Tax, webhook handler, trial lifecycle