diff --git a/.cursor/skills/sweetr-brand-voice/SKILL.md b/.cursor/skills/sweetr-brand-voice/SKILL.md new file mode 100644 index 00000000..1172b86d --- /dev/null +++ b/.cursor/skills/sweetr-brand-voice/SKILL.md @@ -0,0 +1,48 @@ +--- +name: sweetr-brand-voice +description: Sweetr brand voice and copywriting guide. Use when writing or editing any copy for sweetr.dev, including website headlines, feature descriptions, landing page sections, blog articles, meta descriptions, CTA text, changelog entries, social media posts, or any user-facing marketing text. Also use when reviewing existing copy for brand consistency. +--- + +# Sweetr Brand Voice + +Apply Sweetr's brand voice, terminology, and positioning when writing any copy. + +## Setup + +Read the full brand kit before writing: + +- **[BRAND_KIT.md](references/BRAND_KIT.md)**: Complete brand identity, positioning, differentiators, voice guidelines, messaging framework, terminology, and do's/don'ts. + +## Workflow + +### For website copy (headlines, features, CTAs, sections) + +1. Read BRAND_KIT.md sections 1–4 and 6 (Identity, Positioning, Differentiators, Voice, Terminology). +2. Identify which differentiator(s) the copy should reinforce. +3. Match tone to context (see "Tone by context" table in brand kit). +4. Write copy. Validate against the "Words we avoid" list. +5. Confirm the copy does not use "open source", surveillance language, or corporate-speak. + +### For blog articles + +1. Read BRAND_KIT.md sections 4, 5, and 9 (Voice, Messaging Framework, Blog Voice). +2. Write in founder-led, conversational tone. Be opinionated. Frame problems from the developer's POV. +3. Use the core narrative arc: world changed → gap exists → existing options fail → Sweetr is different → outcome. +4. End with a community-inviting CTA (try, star, contribute, give feedback). +5. Never name competitors directly. + +### For meta descriptions and SEO copy + +1. Use "Developer Intelligence Platform" as the category term. +2. Include relevant keywords: DORA metrics, developer experience, engineering performance. +3. Keep the `++` motif for brand recognition when space allows. + +## Critical rules (always apply) + +- **Never call Sweetr "open source."** We are fair source (FSL license). Use "fair source", "source-available", or "built in the open." +- **Never use surveillance language** (monitor, track individuals, rank, score developers). +- **Never name competitors.** +- **Always frame features as team/process improvements**, never as individual measurement. +- **Brand name is `sweetr.dev`** (lowercase, with `.dev`). Short form: Sweetr (capital S only). +- **Never use em dashes (—).** Use periods, commas, or restructure the sentence instead. +- **Sound human, not like AI.** Avoid fancy/flowery words that real developers would never say. Banned words include: erode, delve, elevate, harness, foster, empower, unleash, bolster, spearhead, holistic, pivotal, transformative, streamline, paradigm, synergy, encompass, multifaceted, nuanced, underscore, facilitate, robust, scalable (unless literally about infrastructure), seamless, cutting-edge, groundbreaking, unparalleled, fortify, commencing, aforementioned, culminate, discern, elucidate, endeavor, intricate, myriad, paramount, perpetuate, proliferate, quintessential, resonate, subsequently, traverse, utilize (use "use"), whilst, navigate (as metaphor), landscape (as metaphor), ecosystem (unless literal), moreover, furthermore, additionally, comprehensive, meticulous, realm, testament, embark, journey (as metaphor), pave the way, shed light on, at its core, notably, interestingly, crucial, it's worth noting that, in today's [anything] world. If a word feels like it belongs in a college essay, pick a simpler one. diff --git a/.cursor/skills/sweetr-brand-voice/references/BRAND_KIT.md b/.cursor/skills/sweetr-brand-voice/references/BRAND_KIT.md new file mode 100644 index 00000000..d61ed7be --- /dev/null +++ b/.cursor/skills/sweetr-brand-voice/references/BRAND_KIT.md @@ -0,0 +1,352 @@ +# Sweetr Brand Kit + +## 1. Brand Identity + +### Name + +- **Full name**: sweetr.dev (always lowercase, always with `.dev`) +- **Short reference**: Sweetr (capitalized only when starting a sentence or used as a proper noun in flowing copy) +- **Never**: SWEETR, Sweetr.dev (capital S on the domain), SweetR + +### Tagline + +> The open platform for Engineering Performance++ + +The `++` is a deliberate code-inspired suffix. It signals continuous improvement using language developers instantly recognize (increment operator). Use it in headlines and meta descriptions. It is part of the brand identity. + +### One-liner + +> Insights and automations your dev team will actually trust. Built in the open. No surveillance or $50/seat price tag. + +### Boilerplate (longer description) + +> Sweetr is the open platform for engineering performance. It gives engineering leaders DORA metrics, delivery insights, and workflow automations. All source-available, free to self-host, and built without surveillance or harmful individual metrics. Connect GitHub and Slack, get visibility in minutes, and improve delivery in ways developers will actually thank you for. + +--- + +## 2. Brand Positioning + +### Category + +- **Developer Intelligence Platform**: Use in SEO, meta descriptions, analyst-facing contexts, and category-positioning copy. Aligns with Gartner's emerging category definition. +- **Engineering Performance**: Use in brand headlines and tagline contexts where the `++` motif works. Punchier, more memorable, distinctly Sweetr. + +### Who we serve + +| Persona | Role | What they care about | +| ------------- | ----------------------------------- | -------------------------------------------------------------------------------------- | +| **Primary** | Engineering Managers, Team Leads | Unblocking their team, coaching with data, preparing for 1:1s, improving delivery flow | +| **Secondary** | Directors of Engineering, VPs, CTOs | Org-wide visibility, DORA benchmarks, data-driven investment decisions | +| **Tertiary** | Individual Contributors | Making their work visible, supporting promotion cases, getting unblocked faster | + +### How we position for each persona + +**For developers**: "Get unblocked without asking. Less status reporting, more building." + +**For managers**: "Proactively unblock the team. Have better conversations with the team." + +**For C-level**: "Drive more value per developer. Make data-driven decisions." + +### Market positioning + +Sweetr sits at the intersection of developer experience tools and engineering analytics, but rejects the surveillance playbook that dominates the category. We are closer to a team health tool than a productivity tracker. + +--- + +## 3. Core Differentiators + +These are the pillars that make Sweetr unique. Every piece of copy should reinforce at least one. + +### 3.1 Not a surveillance tool + +This is the single most important differentiator. The entire industry has a trust problem. Tools that track individual keystrokes, rank developers against each other, and feed toxic management. Sweetr explicitly rejects this. + +**How to express it:** + +- "We don't count commits or rank developers. That's toxic. Full visibility without compromising trust." +- "No Big Brother vibes." +- "Improvement is built on trust." +- "Insights your dev team will actually trust." +- Never frame features as ways to monitor individuals. Always frame them as ways to improve the team, the process, or the system. + +**What we never say:** + +- "Track developer productivity" +- "Measure individual performance" +- "Developer ranking" or "leaderboard" +- "Monitor your developers" +- Any language that implies surveillance, scoring individuals, or pitting developers against each other + +### 3.2 Fair source & community-oriented + +Sweetr's code is public on GitHub under the **Functional Source License (FSL)**, the same license used by Sentry. This makes us **fair source**, not open source. This distinction matters: license purists will call it out, and we should never give them reason to. + +**The rule: Never call Sweetr "open source."** Use "fair source", "source-available", or "built in the open" instead. The tagline says "the open platform". That refers to openness and transparency as values, not to the OSI definition of "open source." + +**How to express it:** + +- "Fair source. Same license as Sentry." +- "From code to community, Sweetr is made in the open." +- "Easy to audit, extend, and trust." +- "Community-oriented & source-available." +- Reference the GitHub repo naturally: source code links, star count, contribution guide. + +**What we never say:** + +- "Open source" or "open-source" as a descriptor for Sweetr's license +- "FOSS" or "Free and Open Source Software" +- Any phrasing that implies OSI-approved open source licensing + +### 3.3 Free to self-host + +Self-hosting is free, forever. This is a trust signal and a pricing differentiator. It means organizations with strict data requirements can run Sweetr on their own infra at no cost. + +**How to express it:** + +- "Self-host for free." +- "Free to self-host, forever." +- Pair with Cloud pricing to frame the choice, not the constraint: "No credit card required to get started. Self-host for free." + +### 3.4 Radically affordable + +Cloud pricing is $10/contributor/month (or $8 with yearly billing). This is a fraction of competitors who charge $30–50/seat. We don't feature-gate plans. + +**How to express it:** + +- "No $50/seat price tag." +- "A fraction of what you'd pay elsewhere." +- "Simplified plan with no feature-gating." +- Highlight the 14-day free trial (no credit card). + +### 3.5 Developer-first by principle + +We publish guiding principles. Every design decision runs through the filter of "would a developer trust this?" We don't surface data that can be weaponized. We focus on team-level signals. + +**How to express it:** + +- "Developer-first." +- Reference the published guiding principles doc. +- "Full visibility without compromising trust." +- "Focused data exposure made to surface only what matters. Not overwhelm you." + +### 3.6 Clear by design + +Competitors are bloated dashboards. Sweetr deliberately limits data exposure to what's actionable. Simplicity is a feature. + +**How to express it:** + +- "Clear by design." +- "Surface only what matters. Not overwhelm you." +- "Simple and intuitive interfaces." +- "Not overwhelm you with data you don't need." + +--- + +## 4. Brand Voice & Tone + +### Voice attributes + +| Attribute | Description | Example | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| **Direct** | Get to the point. No filler. No corporate fluff. | "PRs get stuck. Hidden bottlenecks slow down delivery." Not: "In many organizations, pull requests can sometimes encounter..." | +| **Developer-native** | Use the language developers use. PRs, DORA, cycle time, merge, deploy, Slack, GitHub. Don't over-explain technical concepts. | "Alert when an approved PR has been waiting for merge for too long." | +| **Empathetic** | We understand the pain. We've been there. We're not lecturing, we're helping. | "Struggling teammates go unseen." / "Detect when someone might be struggling." | +| **Confident, not arrogant** | We know what we stand for. We state it plainly. We don't trash competitors by name. | "Built in the open. No surveillance or $50/seat price tag." | +| **Warm & slightly playful** | The brand is called "Sweetr." Lean into that warmth. Use the `++` motif. Keep it human. | "The sweetest Developer Intelligence Platform." / "Engineering Performance++" | +| **Anti-corporate** | We don't write like enterprise software. No buzzword salad. No "synergy." No "leverage." | "Automate. Reduce friction. Measure, iterate, and repeat." | + +### Tone by context + +| Context | Tone | +| -------------------- | ---------------------------------------------------------------------------------- | +| Hero / headlines | Bold, punchy, aspirational. Short sentences. Code metaphors welcome. | +| Feature descriptions | Clear, practical, benefit-oriented. Show the "use it to" value. | +| Problem statements | Empathetic, slightly urgent. Name the pain directly. | +| Pricing / FAQ | Transparent, reassuring, no-nonsense. | +| CTA buttons | Action-oriented, specific. "Install the GitHub app" > "Get started" > "Learn more" | +| Blog posts | Conversational, honest, founder-voice. Must be opinionated. | +| Legal / security | Straightforward, factual, confidence-building. | + +### Sentence style + +- Prefer short sentences. Break up complex ideas. +- Use fragments when they hit harder. "Wrong priorities. Missed outcomes." +- Use line breaks for emphasis in subheadings. +- Avoid passive voice. "Sweetr syncs your GitHub data automatically" not "Your GitHub data is synced automatically by Sweetr." +- Use second person ("you", "your team") not third person ("the user", "one's team"). +- Never use em dashes. Use periods, commas, or restructure the sentence. +- Write like a human, not like AI. Use simple, plain words. If a word feels like it belongs in a college essay or a thesaurus, pick a simpler one. + +--- + +## 5. Messaging Framework + +### The core narrative + +**The world changed**: AI made coding faster, but teams didn't automatically become more productive. Bottlenecks just shifted elsewhere. + +**The gap**: Leaders can't see where delivery breaks down. Developers get stuck. Problems stay invisible. Decisions happen without signals. + +**The existing options fail**: Legacy tools are expensive, bloated, and built on surveillance. They break trust instead of building it. + +**Sweetr is different**: An open platform that gives teams visibility and automation without the surveillance tax. Built on trust, priced fairly, source-available. + +**The outcome**: Delivery flows again. Developers get unblocked. Leaders make better decisions. Everyone trusts the tool. + +### Key messages by theme + +**Trust & anti-surveillance:** + +- "Improvement is built on trust." +- "No overhead. No Big Brother vibes. Just the visibility and momentum your team needs." +- "We don't count commits or rank developers. That's toxic. " + +**Visibility & insights:** + +- "Make delivery flow again." +- "Uncover friction, automate workflows, and improve DX in ways developers will thank you for." +- "Spot blockers, patterns, and where to improve." + +**Openness & transparency:** + +- "Built in the open." +- "From code to community, Sweetr is made in the open." +- "Easy to audit, extend, and trust." + +**Speed & simplicity:** + +- "Get started in under 30 seconds." +- "Onboard in minutes." +- "Fast to adopt and flexible to rollout." +- "Connect GitHub & Slack and you're ready to go." + +**AI-era relevance:** + +- "Coding got faster. Delivery didn't." +- "AI made coding faster, but teams didn't automatically become more productive. Instead, it shifted the bottlenecks elsewhere." +- "Success still depends on leaders identifying bottlenecks, improving processes and creating good working conditions for the team." + +### Problem framing (use in pain-point sections) + +| Problem | One-liner | +| ------------------- | --------------------------------------------------------------- | +| Stuck PRs | "PRs get stuck. Hidden bottlenecks slow down delivery." | +| Invisible struggles | "Problems stay invisible. Struggling teammates go unseen." | +| Blind decisions | "Decisions without signals. Wrong priorities. Missed outcomes." | +| AI paradox | "Coding got faster. Delivery didn't." | + +--- + +## 6. Naming & Terminology + +### Product terminology + +| Term | Usage | +| ----------- | ---------------------------------------------------------------------- | +| sweetr.dev | The product/brand. Lowercase with .dev in running text. | +| Cloud | The hosted SaaS plan. | +| Enterprise | The large-scale plan with on-premise option. | +| GitHub app | How users install Sweetr. "Install the GitHub app." | +| Contributor | Billing unit. Anyone who created or reviewed a PR in the last 30 days. | + +### Words we use + +- **Delivery** (not "output" or "velocity") +- **Visibility** (not "monitoring" or "tracking") +- **Insights** (not "analytics" or "reports") +- **Friction** (what we help remove) +- **Flow** (what we help restore) +- **Trust** (the foundation) +- **Bottleneck** (what we help identify) +- **Signal** (what leaders need) +- **DX** / **Developer Experience** (what we improve) + +### Words we avoid + +- **Monitor** / **Monitoring** (surveillance connotation) +- **Track** / **Tracking** (when referring to individuals; OK for "track DORA metrics") +- **Rank** / **Ranking** (implies individual competition) +- **Score** / **Scoring** (implies judgment) +- **Productivity** (alone, too loaded; always pair with context: "team productivity", "delivery performance") +- **Leverage** / **Synergy** / **Paradigm** (corporate speak) +- **Cutting-edge** / **Revolutionary** / **Best-in-class** (empty superlatives) +- **AI-powered** (unless Sweetr actually uses AI in a specific feature; don't claim it generically) +- **AI-sounding words**: erode, delve, elevate, harness, foster, empower, unleash, bolster, spearhead, holistic, pivotal, transformative, streamline, paradigm, encompass, multifaceted, nuanced, underscore, facilitate, robust, seamless, groundbreaking, unparalleled, fortify, commencing, aforementioned, culminate, discern, elucidate, endeavor, intricate, myriad, paramount, perpetuate, proliferate, quintessential, resonate, subsequently, traverse, utilize (just say "use"), whilst, navigate (as metaphor), landscape (as metaphor), ecosystem (unless literal), moreover, furthermore, additionally, comprehensive, meticulous, realm, testament, embark, journey (as metaphor), pave the way, shed light on, at its core, notably, interestingly, crucial, it's worth noting that, in today's [anything] world + +--- + +## 7. Visual Identity + +### Brand color + +- **Primary**: Green (`#69DB7C` / `rgb(105, 219, 124)`) — used for accents, CTAs, emphasis text, icons +- **Background**: Dark (`#141517` range) — the product lives in a dark UI +- **Danger/problem accent**: Red (`#F87171`) — used only for problem statements and pain-point sections +- **Text**: White for headings, zinc/gray tones for body copy + +--- + +## 8. Competitive Positioning (how to talk about competitors) + +### General rule + +Never name competitors. Never trash them. Let the differentiators speak. + +### Positioning against the market + +| Market problem | Our position | +| ---------------------------------- | ----------------------------------------------------------- | +| "$50/seat pricing" | "$10/contributor. No feature-gating." | +| Proprietary black boxes | "Source-available. Audit the code yourself." | +| Surveillance / individual tracking | "We don't count commits or rank developers. That's toxic. " | +| Bloated dashboards | "Clear by design. Only what matters." | +| Long onboarding | "Onboard in minutes. Connect GitHub & Slack." | +| Vendor lock-in | "Self-host for free, forever." | + +### The "anti" framing + +Sweetr defines itself partly by what it is not. This is powerful but should be used sparingly, mostly in hero/positioning sections, not in every feature description. + +- "No surveillance or $50/seat price tag." +- "No Big Brother vibes." +- "Not overwhelm you with data you don't need." +- After establishing what we're against, always pivot to what we're for. + +--- + +## 9. Blog & Long-form Voice + +The blog uses a founder-led, conversational voice. Key traits: + +- **Honest about industry problems**: Call out toxic metrics, expensive tools, bad UX directly. +- **Opinionated**: Take clear stances. "Most tools out there today have serious downsides." +- **Community-inviting**: End with calls to try, star, contribute, give feedback. +- **Developer empathy**: Frame problems from the developer's POV before presenting solutions. +- **No marketing polish**: Write like you're explaining to a peer, not selling to a buyer. + +--- + +## 10. Quick Reference: Do's and Don'ts + +### Do + +- Use developer-native language (PRs, DORA, cycle time, deploy) +- Frame everything around team improvement, not individual measurement +- Reference openness (source code, self-hosting, community) +- Keep sentences short and punchy +- Use "you" and "your team" +- Name the pain directly before presenting the solution +- Link to docs frequently + +### Don't + +- Use surveillance language (monitor, track individuals, rank, score) +- Write in corporate-speak (leverage, synergy, best-in-class) +- Use fancy/flowery AI-sounding words (erode, delve, elevate, harness, foster, empower, etc.) +- Use em dashes +- Over-explain technical concepts to the audience +- Feature-gate or create artificial scarcity in messaging +- Use the word "free" without specifying context (self-host is free; Cloud has a trial) +- Make AI claims unless a specific feature uses AI +- Name competitors +- Call Sweetr "open source". We are fair source (FSL license), not OSI open source diff --git a/.cursor/skills/sweetr-brand-voice/references/WEBSITE.md b/.cursor/skills/sweetr-brand-voice/references/WEBSITE.md new file mode 100644 index 00000000..8556ad89 --- /dev/null +++ b/.cursor/skills/sweetr-brand-voice/references/WEBSITE.md @@ -0,0 +1,530 @@ +[Logo] + +sweetr.dev + +- Features +- Our approach +- Pricing +- Docs +- GitHub +- Sign In +- Get started + +- Features +- Our approach +- Pricing +- Docs + +- + Star us on GitHub +- Dashboard + +Until April 30th: Use "SWEETDEAL" to get 50% off your first six months + +Coupon code "SWEETDEAL" copied to clipboard! + +The open platform for Engineering Performance++ + +Insights and automations your dev team will actually trust. Built in the open — no surveillance or $50/seat price tag. + +security-first + +• + +self-host for free + +• + +source code + +Read the docs + +Install the GitHub app + +[Hero Image] + +Coding got faster. Delivery didn’t. + +When delivery slowed down, could you pinpoint the cause? + +PRs get stuck + +Hidden bottlenecks slow down delivery. + +Problems stay invisible + +Struggling teammates go unseen. + +Decisions without signals + +Wrong priorities. Missed outcomes. + +AI + +AI made coding faster, but teams didn’t automatically become more +productive. Instead, it shifted the bottlenecks elsewhere. +Success still depends on leaders identifying bottlenecks, improving +processes and creating good working conditions for the team. + +[Logo] + +Make delivery flow again + +Uncover friction, automate workflows, and improve DX in ways developers +will thank you for. + +1. Connect + +- Install our GitHub & Slack apps. +- Your org data is synced in minutes. + +2. Understand + +- Get visibility into your team's work. +- Spot blockers, patterns, and where to improve. + +3. Improve + +- Automate. Reduce friction. +- Measure, iterate, and repeat. + +Views & Insights + +DORA MetricsWork In ProgressWork LogPull RequestsCode ReviewsCode Review +DistributionPull Request Size + +Automations + +AlertsDigestsIncident DetectionPR Size LabelerPR Title Check + +Views & Insights + +- DORA Metrics +- Work In Progress +- Work Log +- Pull Requests +- Code Reviews +- Code Review Distribution +- Pull Request Size + +Automations + +- Alerts +- Digests +- Incident Detection +- PR Size Labeler +- PR Title Check + +Work Log + +A weekly view of your team's pull requests and code reviews. Each icon +represents a PR or review, and grows in size with the change. Spot where +work flows, where it piles up, and where it's stuck. + +Use it to + +- Spot workload imbalance: Quickly see if work is spread evenly or if + someone is consistently overloaded. +- Prepare for 1:1s: Walk into conversations with concrete context on + what happened that week, not just gut feelings. +- Recognize effort, not just volume: Fewer, larger icons mean someone + tackled a big piece of work. Not every week needs a wall of dots. +- Check in early: A quiet week can mean someone is blocked. Use it as + a signal to offer support, not to judge. +- Build your brag document: Developers can use their Work Log to + highlight contributions during 1:1s or performance reviews. + +Learn more + +Work In Progress + +Real-time view of the team's open Pull Requests, grouped by status. + +Use it to + +- Facilitate daily meetings. +- Identify blocked PRs. +- Identify PRs with a lot of comments that might need attention. +- Schedule a digest to be sent to Slack, keeping everyone in the loop. + +Learn more + +DORA Metrics + +The industry standard for measuring software delivery performance, +backed by years of research from the DORA team. + +The 4 key metrics + +Deployment Frequency + +How often your team ships to production. + +Lead Time for Changes + +Time from first commit to production. + +Change Failure Rate + +Percentage of deployments that cause incidents. + +Mean Time to Recovery + +How quickly your team recovers from failures. + +Use it to + +- Catch regressions in delivery speed or stability early. +- Track the impact of process changes with real data. +- Give leadership visibility without manual reporting. +- Set goals around outcomes, not just output. + +Learn more + +Pull Requests + +Filterable list of a team's pull requests, filled with lifecycle +insights. + +Use it to + +- Identify ongoing blocked PRs that need attention. +- Locate past PRs that got stuck and identify the reason why. +- Locate PRs with too much back-and-forth. +- Get a grasp on PR size. Encourage the team to create smaller PRs for + faster cycle time. + +Learn more + +Code Review + +View your team's code reviews. + +Use it To + +Help developers grow as reviewers. + +- Understand review frequency and depth. +- Spot rubber-stamp approvals. +- Have better coaching conversations. + +Learn more + +Code Review Distribution + +Insights on code review balance in the team. + +Insights + +This chart can help you measure and answer questions like: + +- Is review load unevenly distributed? +- Could anyone help with more code reviews? +- Is any reviewer interacting only with selected members of the team? +- Is considerable time being spent on reviewing other teams' code? +- Is our strategy to assign reviewers effective? + +Learn more + +PR Size + +Breakdown of team's Pull Request size and frequency. + +Insights + +This chart can help you measure and answer questions like: + +- Is the team striving for small Pull Requests? +- Is review or merge time slow because of big Pull Requests? + +Learn more + +Alerts + +Real-time configurable Slack alerts for Pull Requests needing attention. + +Slow review + +Alert when an open Pull Request has been waiting for review for too +long. +You can set up the minimum idle time to trigger the alert. + +Improves cycle time + +Improves time to approval + +------------------------------------------------------------------------ + +Slow merge + +Alert when an approved Pull Request has been waiting for merge for too +long. +You can set up the minimum idle time to trigger the alert. + +Improves cycle time + +Improves time to merge + +------------------------------------------------------------------------ + +Merged without approval + +Alert when a Pull Request is merged without approvals. + +Improves failure rate + +Learn more + +Digests + +Scheduled Slack digests to keep teams informed and aligned. + +Metrics Digest + +Enabling this digest should help teams understand their flow, and areas +for improvement. It helps with accountability and removes the hurdle of +having to manually check the metrics in the Sweetr dashboard. + +Work In Progress Digest + +Enabling this digest should help team alignment, by bringing light to +any PRs that may need attention, and keeping everyone in the loop. + +Learn more + +Incident Detection + +Automatically ingest incidents from deployments where rollbacks, +hotfixes or reverts were performed. + +Improves data accuracy + +More accurate failure rate on your DORA metrics. Remove manual work from +incident reporting. + +Learn more + +PR Size Labeler + +Automatically label a Pull Request in GitHub with its size. + +Use Cases + +When enabled, Sweetr will automatically add a label indicating the size +of the changes on every new Pull Request in GitHub. You can customize +the labels and their colors. Customize how PR size is calculated in your +workspace settings. + +Improves cycle time + +Encourage faster reviews on smaller PRs. + +Improves failure rate + +Mitigate reviewer fatigue with smaller PRs. + +Learn more + +PR Title Check + +Enforce PR title standards across your organization. + +Define a regular expression to validate Pull Request title across your +organization. You can make it blocking by adding branch protection rules +in your repository. + +Improves compliance + +Standardize Pull Request titles across the organization. + +Learn more + +Improvement is built on trust + +No overhead. No Big Brother vibes. Just the visibility and momentum your team needs. + +Developer-first + +We don't count commits or rank developers. That's toxic. We give you +context to coach, not score. Read our guiding principles. + +[] + +Clear by design + +Focused data exposure made to surface only what matters — not overwhelm +you. + +[] + +Onboard in minutes + +Fast to adopt and flexible to rollout. Connect GitHub & Slack and you're +ready to go. + +[] + +Engineered to delight + +Built for security, data accuracy, performance, and user experience +since day zero. + +[] + +Community-oriented & source-available + +From code to community, Sweetr is made in the open. Easy to audit, +extend, and trust. Submit contributions, share feedback, and help drive +our roadmap. + +[] + +A lot more to come + +A sneak peek into our planned features. + +AI Agents + +Generate release notes, chat with your data, classify work items, and +more. + +DX Surveys + +Qualitative data through automated surveys tailored for developers. + +AI Adoption + +Track AI adoption, usage, and impact on delivery metrics. + +Wellbeing + +More wellbeing-focused insights for increased developer satisfaction and +wellness. + +1:1s + +A new experience for managers and leaders to coach their teams. + +More Integrations + +All of your toolstack: GitLab, JIRA, Linear, Calendar, PagerDuty, and +others. + +Check the roadmap + +Pricing + +No credit card required to get started. Self-host for free. + +Monthly + +Yearly + +20% off + +Cloud + +For organizations that move fast. + +$10 /mo + +Per contributor. + +- All features + +- 1 year data retention + +- Regular support + +Start 14-day trial + +Enterprise + +For organizations operating at large scale. + +Contact us + +- All features + +- Unlimited contributors + +- On-premise supported + +- 3+ years data retention + +- Priority support + +Book a demo + +What is a contributor? + +A contributor is anyone who has created or reviewed a Pull Request in +the last 30 days. + +Is my repository code safe? + +Absolutely. Sweetr does not have access to your code. We follow strict +security best practices to protect our servers and application. Read +more + +Is self-hosting available? + +Yes! Self-hosting is free, forever. However, it comes with maintenance +and setup hurdles. We recommend the Cloud version unless you have hard +requirements to manage your own infrastructure. Learn how to self-host. + +Is training needed? + +Not at all, you and your team should be able to use Sweetr without any +prior training. We design simple and intuitive interfaces, and our +documentation is thorough. + +How is my data used? Can it be removed? + +Sweetr only saves data necessary to provide service to you. You can +delete all of your private data from our servers by revoking OAuth +access or uninstalling our application from your GitHub account or +organization at any moment.Read our privacy policy. + +Is GitLab or BitBucket supported? + +Not yet. They are in our backlog, you can check their status on +Featurebase. + +BitBucket • GitLab + +Are contributions accepted? + +For sure! We welcome PRs from the community. You can learn more in our +contribution guide. + +[Logo] + +Get started in under 30 seconds + +Connect your GitHub organization now and start a 14-day free trial. + +Install the GitHub app + +[Logo] + +© sweetr.dev. All rights reserved. + +- +- + +Resources + +- Documentation +- Blog +- Changelog +- Roadmap +- System status + +Legal + +- License +- Terms and Conditions +- Privacy policy +- Cookies Policy +- Data Processing diff --git a/apps/api/src/app/api-keys/services/api-keys.service.ts b/apps/api/src/app/api-keys/services/api-keys.service.ts index 8b7a0863..9d565137 100644 --- a/apps/api/src/app/api-keys/services/api-keys.service.ts +++ b/apps/api/src/app/api-keys/services/api-keys.service.ts @@ -41,6 +41,9 @@ export const regenerateApiKey = async ( return key; }; +export const getBearerToken = (header: string | undefined): string => + (header ?? "").trim().replace(/^bearer\s+/i, ""); + export const findApiKeyOrThrow = async (key: string) => { if (!key) { throw new AuthorizationException("Invalid API key"); diff --git a/apps/api/src/app/deployment/deployments.router.ts b/apps/api/src/app/deployment/deployments.router.ts index 56fa004a..eddcb7b8 100644 --- a/apps/api/src/app/deployment/deployments.router.ts +++ b/apps/api/src/app/deployment/deployments.router.ts @@ -3,14 +3,17 @@ import { addJob, SweetQueue } from "../../bull-mq/queues"; import { validateInputOrThrow } from "../validator.service"; import { postDeploymentValidationSchema } from "./services/deployment.validation"; import { logger } from "../../lib/logger"; -import { findApiKeyOrThrow } from "../api-keys/services/api-keys.service"; +import { + findApiKeyOrThrow, + getBearerToken, +} from "../api-keys/services/api-keys.service"; export const deploymentsRouter: FastifyPluginAsync = async (fastify) => { fastify.post("/v1/deployments", async (request, reply) => { logger.debug("http.deployments.create", { body: request.body }); const apiKey = await findApiKeyOrThrow( - request.headers.authorization as string + getBearerToken(request.headers.authorization) ); const payload = await validateInputOrThrow( diff --git a/apps/api/src/app/deployment/deployments.router.unit.test.ts b/apps/api/src/app/deployment/deployments.router.unit.test.ts new file mode 100644 index 00000000..043761db --- /dev/null +++ b/apps/api/src/app/deployment/deployments.router.unit.test.ts @@ -0,0 +1,237 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import Fastify, { type FastifyInstance } from "fastify"; + +vi.mock("../../env", () => ({ + env: { FRONTEND_URL: "http://localhost" }, + isProduction: false, + isDev: true, +})); + +vi.mock("../../lib/logger", () => ({ + logger: { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }, +})); + +vi.mock("../../lib/sentry", () => ({ + captureException: vi.fn(), + setupFastifyErrorHandler: vi.fn(), +})); + +vi.mock("../api-keys/services/api-keys.service", () => ({ + findApiKeyOrThrow: vi.fn(), + getBearerToken: (header: string | undefined) => + (header ?? "").trim().replace(/^bearer\s+/i, ""), +})); + +vi.mock("../../bull-mq/queues", () => ({ + addJob: vi.fn(), + SweetQueue: { DEPLOYMENT_TRIGGERED_BY_API: "deployment.triggered_by_api" }, +})); + +import { deploymentsRouter } from "./deployments.router"; +import { errorHandler } from "../../lib/fastify-helpers"; +import { AuthorizationException } from "../errors/exceptions/authorization.exception"; + +import { findApiKeyOrThrow } from "../api-keys/services/api-keys.service"; +import { addJob } from "../../bull-mq/queues"; + +const mockedFindApiKey = vi.mocked(findApiKeyOrThrow); +const mockedAddJob = vi.mocked(addJob); + +const validBody = { + repositoryFullName: "acme/backend", + environment: "production", + app: "backend-api", + version: "v1.0.0", + commitHash: "abc123", +}; + +describe("POST /v1/deployments", () => { + let app: FastifyInstance; + + beforeEach(async () => { + app = Fastify(); + app.setErrorHandler(errorHandler); + await app.register(deploymentsRouter); + await app.ready(); + + mockedFindApiKey.mockResolvedValue({ id: 1, workspaceId: 42 } as any); + mockedAddJob.mockResolvedValue(undefined as any); + }); + + afterEach(async () => { + vi.restoreAllMocks(); + await app.close(); + }); + + it("returns 401 when authorization header is missing", async () => { + mockedFindApiKey.mockRejectedValue( + new AuthorizationException("Invalid API key") + ); + + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + payload: validBody, + }); + + expect(response.statusCode).toBe(401); + }); + + it("returns 401 when API key is invalid", async () => { + mockedFindApiKey.mockRejectedValue( + new AuthorizationException("Invalid API key") + ); + + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "Bearer bad-key" }, + payload: validBody, + }); + + expect(response.statusCode).toBe(401); + }); + + it("strips Bearer prefix before validating the key", async () => { + await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "Bearer my-secret-key" }, + payload: validBody, + }); + + expect(mockedFindApiKey).toHaveBeenCalledWith("my-secret-key"); + }); + + it("works without Bearer prefix", async () => { + await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "raw-key" }, + payload: validBody, + }); + + expect(mockedFindApiKey).toHaveBeenCalledWith("raw-key"); + }); + + it("returns 422 when required fields are missing", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: { repositoryFullName: "acme/backend" }, + }); + + expect(response.statusCode).toBe(422); + expect(response.json().validationErrors).toBeDefined(); + }); + + it("returns 422 when fields exceed max length", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: { ...validBody, version: "x".repeat(71) }, + }); + + expect(response.statusCode).toBe(422); + }); + + it("returns 422 when deployedAt is not a valid ISO 8601 datetime", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: { ...validBody, deployedAt: "not-a-date" }, + }); + + expect(response.statusCode).toBe(422); + }); + + it("returns 202 and enqueues a job on success", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "Bearer valid-key" }, + payload: validBody, + }); + + expect(response.statusCode).toBe(202); + expect(mockedAddJob).toHaveBeenCalledOnce(); + expect(mockedAddJob).toHaveBeenCalledWith( + "deployment.triggered_by_api", + expect.objectContaining({ + workspaceId: 42, + repositoryFullName: "acme/backend", + environment: "production", + app: "backend-api", + version: "v1.0.0", + commitHash: "abc123", + }) + ); + }); + + it("passes deployedAt as a Date when provided", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: { ...validBody, deployedAt: "2025-01-15T10:00:00Z" }, + }); + + expect(response.statusCode).toBe(202); + expect(mockedAddJob).toHaveBeenCalledWith( + "deployment.triggered_by_api", + expect.objectContaining({ + deployedAt: new Date("2025-01-15T10:00:00Z"), + }) + ); + }); + + it("defaults deployedAt to current time when not provided", async () => { + const before = new Date(); + + await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: validBody, + }); + + const after = new Date(); + const jobData = mockedAddJob.mock.calls[0][1] as any; + expect(jobData.deployedAt.getTime()).toBeGreaterThanOrEqual( + before.getTime() + ); + expect(jobData.deployedAt.getTime()).toBeLessThanOrEqual(after.getTime()); + }); + + it("includes optional fields in the job payload", async () => { + const response = await app.inject({ + method: "POST", + url: "/v1/deployments", + headers: { authorization: "key" }, + payload: { + ...validBody, + description: "Release v1.0.0", + author: "jane-doe", + monorepoPath: "packages/api", + }, + }); + + expect(response.statusCode).toBe(202); + expect(mockedAddJob).toHaveBeenCalledWith( + "deployment.triggered_by_api", + expect.objectContaining({ + description: "Release v1.0.0", + author: "jane-doe", + monorepoPath: "packages/api", + }) + ); + }); +}); diff --git a/apps/api/src/fastify.ts b/apps/api/src/fastify.ts index b885e433..108c7aad 100644 --- a/apps/api/src/fastify.ts +++ b/apps/api/src/fastify.ts @@ -1,5 +1,6 @@ import Fastify, { FastifyServerOptions } from "fastify"; import cors from "@fastify/cors"; +import rateLimit from "@fastify/rate-limit"; import rawBody from "fastify-raw-body"; import formbody from "@fastify/formbody"; import { yoga } from "./yoga"; @@ -13,6 +14,7 @@ import { env } from "./env"; import { deploymentsRouter } from "./app/deployment/deployments.router"; import { healthRouter } from "./app/health/health.router"; import { isAppSelfHosted } from "./lib/self-host"; +import { getBearerToken } from "./app/api-keys/services/api-keys.service"; export async function buildApp(opts: FastifyServerOptions = {}) { const app = Fastify(opts); @@ -37,17 +39,29 @@ export async function buildApp(opts: FastifyServerOptions = {}) { done(null) ); + // Integration APIs await app.register(healthRouter); await app.register(githubRouter); + await app.register(slackRouter); + await app.register(bullBoardRouter); if (!isAppSelfHosted()) { await app.register(stripeRouter); } - await app.register(slackRouter); - await app.register(bullBoardRouter); - await app.register(deploymentsRouter); + // User-facing APIs. All routes registered inside this scope are rate limited. + await app.register(async (scope) => { + await scope.register(rateLimit, { + max: 100, + timeWindow: "1 minute", + keyGenerator: (request) => + getBearerToken(request.headers.authorization) || request.ip, + }); + + await scope.register(deploymentsRouter); + }); + // GraphQL app.route({ url: yoga.graphqlEndpoint, method: ["GET", "POST", "OPTIONS"], diff --git a/apps/docs/about/data-privacy-and-security.mdx b/apps/docs/about/data-privacy-and-security.mdx index c061006c..c927a2b5 100644 --- a/apps/docs/about/data-privacy-and-security.mdx +++ b/apps/docs/about/data-privacy-and-security.mdx @@ -1,11 +1,11 @@ --- title: Data-privacy & Security -icon: "shield-keyhole" +icon: "shield" --- import GithubPermissions from "/snippets/github-permissions.mdx"; -At Sweetr, we prioritize the security and privacy of our users. We implement the best security measures to ensure our services are secure and reliable. Our dedication to protecting your data is unwavering, and we continually update our practices to meet the highest security standards. +Your data security and privacy come first. We follow strict security best practices to protect our servers and application. ## Data deletion @@ -13,7 +13,7 @@ We understand the importance of data privacy. Upon uninstalling our GitHub app, ## Source code handling -We do not store any of your repositories' source code. Our services operate by accessing only the necessary information required to provide our tools and features, ensuring that your intellectual property remains secure and private. +We do not store any of your repositories' source code. We only access the metadata required to provide our tools and features. ## GitHub permissions @@ -21,21 +21,18 @@ We do not store any of your repositories' source code. Our services operate by a ## Minimal data storage -We save only the data needed to service our users effectively. This includes metadata and other essential information that allows us to provide a seamless and efficient experience. By minimizing the data we store, we reduce potential risks and enhance your privacy. +We save only the data needed to provide service to you. Less stored data means less risk. ## Trust and transparency -As an open-source project, we welcome anyone to audit our code. Transparency is a core value for us, and we believe in providing our users with the assurance that our code is secure and trustworthy. - -Our processes are designed to be clear and understandable, ensuring that you feel confident in the security and privacy of your information. We are always open to feedback and continuously strive to improve our security measures. +Our code is source-available. You're welcome to audit it yourself. We believe trust is earned through transparency, not promises. ## Security inquiries -We are happy to answer any security questions from your organization. Our team is committed to providing clear and detailed information to ensure you feel confident in using our tools. Feel free to reach out to us with any concerns or questions regarding our security practices. +We're happy to answer any security questions from your organization. Email security@sweetr.dev to inquire about our security practices. ## Report Vulnerabilities -Please report vulnerabilities directly to security@sweetr.dev - do not open an issue in our GitHub nor post it anywhere else that is public accessible. - +Please report vulnerabilities directly to security@sweetr.dev - do not open an issue in our GitHub or post it anywhere else that is publicly accessible. diff --git a/apps/docs/about/open-source.mdx b/apps/docs/about/open-source.mdx index 5501bd39..a64d2cd9 100644 --- a/apps/docs/about/open-source.mdx +++ b/apps/docs/about/open-source.mdx @@ -1,18 +1,18 @@ --- title: Open Source -icon: "gear-code" +icon: "brand-open-source" --- -At Sweetr, we are huge fans of open source and its community. We believe in the power of community-driven development and the positive impact it has on innovation and progress. Our source code is freely available for everyone, and we allow self-hosting to ensure accessibility and flexibility. +From code to community, Sweetr is made in the open. Our source code is public on GitHub, easy to audit, extend, and trust. Self-hosting is free, forever. ## License -Our projects are licensed under the Functional Source License (FSL). While this license is not OSI-approved, it combines the benefits of open source with safeguards against harmful free-riding. The FSL ensures that the software remains open for use, modification, and distribution, but prevents commercial users to use our code to compete against us. After two years, the FSL license automatically converts to the Apache License. +Our projects are licensed under the Functional Source License (FSL), the same license used by Sentry. This makes Sweetr **fair source**, not open source. The FSL allows use, modification, and distribution, but prevents commercial users from using our code to compete against us. After two years, the license automatically converts to Apache 2.0. -We believe this license strikes a good balance between freedom for our users and sustainability to our business. +This gives our users freedom while keeping the project sustainable. ## Contributing -Contributions from the community are invaluable to us, and we welcome any input, whether it’s bug fixes, new features, or improvements to documentation. +We welcome PRs from the community, whether it's bug fixes, new features, or documentation improvements. Refer to our [Contribution Guidelines](https://github.com/sweetr-dev/sweetr.dev/blob/main/CONTRIBUTING.md) for more information. diff --git a/apps/docs/about/principles.mdx b/apps/docs/about/principles.mdx index 353c8127..d594bd48 100644 --- a/apps/docs/about/principles.mdx +++ b/apps/docs/about/principles.mdx @@ -1,31 +1,28 @@ --- title: Principles -icon: "scale-balanced" +icon: "scale" --- -Our mission is to empower developers with tools that enhance productivity, well-being and promote continuous improvement. Our guiding principles reflect our commitment to excellence and innovation. +Improvement is built on trust. Every design decision runs through the filter of "would a developer trust this?". These are the principles we build by. - - Taking a human-centric bottom-up approach, everything we build is designed - with developers in mind. Each addition is carefully considered to avoid - enabling toxic managerial practices, aiming to create a space where - developers can flourish, innovate and remain accountable. + + Everything we build is designed with developers in mind. We don't surface + data that can be weaponized. Every feature is considered to avoid enabling + toxic practices, giving teams context to coach, not score. - Just like the developers we serve, we are committed to continuous - improvement. We own our mistakes and acknowledge that, like everyone, we are - prone to them. We iterate on our products based on user feedback, emerging - trends, and our own convictions on what shapes a winning culture. + Just like the developers we serve, we iterate constantly. We own our + mistakes and acknowledge that, like everyone, we are prone to them. We + improve based on user feedback, emerging trends, and our own convictions on + what shapes a winning culture. - - Our commitment is to deliver solutions that are both powerful and easy to - use. We design our tools with simplicity in mind, ensuring they are - intuitive and user-friendly. + + We surface only what matters. Not to overwhelm you. Our tools are simple, + intuitive, and focused on what's actionable. - + Our community is at the heart of everything we do. We actively seek out and - incorporate community feedback, and we know that's how we build a winning - product. + incorporate community feedback. That's how we build a winning product. diff --git a/apps/docs/api-reference/authentication.mdx b/apps/docs/api-reference/authentication.mdx new file mode 100644 index 00000000..eb871d17 --- /dev/null +++ b/apps/docs/api-reference/authentication.mdx @@ -0,0 +1,30 @@ +--- +title: Authentication +description: Authenticate requests to the Sweetr API using API keys. +icon: "key" +--- + +All API requests must include a valid API key in the `Authorization` header using the Bearer scheme: + +```bash +Authorization: Bearer YOUR_API_KEY +``` + +## Generating API keys + +API keys are scoped to a workspace. To generate one: + +1. Open the Sweetr dashboard. +2. Navigate to **Settings > Workspace**. +3. Scroll down to the **API** section. +4. Click **Regenerate** and copy the generated key. + + + API keys are only displayed once at creation time. Store them securely, for + example as a secret in your CI/CD provider. + + +## Security best practices + +- **Never commit API keys** to source control. +- **Use CI/CD secrets** (e.g., GitHub Actions secrets, GitLab CI variables) to inject keys at runtime. diff --git a/apps/docs/api-reference/deployments/create-deployment.mdx b/apps/docs/api-reference/deployments/create-deployment.mdx new file mode 100644 index 00000000..b5a327b6 --- /dev/null +++ b/apps/docs/api-reference/deployments/create-deployment.mdx @@ -0,0 +1,99 @@ +--- +title: Create Deployment +api: "POST /v1/deployments" +--- + +Track a new deployment for an application. If the application doesn't exist, it will be created automatically. + +The request is processed asynchronously. A `202 Accepted` response means the deployment has been queued for processing. + +## Body + + + Full name of the GitHub repository (e.g., `owner/repo-name`). Max 255 + characters. + + + + Target environment name (e.g., `production`, `staging`). Created automatically + if it doesn't exist. Max 255 characters. + + + + Application name. Created automatically if it doesn't exist. Max 255 + characters. + + + + Version identifier for this deployment (e.g., `v1.2.3`, `build-456`). Max 70 + characters. + + + + The full Git commit SHA being deployed. Max 70 characters. + + + + A short description of the deployment. Max 255 characters. + + + + The person who triggered the deployment. Max 255 characters. + + + + ISO 8601 datetime of when the deployment occurred. Defaults to the current + time if not provided. + + + + Subdirectory path within the repository for monorepo setups. Max 255 + characters. + + +## Response + + + `202`: The deployment has been accepted and queued for processing. + + +## Error codes + +| Status | Description | +| ------ | ------------------------------------------------------------------------ | +| `422` | Validation failed. Check the request body for missing or invalid fields. | +| `401` | Invalid or missing API key. | +| `429` | Rate limit exceeded. See [Rate Limits](/api-reference/rate-limit). | + + +```bash cURL +curl -X POST https://api.sweetr.dev/v1/deployments \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "repositoryFullName": "acme/backend", + "environment": "production", + "app": "backend-api", + "version": "v1.4.2", + "commitHash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2", + "description": "Release v1.4.2", + "author": "jane-doe" + }' +``` + +```bash GitHub Actions +- name: Track deployment + run: | + curl -X POST https://api.sweetr.dev/v1/deployments \ + -H "Authorization: Bearer ${{ secrets.SWEETR_API_KEY }}" \ + -H "Content-Type: application/json" \ + -d '{ + "repositoryFullName": "${{ github.repository }}", + "environment": "production", + "app": "my-app", + "version": "${{ github.sha }}", + "commitHash": "${{ github.sha }}" + }' +``` + + diff --git a/apps/docs/api-reference/introduction.mdx b/apps/docs/api-reference/introduction.mdx new file mode 100644 index 00000000..16035b08 --- /dev/null +++ b/apps/docs/api-reference/introduction.mdx @@ -0,0 +1,42 @@ +--- +title: Introduction +description: Integrate your CI/CD pipeline with Sweetr using the REST API. +icon: "article" +--- + +The Sweetr API lets you programmatically send data to Sweetr from your CI/CD pipelines and external tools. + +## Base URL + +All API requests are made to: + +``` +https://api.sweetr.dev +``` + +## Available endpoints + + + + Track a new deployment for an application. + + + +## Related + + + + + diff --git a/apps/docs/api-reference/rate-limit.mdx b/apps/docs/api-reference/rate-limit.mdx new file mode 100644 index 00000000..7580e9e4 --- /dev/null +++ b/apps/docs/api-reference/rate-limit.mdx @@ -0,0 +1,11 @@ +--- +title: Rate Limits +description: Understand the rate limits applied to the Sweetr API. +icon: "gauge" +--- + +All API endpoints are rate limited to **100 requests per minute**, scoped to your API key. Requests that exceed the limit receive a `429 Too Many Requests` response. + +## Handling rate limits + +If you hit a rate limit, wait before retrying. The recommended approach is exponential backoff: wait 1 second, then 2, then 4, and so on. diff --git a/apps/docs/features/alerts.mdx b/apps/docs/automations/alerts.mdx similarity index 68% rename from apps/docs/features/alerts.mdx rename to apps/docs/automations/alerts.mdx index ea1bec3c..5f752cdf 100644 --- a/apps/docs/features/alerts.mdx +++ b/apps/docs/automations/alerts.mdx @@ -1,6 +1,6 @@ --- title: Alerts -description: Real time alerts for Pull Requests needing attention. +description: Real-time alerts for Pull Requests needing attention. icon: "bell" --- @@ -23,18 +23,22 @@ Alerts are team scoped, and must be enabled individually for each team. Each alert can be toggled on or off individually, and their Slack channels can be customized independently. +## Enabling alerts + +Navigate to **Teams > [Your Team] > Alerts** to configure alerts. Each alert type can be toggled on or off, and you can set a specific Slack channel per alert. + ## Alert Types Alert when an open Pull Request has been waiting for review for too long. You - can setup the minimum idle time to trigger the alert. + can configure the minimum idle time (1 to 168 hours) to trigger the alert.

`Improves cycle time` `Improves time to approval`

- + Alert when an approved Pull Request has been waiting for merge for too long. - You can setup the minimum idle time to trigger the alert. + You can configure the minimum idle time (1 to 168 hours) to trigger the alert.

`Improves cycle time` `Improves time to merge`

@@ -45,8 +49,8 @@ customized independently.

`Improves failure rate`

- - Alert when a Pull Request has lot of comments or back-and-forth. + + Alert when a Pull Request has a lot of comments or back-and-forth. -The metrics digest includes a summary of metrics found in [Team Insights](/features/team). +The metrics digest includes a summary of metrics found in [Team Insights](/metrics-and-insights/team/intro). - Average Pull Request Size - Average Cycle Time @@ -32,7 +32,7 @@ The metrics digest includes a summary of metrics found in [Team Insights](/featu - Time to Approve - Time to Merge -Enabling this digest should help teams understand their flow, and areas for improvement. It helps with accountability and removes the hurdle of having to manually check the metrics in the Sweetr dashboard. +Enabling this digest helps teams understand their flow and areas for improvement. It removes the hurdle of having to manually check the metrics in the Sweetr dashboard. ## Work in Progress Digest @@ -40,8 +40,8 @@ Enabling this digest should help teams understand their flow, and areas for impr -The work in progress digest includes a summary of all the team's open Pull Requests found in [Work in Progress](/features/wip). +The work in progress digest includes a summary of all the team's open Pull Requests found in [Work in Progress](/metrics-and-insights/wip). -Enabling this digest should help teams alignment, by bringing light to any PRs that may need attention. +Enabling this digest helps team alignment, by bringing visibility to any PRs that may need attention. diff --git a/apps/docs/automations/incident-detection.mdx b/apps/docs/automations/incident-detection.mdx new file mode 100644 index 00000000..0ca13548 --- /dev/null +++ b/apps/docs/automations/incident-detection.mdx @@ -0,0 +1,73 @@ +--- +title: Incident Detection +description: Automatically create incident records from rollbacks, hotfixes and reverts. +icon: "circle-dot" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## How it works + +Incident Detection automatically creates incidents when it detects problematic deployments. Incident Detection is enabled and pre-configured by default for every workspace. You can disable or customize the detection rules as needed. + +### Rollback detection + +Detects when a deployment reverts to a previously deployed version. Sweetr compares the commit history between deployments to identify rollbacks automatically. + +| Incident field | Value | +| -------------------- | --------------------------------------------------------------- | +| **Cause deployment** | The first deployment after the version that was rolled back to. | +| **Fix deployment** | The rollback deployment itself. | +| **Detected at** | The time of the rollback deployment. | + +For example, given deployment versions `A → B → C → D -> B²`: + +- **Cause deployment**: `C` (the first deployment after `B`, where the problem was introduced) +- **Fix deployment**: `B²` (the rollback deployment itself) + +### Hotfix detection + +Detects incidents based on patterns in pull request titles, branch names, or labels. Configure regular expressions to match your team's conventions. + +| Pattern | Description | +| ------------------ | -------------------------------------------------------- | +| **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). | +| **Branch regex** | Match branch names (e.g., `^hotfix/.+`). | +| **PR label regex** | Match pull request labels. | + +| Incident field | Value | +| -------------------- | -------------------------------------------------------- | +| **Cause deployment** | The deployment immediately before the hotfix deployment. | +| **Fix deployment** | The deployment containing the hotfix pull request. | +| **Detected at** | The time of the hotfix deployment. | + +### Revert detection + +Detects when a pull request is a revert of a previous change. + +| Incident field | Value | +| -------------------- | ----------------------------------------------------------------------- | +| **Cause deployment** | The deployment that contained the original (now-reverted) pull request. | +| **Fix deployment** | The deployment containing the revert pull request. | +| **Detected at** | The time of the revert deployment. | + +## Benefits + + + More accurate failure rate on your DORA metrics. Remove manual work from + incident reporting. + + +## Related + + + + + + + + diff --git a/apps/docs/features/automations/pr-size-labeler.mdx b/apps/docs/automations/pr-size-labeler.mdx similarity index 98% rename from apps/docs/features/automations/pr-size-labeler.mdx rename to apps/docs/automations/pr-size-labeler.mdx index adf9821d..41b1feec 100644 --- a/apps/docs/features/automations/pr-size-labeler.mdx +++ b/apps/docs/automations/pr-size-labeler.mdx @@ -1,6 +1,7 @@ --- title: PR Size Labeler description: Automatically label a Pull Request with its size. +icon: "ruler" --- import { PrSize } from "/snippets/pr-size.mdx"; diff --git a/apps/docs/automations/pr-title-check.mdx b/apps/docs/automations/pr-title-check.mdx new file mode 100644 index 00000000..f9b5a261 --- /dev/null +++ b/apps/docs/automations/pr-title-check.mdx @@ -0,0 +1,41 @@ +--- +title: PR Title Requirements +description: Enforce PR title standards across your organization. +icon: "heading" +--- + +## Demo + + + + + +## How it works + +Enable this automation in **Automations > PR Title Check** by defining a regular expression to validate Pull Request titles across your organization. When a PR is opened or updated, Sweetr posts a commit status check (`[Sweetr] PR Title Check`) with a **success** or **error** state. + +By default the check is non-blocking. To make it required, add branch protection rules in your repository that require the `[Sweetr] PR Title Check` status to pass before merging. + +## Benefits + + + Standardize Pull Request titles across the organization. + + +## Popular Patterns + + + +```js [KEY-100] Foo +^\[([A-Za-z]+-\d+)\]\s+.+$ +``` + +```js feat: Foo +^(feat|fix|chore|refactor|docs|test):\s+.+$ +``` + +```js [KEY-100] feat: Foo +^\[([A-Za-z]+-\d+)\]\s+(feat|fix|chore|refactor|docs|test):\s+.+$ +``` + + diff --git a/apps/docs/docs.json b/apps/docs/docs.json new file mode 100644 index 00000000..741c5c95 --- /dev/null +++ b/apps/docs/docs.json @@ -0,0 +1,160 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "Sweetr Docs", + "logo": { + "dark": "/logo.svg", + "light": "/logo.svg" + }, + "icons": { + "library": "tabler" + }, + "favicon": "/logo.svg", + "colors": { + "primary": "#69db7c" + }, + "appearance": { + "default": "dark", + "strict": true + }, + "background": { + "color": { + "dark": "#141517" + } + }, + "navbar": { + "links": [ + { + "label": "Login", + "href": "https://app.sweetr.dev/" + } + ], + "primary": { + "type": "button", + "label": "Get Started", + "href": "https://github.com/apps/sweetr-dev/installations/new" + } + }, + "navigation": { + "global": { + "anchors": [ + { + "anchor": "Repository", + "icon": "github", + "href": "https://github.com/sweetr-dev/sweetr.dev" + }, + { + "anchor": "Give Feedback", + "icon": "message-code", + "href": "https://sweetr.featurebase.app/" + } + ] + }, + + "tabs": [ + { + "tab": "Sweetr", + "pages": [ + { + "group": "Welcome", + "pages": [ + "get-started/intro", + { + "group": "Get Started", + "icon": "sparkles", + "pages": ["get-started/cloud", "get-started/self-host"] + } + ] + }, + { + "group": "Metrics & Insights", + "pages": [ + "metrics-and-insights/dora", + { + "group": "Team Insights", + "icon": "chart-arcs", + "pages": [ + "metrics-and-insights/team/intro", + "metrics-and-insights/team/code-review-distribution", + "metrics-and-insights/team/pr-size-distribution", + "metrics-and-insights/team/cycle-time", + "metrics-and-insights/team/time-to-first-review", + "metrics-and-insights/team/time-to-approve", + "metrics-and-insights/team/time-to-merge" + ] + }, + "metrics-and-insights/work-log", + "metrics-and-insights/pull-requests", + "metrics-and-insights/wip", + "metrics-and-insights/code-reviews" + ] + }, + { + "group": "Automations", + "pages": [ + "automations/alerts", + "automations/digests", + "automations/incident-detection", + "automations/pr-size-labeler", + "automations/pr-title-check" + ] + }, + { + "group": "Platform", + "pages": [ + "platform/teams", + "platform/people", + "platform/applications", + "platform/deployments", + "platform/incidents", + "platform/environments", + "platform/integrations" + ] + }, + { + "group": "About Us", + "pages": [ + "about/principles", + "about/open-source", + "about/data-privacy-and-security", + "about/roadmap" + ] + } + ] + }, + { + "tab": "API Reference", + "pages": [ + { + "group": "Overview", + "pages": [ + "api-reference/introduction", + "api-reference/authentication", + "api-reference/rate-limit" + ] + }, + { + "group": "Deployments", + "pages": ["api-reference/deployments/create-deployment"] + } + ] + } + ], + "groups": [] + }, + "api": { + "mdx": { + "server": "https://api.sweetr.dev", + "auth": { + "method": "bearer" + } + } + }, + "footer": { + "socials": { + "x": "https://x.com/sweetr_dev", + "github": "https://github.com/sweetr-dev", + "linkedin": "https://www.linkedin.com/company/sweetr-dev" + } + } +} diff --git a/apps/docs/features/automations/intro.mdx b/apps/docs/features/automations/intro.mdx deleted file mode 100644 index 8b06f7b3..00000000 --- a/apps/docs/features/automations/intro.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Intro -description: Improve Developer Experience with automations. ---- - -import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; - -## Demo - - - - - -## How it works - -Automations are plug-n-play no-code improvements you can add to your organization in a single click. Think of them as an opinionated easier version of GitHub Actions for specific purposes. - -Each automation can improve one or more areas of your engineering organization, we categorize them as: - - - - - - -## Explore - - - - - - - - - diff --git a/apps/docs/features/automations/pr-title-check.mdx b/apps/docs/features/automations/pr-title-check.mdx deleted file mode 100644 index d604aede..00000000 --- a/apps/docs/features/automations/pr-title-check.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: PR Title Requirements -description: Enforce PR title standards across your organization. ---- - -## Demo - - - - - -## How it works - -Define a regular expression to validate Pull Request title across your organization. You can make it blocking by adding branch protection rules in your repository. - -## Benefits - - - Standardize Pull Request titles across the organization. - - -## Popular Patterns - - - -```js [KEY-100] Foo -^\[([A-Za-z]+-\d+)\]\s+.+$ -``` - -```js feat: Foo -^(feat|fix|chore|refactor|docs|test):\s+.+$ -``` - -```js [KEY-100] feat: Foo -^\[([A-Za-z]+-\d+)\]\s+(feat|fix|chore|refactor|docs|test):\s+.+$ -``` - - diff --git a/apps/docs/features/deployments.mdx b/apps/docs/features/deployments.mdx deleted file mode 100644 index ece41796..00000000 --- a/apps/docs/features/deployments.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Deployments -description: The history of your organization's deployments. -icon: "rocket" ---- - -## Under construction - -This feature will be fully released soon. - - diff --git a/apps/docs/features/environments.mdx b/apps/docs/features/environments.mdx deleted file mode 100644 index 156e42ed..00000000 --- a/apps/docs/features/environments.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Environments -description: The environments in which your organization's applications are deployed. -icon: "server" ---- - -## Under construction - -This feature will be fully released soon. - - diff --git a/apps/docs/features/work-log.mdx b/apps/docs/features/work-log.mdx deleted file mode 100644 index 5a8a048e..00000000 --- a/apps/docs/features/work-log.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Work Log -description: Turn daily work into insights for better feedback and progress tracking. -icon: "wave-pulse" ---- - -import { PrBadge } from "/snippets/pr-badge.mdx"; -import { ColorBadge } from "/snippets/color-badge.mdx"; -import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; - -## Demo - - - - - -## How it works - -The Work Log provides a real-time snapshot of your team’s ongoing work, displaying daily activity for each contributor. This feature helps improve visibility into contributions across the team, offering valuable insights for both managers and developers. - -The Work Log displays contributions from each team member, organized by day and grouped into three categories: - -- **Opened PRs** (green hexagons) -- **Merged PRs** (purple hexagons) -- **Code reviews** (speech bubble icons) - -The size of each icon varies based on the PR size, giving a clear indication of the effort involved. Hovering over an icon provides additional details, including the PR title, repository name, number of comments, and size. - -### Insights - -#### For leaders - -- **Improve workload distribution:** Gain context to better balance workloads if someone is regularly overloaded. -- **Prepare for 1:1s & retrospectives:** Gather concrete, data-backed insights to support feedback, career growth discussions, and workload adjustments. -- **Recognize effort, not just volume:** Ensure complex, high-effort contributions are properly acknowledged. -- **Detect when someone might be struggling:** Spot low activity from a developer over several days, which could indicate they’re stuck or facing challenges, allowing you to proactively offer support. - -#### For individual contributors - -- **Make your work visible:** Use the Work Log as a “brag document” to highlight significant contributions during 1:1s or performance reviews. -- **Support promotion cases:** Provide concrete evidence of high-impact work and consistency over time. -- **Document growth:** Track your progress over time and identify areas where you've improved or taken on more complex tasks. - -### Bad practices - -It’s very important to know how this data should not be used. The Work Log is **not intended to measure individual productivity.** It only reflects activity related to PRs and code reviews. It doesn’t account for essential work outside of code contributions, like planning, meetings, research, or documentation. - -Use it as a tool to improve collaboration, provide feedback, and recognize effort — not as a singular performance metric. - - diff --git a/apps/docs/get-started/get-started.mdx b/apps/docs/get-started/get-started.mdx deleted file mode 100644 index ef4ec128..00000000 --- a/apps/docs/get-started/get-started.mdx +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Get Started -description: "Welcome to sweetr.dev" ---- - -This page is under construction diff --git a/apps/docs/get-started/intro.mdx b/apps/docs/get-started/intro.mdx index c2b3d32a..c8435f11 100644 --- a/apps/docs/get-started/intro.mdx +++ b/apps/docs/get-started/intro.mdx @@ -1,39 +1,20 @@ --- title: Intro -description: "Welcome to sweetr.dev, the open platform for developer productivity." -icon: "hand-wave" +description: "Welcome to sweetr.dev, the open platform for Engineering Performance++." +icon: "article" --- **What problems does it solve?** -Sweetr tries to solve several of problems that affect **productivity** and **developer experience**, like big PRs, slow code reviews, unfair performance reviews, and so forth. +PRs get stuck. Bottlenecks stay hidden. Decisions happen without signals. Sweetr gives your team the visibility and automations to uncover friction, improve delivery, and build a better developer experience. -Explore the features section to learn how each tool can help your team. +Explore the feature sections to learn how each tool can help your team. **Who is it for?** -For leaders, managers and developers of teams of all sizes. +Engineering managers, team leads, directors, and developers of teams of all sizes. -#### Get Started +## Get Started - -#### Explore - - - - - - - - - diff --git a/apps/docs/get-started/self-host.mdx b/apps/docs/get-started/self-host.mdx index 84b0f322..f6b584fb 100644 --- a/apps/docs/get-started/self-host.mdx +++ b/apps/docs/get-started/self-host.mdx @@ -40,14 +40,13 @@ merging future enhancements rests entirely with you. #### Repository permissions - - Contents: Read-only - Metadata: Read-only - Pull requests: Read and Write - Commit Statuses: Read and Write - Organization permissions - Members: Read-only #### Account permissions - - Email adresses: Read-only + - Email addresses: Read-only #### Subscribe to events - Installation target - Organization @@ -136,7 +135,7 @@ merging future enhancements rests entirely with you. Update the .env file: ``` VITE_GRAPHQL_API=https://your-api.com - VITE_AUTH_COOKIE_DOMAIN=you-web-app.com + VITE_AUTH_COOKIE_DOMAIN=your-web-app.com VITE_GITHUB_APP=your-github-app-slug ``` diff --git a/apps/docs/images/applications.png b/apps/docs/images/applications.png new file mode 100644 index 00000000..b6d7af45 Binary files /dev/null and b/apps/docs/images/applications.png differ diff --git a/apps/docs/images/deployments.png b/apps/docs/images/deployments.png new file mode 100644 index 00000000..73c9a17e Binary files /dev/null and b/apps/docs/images/deployments.png differ diff --git a/apps/docs/images/dora.png b/apps/docs/images/dora.png new file mode 100644 index 00000000..a72f575a Binary files /dev/null and b/apps/docs/images/dora.png differ diff --git a/apps/docs/images/environments.png b/apps/docs/images/environments.png new file mode 100644 index 00000000..701380d3 Binary files /dev/null and b/apps/docs/images/environments.png differ diff --git a/apps/docs/images/incidents.png b/apps/docs/images/incidents.png new file mode 100644 index 00000000..2ec46cd0 Binary files /dev/null and b/apps/docs/images/incidents.png differ diff --git a/apps/docs/images/people.png b/apps/docs/images/people.png index 4afee6f3..bb810180 100644 Binary files a/apps/docs/images/people.png and b/apps/docs/images/people.png differ diff --git a/apps/docs/images/team-list.png b/apps/docs/images/team-list.png index 86947c50..1b544f0d 100644 Binary files a/apps/docs/images/team-list.png and b/apps/docs/images/team-list.png differ diff --git a/apps/docs/images/team-members.png b/apps/docs/images/team-members.png index bb512aae..798b9aa5 100644 Binary files a/apps/docs/images/team-members.png and b/apps/docs/images/team-members.png differ diff --git a/apps/docs/features/code-reviews.mdx b/apps/docs/metrics-and-insights/code-reviews.mdx similarity index 94% rename from apps/docs/features/code-reviews.mdx rename to apps/docs/metrics-and-insights/code-reviews.mdx index 2b309428..446b9c35 100644 --- a/apps/docs/features/code-reviews.mdx +++ b/apps/docs/metrics-and-insights/code-reviews.mdx @@ -50,7 +50,7 @@ While this may seem overly complex, it's important so that the time elapsed calc ## Use cases -- Easily see developer's code reviews in one place. Quickly open the pull requests and go through the comments. +- Easily see a developer's code reviews in one place. Quickly open the pull requests and go through the comments. - Spot LGTM stamps in a glance (number of comments vs Pull Request size). - Coach a developer into becoming a better reviewer. - Assess their communication style. diff --git a/apps/docs/metrics-and-insights/dora.mdx b/apps/docs/metrics-and-insights/dora.mdx new file mode 100644 index 00000000..b7880243 --- /dev/null +++ b/apps/docs/metrics-and-insights/dora.mdx @@ -0,0 +1,93 @@ +--- +title: DORA Metrics +description: Measure software delivery performance with the four DORA metrics. +icon: "chart-line" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +DORA metrics are four key indicators of software delivery performance, developed by the [DORA research program](https://dora.dev). Sweetr calculates these metrics from your deployment and incident data. + +All metrics support filtering by **team**, **application**, **environment**, and **date range**, and include a comparison against the previous period. + +## Metrics + +### Deployment Frequency + +How often your team deploys to production. Higher frequency indicates smaller, more manageable releases. + +- **Calculation:** Count of deployments in the selected period. +- **Chart:** Deployments over time with average per day. + +### Lead Time for Changes + +The time from first commit to production deployment. Lower lead time means faster delivery. + +- **Calculation:** Time from first commit to deployment, averaged across all deployments. +- **Breakdown:** + - **Coding time**: First commit to pull request creation. + - **Time to first review**: PR creation to first review. + - **Time to approve**: First review to approval. + - **Time to merge**: Approval to merge. + - **Time to deploy**: Merge to deployment. + +### Change Failure Rate + +The percentage of deployments that cause an incident. Lower rate indicates more stable releases. + +- **Calculation:** `(Incidents caused by deployments / Total deployments) × 100` +- **Requires:** [Incidents](/platform/incidents) linked to deployments. + +### Mean Time to Recovery (MTTR) + +The average time to recover from an incident. Lower MTTR indicates faster incident response. + +- **Calculation:** Average of `resolved at - detected at` across all resolved incidents. +- **Requires:** [Incidents](/platform/incidents) with detection and resolution timestamps. + +## Benchmarks + +The DORA research program publishes annual benchmarks that categorize teams into Elite, High, Medium, and Low performers. Use these to assess where your team stands and set realistic goals. See the official DORA guides for the latest thresholds. + +## Prerequisites + +To get the most out of DORA metrics: + + + + Create [applications](/platform/applications) and configure their deployment + settings. + + + Send deployments via the + [API](/api-reference/deployments/create-deployment), PR merges, or GitHub + deployment events. + + + Create [incidents](/platform/incidents) manually or enable [Incident + Detection](/automations/incident-detection) to automate it. + + + +## Related + + + + + + + + + diff --git a/apps/docs/features/pull-requests.mdx b/apps/docs/metrics-and-insights/pull-requests.mdx similarity index 94% rename from apps/docs/features/pull-requests.mdx rename to apps/docs/metrics-and-insights/pull-requests.mdx index 565d6263..974889d0 100644 --- a/apps/docs/features/pull-requests.mdx +++ b/apps/docs/metrics-and-insights/pull-requests.mdx @@ -1,7 +1,7 @@ --- title: Pull Requests description: Filterable list of a team's pull requests. -icon: "code-pull-request" +icon: "git-pull-request" --- import { PrBadge } from "/snippets/pr-badge.mdx"; @@ -53,6 +53,11 @@ The color of the icons also changes depending on the time elapsed for the corres Weekends are not included when calculating time elapsed. + + Color thresholds are not configurable today. Customizable thresholds are + planned. + + ## Use cases - Easily see all team PRs in one place. diff --git a/apps/docs/features/team/code-review-distribution.mdx b/apps/docs/metrics-and-insights/team/code-review-distribution.mdx similarity index 91% rename from apps/docs/features/team/code-review-distribution.mdx rename to apps/docs/metrics-and-insights/team/code-review-distribution.mdx index 09d27994..86a66eff 100644 --- a/apps/docs/features/team/code-review-distribution.mdx +++ b/apps/docs/metrics-and-insights/team/code-review-distribution.mdx @@ -24,7 +24,7 @@ You can hover over each reviewer to see detailed info on: This chart can help you measure and answer questions like: -- Is anyone at risk of burning out due to review overload? +- Is review load unevenly distributed? - Could anyone help with more code reviews? - Is any reviewer interacting only with selected members of the team? - Is considerable time being spent on reviewing other team's code? @@ -45,7 +45,7 @@ There are some strategies you can employ to try to achieve a more balanced revie - Visit this data during retrospectives and discuss options with the team. - Discuss code review accountability during 1:1s and performance evaluations. - Encourage new developers to review code early on their onboarding - even if only to ask questions. -- Make sure your team feels safe giving feedback. Go through your team's Pull Requests to assert your team members have a healthy communication style. +- Make sure your team feels safe giving feedback. Go through your team's Pull Requests to ensure communication stays healthy. ## Bad practices diff --git a/apps/docs/features/team/cycle-time.mdx b/apps/docs/metrics-and-insights/team/cycle-time.mdx similarity index 70% rename from apps/docs/features/team/cycle-time.mdx rename to apps/docs/metrics-and-insights/team/cycle-time.mdx index b46da5fb..b2065adf 100644 --- a/apps/docs/features/team/cycle-time.mdx +++ b/apps/docs/metrics-and-insights/team/cycle-time.mdx @@ -1,6 +1,6 @@ --- title: Cycle time -description: Time elapsed between opening and merging a Pull Request. +description: Time elapsed between starting and merging a Pull Request. --- import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; @@ -18,7 +18,7 @@ This chart can help you measure and answer questions like: - Is the team's flow consistent? - Are the recent process changes effective? - Are there any recurring patterns or periodic fluctuations? -- How is our team's overall efficiency and health? +- How is our team's overall flow and health? ## What good looks like @@ -35,4 +35,11 @@ There are some strategies that can help your team's cycle time. - Prioritize resolving blockers. - Prioritize finishing open work vs starting new things. +## How this metric is calculated + +- **Start:** The earlier of the first commit date or the PR creation date. +- **End:** The PR merge date. +- **Aggregation:** Average (mean) across all merged PRs in the selected period. +- **Business time:** Weekends are excluded. Full weekdays are counted. + diff --git a/apps/docs/features/team/intro.mdx b/apps/docs/metrics-and-insights/team/intro.mdx similarity index 51% rename from apps/docs/features/team/intro.mdx rename to apps/docs/metrics-and-insights/team/intro.mdx index 852b5434..a51774b6 100644 --- a/apps/docs/features/team/intro.mdx +++ b/apps/docs/metrics-and-insights/team/intro.mdx @@ -15,26 +15,29 @@ import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; All metrics and insights are displayed at a team level. All the data analyzed is from your organization's GitHub account. -Each chart's high-level goal is to give you means to find ways to improve your team's performance, health and satisfaction. +Each chart helps you spot friction, find patterns, and improve your team's delivery flow. ## Explore - + - - + + diff --git a/apps/docs/features/team/pr-size-distribution.mdx b/apps/docs/metrics-and-insights/team/pr-size-distribution.mdx similarity index 96% rename from apps/docs/features/team/pr-size-distribution.mdx rename to apps/docs/metrics-and-insights/team/pr-size-distribution.mdx index dc3780ba..e438a8ef 100644 --- a/apps/docs/features/team/pr-size-distribution.mdx +++ b/apps/docs/metrics-and-insights/team/pr-size-distribution.mdx @@ -33,7 +33,7 @@ This chart can help you measure and answer questions like: ## What good looks like -Ideally, most of Pull Requests should be small or tiny. +Ideally, most Pull Requests should be small or tiny. - They are easier to review. - They have fewer bugs. diff --git a/apps/docs/features/team/time-to-approve.mdx b/apps/docs/metrics-and-insights/team/time-to-approve.mdx similarity index 63% rename from apps/docs/features/team/time-to-approve.mdx rename to apps/docs/metrics-and-insights/team/time-to-approve.mdx index 0cf0c981..8a490b67 100644 --- a/apps/docs/features/team/time-to-approve.mdx +++ b/apps/docs/metrics-and-insights/team/time-to-approve.mdx @@ -22,7 +22,7 @@ This chart can help you measure and answer questions like: ## What good looks like -Ideally, most Pull Requests should be approved within hours of its creation, but it can vary significantly depending on the context, such as the complexity of the project and the size of the Pull Request. +Ideally, most Pull Requests should be approved within hours of their creation, but it can vary significantly depending on the context, such as the complexity of the project and the size of the Pull Request. ## How to improve @@ -37,7 +37,7 @@ There are some strategies that can help your team's time to approve. - Encourage the team to communicate and ask questions early. - Encourage the team to review their own work before requesting reviews. -A even better way to understand how to improve is to go through the pull requests and assess the common causes for delay: +An even better way to understand how to improve is to go through the pull requests and assess the common causes for delay: - blocked due to nitpicks. - missing requirements. @@ -54,4 +54,11 @@ data should **not** be used. Strive for a good balance of code quality vs speed instead. +## How this metric is calculated + +- **Start ("ready"):** The earliest available timestamp, in priority order: (1) first reviewer requested date, (2) date the PR was marked ready for review, or (3) PR creation date. +- **End:** The first approval date. +- **Aggregation:** Average (mean) across all approved PRs in the selected period. +- **Business time:** Weekends are excluded. Full weekdays are counted. + diff --git a/apps/docs/features/team/time-to-first-review.mdx b/apps/docs/metrics-and-insights/team/time-to-first-review.mdx similarity index 60% rename from apps/docs/features/team/time-to-first-review.mdx rename to apps/docs/metrics-and-insights/team/time-to-first-review.mdx index 8e4e6d20..73e4b537 100644 --- a/apps/docs/features/team/time-to-first-review.mdx +++ b/apps/docs/metrics-and-insights/team/time-to-first-review.mdx @@ -22,7 +22,7 @@ This chart can help you measure and answer questions like: ## What good looks like -Ideally, most small Pull Requests should be reviewed within hours of its creation. Team members should prioritize moving together as a team over their own individual work. +Ideally, most small Pull Requests should be reviewed within hours of their creation. Team members should prioritize moving together as a team over their own individual work. ## How to improve @@ -34,4 +34,11 @@ There are some strategies that can help your team's time to first review. - Make it clear to the team that reviewing code is a priority. - Simplify your reviewer assigning process. +## How this metric is calculated + +- **Start ("ready"):** The earliest available timestamp, in priority order: (1) first reviewer requested date, (2) date the PR was marked ready for review (draft PRs are not considered ready), or (3) PR creation date. Only timestamps before the review are considered. +- **End:** The first non-author, non-bot review submission date. +- **Aggregation:** Average (mean) across all reviewed PRs in the selected period. +- **Business time:** Weekends are excluded. Full weekdays are counted. + diff --git a/apps/docs/features/team/time-to-merge.mdx b/apps/docs/metrics-and-insights/team/time-to-merge.mdx similarity index 60% rename from apps/docs/features/team/time-to-merge.mdx rename to apps/docs/metrics-and-insights/team/time-to-merge.mdx index baec7af1..fd982310 100644 --- a/apps/docs/features/team/time-to-merge.mdx +++ b/apps/docs/metrics-and-insights/team/time-to-merge.mdx @@ -21,7 +21,7 @@ This chart can help you measure and answer questions like: ## What good looks like -Ideally, most small Pull Requests should be merged within a hour of it being approved. Teams should prioritize finishing work over starting new things. +Ideally, most small Pull Requests should be merged within an hour of being approved. Teams should prioritize finishing work over starting new things. ## How to improve @@ -31,4 +31,11 @@ There are some strategies that can help your team's time to merge. - Keep CI/CD process fast and painless. - Prioritize finishing open work vs starting new things. +## How this metric is calculated + +- **Start:** The first approval date. If the PR was never approved, falls back to the "ready" date or PR creation date. +- **End:** The PR merge date. +- **Aggregation:** Average (mean) across all merged PRs in the selected period. +- **Business time:** Weekends are excluded. Full weekdays are counted. + diff --git a/apps/docs/features/wip.mdx b/apps/docs/metrics-and-insights/wip.mdx similarity index 54% rename from apps/docs/features/wip.mdx rename to apps/docs/metrics-and-insights/wip.mdx index 32c624da..00251392 100644 --- a/apps/docs/features/wip.mdx +++ b/apps/docs/metrics-and-insights/wip.mdx @@ -16,22 +16,27 @@ import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; ## How it works -The Work in Progress page provides a real-time view of all the team's open Pull Requests, grouping it by their status. +The Work in Progress page provides a real-time view of all the team's open Pull Requests, grouped by their status into four columns: -This is a focused view of the [Pull Requests](/features/pull-requests) page, and can be used to get a quick overview of the team's work in progress. +- **Drafted** — PRs still in draft. +- **Pending Review** — Open PRs waiting for a review. +- **Changes Requested** — PRs where a reviewer requested changes. +- **Pending Merge** — Approved PRs waiting to be merged. + +This is a focused view of the [Pull Requests](/metrics-and-insights/pull-requests) page, and can be used to get a quick overview of the team's work in progress. ## Use cases -- Facilitate daily meetings. +- Run better daily meetings. - Identify blocked PRs. - Identify PRs with a lot of comments that might need attention. ## Use it with Send daily snapshots of your team's Work In Progress to a channel in Slack. diff --git a/apps/docs/metrics-and-insights/work-log.mdx b/apps/docs/metrics-and-insights/work-log.mdx new file mode 100644 index 00000000..27f8aa6f --- /dev/null +++ b/apps/docs/metrics-and-insights/work-log.mdx @@ -0,0 +1,50 @@ +--- +title: Work Log +description: A weekly view of your team's pull requests and code reviews. +icon: "activity" +--- + +import { PrBadge } from "/snippets/pr-badge.mdx"; +import { ColorBadge } from "/snippets/color-badge.mdx"; +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +A weekly view of your team's pull requests and code reviews. Each icon represents a PR or review, and grows in size with the change. Spot where work flows, where it piles up, and where it's stuck. + +Contributions from each team member are organized by day and grouped into three categories: + +- **Opened PRs** (green hexagons) +- **Merged PRs** (purple hexagons) +- **Code reviews** (speech bubble icons) + +The size of each icon varies based on the PR size, giving a clear indication of the effort involved. Hovering over an icon provides additional details, including the PR title, repository name, number of comments, and size. + +### Use it to + +#### For leaders + +- **Spot workload imbalance:** Quickly see if work is spread evenly or if someone is consistently overloaded. +- **Prepare for 1:1s:** Walk into conversations with concrete context on what happened that week, not just gut feelings. +- **Recognize effort, not just volume:** Fewer, larger icons mean someone tackled a big piece of work. Not every week needs a wall of dots. +- **Check in early:** A quiet week can mean someone is blocked. Use it as a signal to offer support, not to judge. + +#### For individual contributors + +- **Build your brag document:** Use the Work Log to highlight contributions during 1:1s or performance reviews. +- **Support promotion cases:** Provide concrete evidence of high-impact work and consistency over time. +- **Document growth:** See your progress over time and identify areas where you've improved or taken on more complex tasks. + +### Bad practices + +It's very important to know how this data should not be used. The Work Log is **not intended to measure individual productivity.** It only reflects activity related to PRs and code reviews. It doesn't account for essential work outside of code contributions, like planning, meetings, research, or documentation. + +Use it as a tool to improve collaboration, provide feedback, and recognize effort, not as a singular performance metric. + + diff --git a/apps/docs/mint.json b/apps/docs/mint.json deleted file mode 100644 index d5f9b0be..00000000 --- a/apps/docs/mint.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "$schema": "https://mintlify.com/schema.json", - "name": "Sweetr Docs", - "logo": { - "dark": "/logo.svg", - "light": "/logo.svg" - }, - "favicon": "/logo.svg", - "colors": { - "primary": "#69db7c", - "background": { - "dark": "#141517" - }, - "anchors": { - "from": "#69db7c", - "to": "#53851d" - } - }, - "modeToggle": { - "default": "dark", - "isHidden": true - }, - "topbarLinks": [ - { - "name": "Login", - "url": "https://app.sweetr.dev/" - } - ], - "topbarCtaButton": { - "name": "Get Started", - "url": "https://github.com/apps/sweetr-dev/installations/new" - }, - "anchors": [ - { - "name": "Repository", - "icon": "github", - "url": "https://github.com/sweetr-dev/sweetr.dev" - }, - { - "name": "Give Feedback", - "icon": "message-code", - "url": "https://sweetr.featurebase.app/" - } - ], - "feedback": { - "suggestEdit": true, - "raiseIssue": true - }, - "navigation": [ - { - "group": "Welcome", - "pages": [ - "get-started/intro", - { - "group": "Get Started", - "icon": "sparkles", - "pages": ["get-started/cloud", "get-started/self-host"] - } - ] - }, - { - "group": "Features", - "pages": [ - "features/alerts", - "features/digests", - "features/work-log", - "features/pull-requests", - "features/wip", - "features/teams", - "features/people", - "features/code-reviews", - { - "group": "Team Insights", - "icon": "chart-simple", - "pages": [ - "features/team/intro", - "features/team/code-review-distribution", - "features/team/pr-size-distribution", - "features/team/cycle-time", - "features/team/time-to-first-review", - "features/team/time-to-approve", - "features/team/time-to-merge" - ] - }, - { - "group": "Automations", - "icon": "robot", - "pages": [ - "features/automations/intro", - "features/automations/pr-size-labeler", - "features/automations/pr-title-check" - ] - }, - "features/integrations" - ] - }, - { - "group": "About Us", - "pages": [ - "about/principles", - "about/open-source", - "about/data-privacy-and-security", - "about/roadmap" - ] - } - ], - "footerSocials": { - "x": "https://x.com/sweetr_dev", - "github": "https://github.com/sweetr-dev", - "linkedin": "https://www.linkedin.com/company/sweetr-dev" - } -} diff --git a/apps/docs/platform/applications.mdx b/apps/docs/platform/applications.mdx new file mode 100644 index 00000000..8c772f67 --- /dev/null +++ b/apps/docs/platform/applications.mdx @@ -0,0 +1,53 @@ +--- +title: Applications +description: Manage deployable units within your repositories. +icon: "cube" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +Applications represent deployable units within your repositories. They connect a repository to its deployments and environments, making it possible to track deployment history and DORA metrics per application. + +Applications support **monorepo setups**. A single repository can have multiple applications, each mapped to a subdirectory. + +## Creating applications + +Applications can be created in two ways: + +- **Manually**: Create an application from the UI and configure its deployment settings. +- **Automatically**: When a deployment is sent via the API, Sweetr auto-creates the application if it doesn't exist. + +## Deployment settings + +Each application has configurable deployment settings that control how deployments are tracked: + +| Setting | Description | +| ----------------- | ------------------------------------------------------------------- | +| **Trigger** | How deployments are created: API Webhook or PR Merge. | +| **Target branch** | For merge-based triggers, the branch that represents production. | +| **Subdirectory** | For monorepos, the path within the repository for this application. | + +## Archiving + +Applications that are no longer in use can be archived. Archived applications are hidden from filters and excluded from metrics. You can unarchive them at any time. + +## Related + + + + + + + diff --git a/apps/docs/platform/deployments.mdx b/apps/docs/platform/deployments.mdx new file mode 100644 index 00000000..fc664a69 --- /dev/null +++ b/apps/docs/platform/deployments.mdx @@ -0,0 +1,105 @@ +--- +title: Deployments +description: Track every deployment across your applications and environments. +icon: "rocket" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +Deployments track when a version of an application is deployed to an environment. Each deployment records the version, commit hash, environment, and linked pull requests. + +Filter deployments by application, environment, and date range to find exactly what you need. + +## Change type + +Sweetr automatically determines the **change type** for each deployment by comparing commits against the previous deployment: + +- **Forward**: A standard deployment with new changes. +- **Rollback**: The deployment reverts to a previous version. +- **No Change**: A redeployment of the same version. + +## Deployment triggers + +Deployments can be tracked through two different triggers: + + + Send deployments via the [POST + /v1/deployments](/api-reference/deployments/create-deployment) REST endpoint. + Best for custom CI/CD pipelines. + + + + Automatically create a deployment when a pull request is merged to a target + branch. Best for trunk-based development. + + +### Linking Pull Requests + +Each deployment is automatically linked to the pull requests it contains. The linking strategy depends on the deployment trigger. + +#### API Webhook + +When a deployment is received via the API, Sweetr compares the deployment's commit hash against the previous deployment's commit hash using GitHub's [compare API](https://docs.github.com/en/rest/commits/commits#compare-two-commits). All merged pull requests whose merge commit falls within that range are linked to the deployment. + +For monorepo applications with a configured subdirectory, only pull requests that modified files within that subdirectory are linked. + + + The first deployment for an application/environment pair is marked as a + **baseline** and has no linked pull requests, since there is no previous + deployment to compare against. + + +#### Pull Request Merge + +When a deployment is triggered by a pull request merge, the linked pull request is always the one that was merged. No commit comparison is needed. + +## Data quality + +The deployment trigger you choose affects the accuracy of your [DORA metrics](/metrics-and-insights/dora), specifically **Change Lead Time** and **Deployment Frequency**. + + + + Records the **actual deployment time** as reported by your CI/CD pipeline. + This provides the most accurate time-to-deploy calculations since it + captures the real moment your code reaches production. + + + + Uses the **merge time** as the deployment time. This is an approximation, + since the actual deployment typically happens after the merge — once your + CI/CD pipeline finishes building, testing, and deploying. + + + +For the most accurate metrics, prefer using the API Webhook trigger so that Sweetr captures when your code was actually deployed, not just when it was merged. + +## Archiving + +Deployments that are no longer relevant can be archived. Archived deployments are excluded from metrics. You can unarchive them at any time. + +## Related + + + + + + + + + diff --git a/apps/docs/platform/environments.mdx b/apps/docs/platform/environments.mdx new file mode 100644 index 00000000..af1735a2 --- /dev/null +++ b/apps/docs/platform/environments.mdx @@ -0,0 +1,53 @@ +--- +title: Environments +description: Organize deployments by environment to track metrics across your deployment targets. +icon: "server" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +Environments represent deployment targets like `production`, `staging`, or `qa`. Deployments are always associated with an environment, and metrics can be filtered by environment. + +A default **production** environment is created for every workspace. Additional environments are created automatically when a deployment is sent via the [API](/api-reference/deployments/create-deployment) with an environment name that doesn't exist yet. + + + Environments named `production` or `prod` (case-insensitive) are automatically + marked as production environments. + + +## Production flag + +Each environment has an `isProduction` flag. This matters because DORA metrics default to production environments only. Non-production deployments are excluded unless you explicitly filter for them. + +## When to use multiple environments + +For most teams, the default `production` environment is all you need. Multiple environments are useful when: + +- **You want to measure metrics for non-production environments**, for example, tracking deployment frequency to staging. +- **You have multiple production environments**, for example, regional deployments (`production-us`, `production-eu`). Since only exact names `production` or `prod` are auto-detected, you must explicitly set the production flag for regional environment names. + +## Archiving + +Environments that are no longer in use can be archived. Archived environments are hidden from filters and excluded from metrics. You can unarchive them at any time. + +## Related + + + + + + + + diff --git a/apps/docs/platform/incidents.mdx b/apps/docs/platform/incidents.mdx new file mode 100644 index 00000000..e0ee0aa8 --- /dev/null +++ b/apps/docs/platform/incidents.mdx @@ -0,0 +1,65 @@ +--- +title: Incidents +description: Track production incidents caused by deployments. +icon: "flame" +--- + +import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; + +## Demo + + + + + +## How it works + +Incidents represent production issues caused by a deployment. They track the full lifecycle from detection to resolution, linking back to the deployment that caused the issue and the deployment that fixed it. + +## Key fields + +| Field | Description | +| -------------------- | ---------------------------------------------------- | +| **Cause deployment** | The deployment that introduced the issue (required). | +| **Fix deployment** | The deployment that resolved the issue. | +| **Detected at** | When the incident was detected. | +| **Resolved at** | When the incident was resolved. | +| **Team** | The team responsible for the incident. | +| **Leader** | The person leading incident response. | +| **Postmortem URL** | Link to the postmortem document. | + +## Creating incidents + +Incidents can be created in two ways: + +- **Manually**: Create an incident from the UI, linking it to the deployment that caused it. +- **Automatically**: Use the [Incident Detection](/automations/incident-detection) automation to detect incidents from rollbacks, hotfixes, and reverts. + +## Impact on metrics + +Incidents directly feed into two DORA metrics: + +- **Change Failure Rate**: The percentage of deployments that caused an incident. +- **Mean Time to Recovery**: The average time between incident detection and resolution. + +## Archiving + +Incidents that are no longer relevant can be archived. Archived incidents are excluded from metrics. You can unarchive them at any time. + +## Related + + + + + + + + diff --git a/apps/docs/features/integrations.mdx b/apps/docs/platform/integrations.mdx similarity index 57% rename from apps/docs/features/integrations.mdx rename to apps/docs/platform/integrations.mdx index 21fe5e81..3245a72d 100644 --- a/apps/docs/features/integrations.mdx +++ b/apps/docs/platform/integrations.mdx @@ -1,7 +1,7 @@ --- title: Integrations description: The tools we integrate with. -icon: "grid-2-plus" +icon: "apps" --- import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; @@ -9,19 +9,26 @@ import { CtaGetStarted } from "/snippets/cta-get-started.mdx"; ## Available today - - + + Syncs metadata from GitHub. Enabled by default. + + + Allows automations to send messages to Slack channels. + ## Coming soon + + + diff --git a/apps/docs/features/people.mdx b/apps/docs/platform/people.mdx similarity index 68% rename from apps/docs/features/people.mdx rename to apps/docs/platform/people.mdx index 119093e9..bfddb89c 100644 --- a/apps/docs/features/people.mdx +++ b/apps/docs/platform/people.mdx @@ -24,10 +24,18 @@ The list of members is 100% synced with your GitHub organization. You can't directly add or remove people in our dashboard. When a user is invited or removed from your organization in GitHub, that change is automatically synced in Sweetr. + + When someone is removed from your GitHub organization, their historical data (pull requests, code reviews) is currently removed from Sweetr as well. Data preservation for past members is planned. + + ## Explore - + diff --git a/apps/docs/features/teams.mdx b/apps/docs/platform/teams.mdx similarity index 54% rename from apps/docs/features/teams.mdx rename to apps/docs/platform/teams.mdx index ad0492ed..347acc6f 100644 --- a/apps/docs/features/teams.mdx +++ b/apps/docs/platform/teams.mdx @@ -1,7 +1,7 @@ --- title: Teams description: A directory of your organization's teams. -icon: "users-rectangle" +icon: "circles" --- import { PrBadge } from "/snippets/pr-badge.mdx"; @@ -28,7 +28,7 @@ Click the "New" button in the team list page to create a new team. -Each member can have a specific role within a team. +A person can belong to multiple teams. Each member can have a specific role within a team. Roles are informational labels that help viewers understand each person's function on the team. They do not affect permissions or metrics. - Engineer - Product @@ -37,15 +37,23 @@ Each member can have a specific role within a team. - Leader - Manager +## Archiving + +Teams that are no longer active can be archived. Archived teams are hidden from filters and excluded from metrics. You can unarchive them at any time. + ## Explore + - diff --git a/apps/docs/snippets/cta-get-started.mdx b/apps/docs/snippets/cta-get-started.mdx index 468425c8..ad474571 100644 --- a/apps/docs/snippets/cta-get-started.mdx +++ b/apps/docs/snippets/cta-get-started.mdx @@ -1,5 +1,5 @@ export const CtaGetStarted = ({ - label = "Ready to unlock continuous improvement in your team?", + label = "Ready to make delivery flow again?", }) => (
(
); - -;