<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Johnny Santamaria</title>
    <description>The latest articles on Forem by Johnny Santamaria (@jds64).</description>
    <link>https://forem.com/jds64</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2196487%2Fcc8072cd-314c-42fe-a09e-3a1422132a2e.png</url>
      <title>Forem: Johnny Santamaria</title>
      <link>https://forem.com/jds64</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jds64"/>
    <language>en</language>
    <item>
      <title>Keeping Your Secrets in Sync: Environment Lifecycle Management That Actually Works</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 14 Feb 2026 01:25:14 +0000</pubDate>
      <link>https://forem.com/jds64/keeping-your-secrets-in-sync-environment-lifecycle-management-that-actually-works-24ga</link>
      <guid>https://forem.com/jds64/keeping-your-secrets-in-sync-environment-lifecycle-management-that-actually-works-24ga</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Keyshade is an open-source real-time secret and configuration management platform that helps developers securely store, sync, and rotate sensitive data like API keys, passwords, and environment variables across multiple environments. It uses end-to-end encryption and live updates to eliminate insecure .env file sharing, manual dashboard updates, and secret sprawl. Designed for teams and solo developers alike, Keyshade improves collaboration, auditability, and security by providing version history, access controls, and seamless integrations with modern deployment platforms.&lt;/p&gt;

&lt;p&gt;Try it out on &lt;a href="https://keyshade.io/" rel="noopener noreferrer"&gt;https://keyshade.io/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Silent Failures in Cloud Integrations (&lt;a href="https://github.com/keyshade-xyz/keyshade/issues/1254" rel="noopener noreferrer"&gt;#1254&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;The problem was that the integrations with Vercel or AWS Lambda would only respond to updates in secrets and variables. It would completely ignore situations where the user had deleted the environment or renamed the environment. This meant that when a user deleted an environment in Keyshade, the secrets and variables would still be available in Vercel or AWS Lambda but would be orphaned. This presented a problem from a security point of view. Also, when the environment was renamed, the integrations would be out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Bug Mattered to Production Teams
&lt;/h2&gt;

&lt;p&gt;This problem was significant because of several factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security Risk: When a user deleted an environment using Keyshade (like an environment in staging mode), the secrets became active in Vercel and AWS Lambda. This meant the secrets were exposed on another platform. That is, credentials became potential attack vectors.&lt;/li&gt;
&lt;li&gt;Data Integrity: The disconnect between Keyshade’s environment state and the external platforms led to a situation where users couldn’t be assured of data integrity. It defeats the purpose of having a reliable tool like Keyshade.&lt;/li&gt;
&lt;li&gt;User Experience: It will be the responsibility of the consumers of Keyshade to manually log in to the Vercel or AWS Lambda interface to clean up after environment changes, thereby defeating the purpose of the integration in the first place. Such an interface might discourage the use of Keyshade.&lt;/li&gt;
&lt;li&gt;Production Readiness: The integrations must be prepared to handle the full lifecycle of environments, not only the secrets within static environments, for Keyshade to be considered viable in production, especially by teams with high rates of environment changes (e.g., CI/CD workflows creating ephemeral environments). It was marked as "priority: high" and "difficulty: 4." This was my hardest PR that took around two months.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Under the Hood: Key Code Changes
&lt;/h2&gt;

&lt;p&gt;keyshade/apps/api/src/integrations/plugins/vercel.integration.ts&lt;br&gt;
Purposes: Integrates the Vercel platform - responsible for syncing Keyshade secrets/variables to Vercel projects as environment variables.&lt;br&gt;
Key sections to edit:&lt;br&gt;
getPermittedEvents(). Added ENVIRONMENT_UPDATED and ENVIRONMENT_DELETED to the set of events the integration subscribes to.&lt;br&gt;
added case handlers to switch of emitEvent() for routing environment lifecycle events.&lt;br&gt;
New functions added: handleEnvironmentDeleted(): This cleans up project-level environment variables scoped to the deleted environment and breaks the integration relationship handleEnvironmentUpdated(): Renames custom Vercel environments if available (pro plan users) &amp;amp; update integration metadata&lt;/p&gt;

&lt;p&gt;apps/api/src/integration/plugins/aws-lambda.integration.ts&lt;br&gt;
Purpose: Implements the AWS Lambda integration, syncing Keyshade secrets to Lambda function environment variables&lt;br&gt;
Key sections modified:&lt;br&gt;
getPermittedEvents(): Added the two environment events&lt;br&gt;
emitEvent() switch statement: Added routing for environment events&lt;br&gt;
New functions added:&lt;br&gt;
handleEnvironmentDeleted(): Removes environment-scoped keys from Lambda function configuration and disconnects the environment relationship&lt;br&gt;
handleEnvironmentUpdated(): No-op handler (Lambda has no environment rename concept) that logs an audit event&lt;/p&gt;

&lt;p&gt;apps/api/src/common/util.ts&lt;br&gt;
Purpose: Added retryWithBackoff() helper function to handle transient failures when calling external APIs (Vercel/AWS)&lt;br&gt;
Why important: Cloud APIs can fail temporarily; this ensures cleanup operations are resilient and retry with exponential backoff&lt;/p&gt;

&lt;p&gt;apps/api/src/integration/reconciler.ts&lt;br&gt;
Purpose: Lightweight reconciliation system that processes failed cleanup operations stored in integration.metadata.pendingCleanup&lt;br&gt;
Why important: When retries fail after multiple attempts, the reconciler can later replay these operations, ensuring eventual consistency even if external APIs are temporarily unavailable&lt;/p&gt;

&lt;p&gt;apps/api/src/event/event.types.ts&lt;br&gt;
Purpose: Defines TypeScript types for event metadata&lt;br&gt;
Relevant types:&lt;br&gt;
EnvironmentUpdatedEventMetadata: Contains name and description fields for environment updates&lt;br&gt;
EnvironmentDeletedEventMetadata: Contains the environment name for deletion events&lt;/p&gt;

&lt;p&gt;Test files:&lt;br&gt;
apps/api/src/integration/plugins/vercel.integration.spec.ts: tests covering environment lifecycle handlers&lt;br&gt;
apps/api/src/integration/plugins/aws-lambda.integration.spec.ts: tests covering Lambda-specific handlers&lt;br&gt;
apps/api/src/integration/reconciler.spec.ts: testing the reconciler's pending cleanup processing&lt;/p&gt;

&lt;p&gt;Supporting materials/artifacts&lt;br&gt;
Before the fix:&lt;br&gt;
When a user deleted an environment in Keyshade, the integration would:&lt;/p&gt;

&lt;p&gt;Not receive or process the ENVIRONMENT_DELETED event&lt;br&gt;
Leave all environment-scoped secrets active on Vercel/AWS Lambda&lt;br&gt;
Not update the integration metadata to reflect the environment was gone&lt;br&gt;
Create orphaned credentials that users would have to manually clean up&lt;/p&gt;

&lt;p&gt;Error behavior:&lt;br&gt;
While there wasn't a specific error message, the silent failure was the problem. Users would delete an environment expecting it to be cleaned up everywhere, but the secrets would persist on external platforms with no warning or indication that cleanup failed.&lt;br&gt;
After the fix:&lt;br&gt;
The integration now:&lt;br&gt;
Subscribes to ENVIRONMENT_UPDATED and ENVIRONMENT_DELETED events&lt;br&gt;
Automatically removes environment variables from Vercel projects when environments are deleted&lt;br&gt;
Removes environment-scoped keys from AWS Lambda function configurations&lt;br&gt;
Updates integration metadata to stay in sync with environment name changes&lt;br&gt;
Uses retry logic with exponential backoff for resilience against transient API failures&lt;br&gt;
Persists failed operations in pendingCleanup for later reconciliation&lt;br&gt;
Logs audit events for compliance and debugging&lt;/p&gt;

&lt;p&gt;Key Implementation Detail:&lt;br&gt;
For Vercel's ENVIRONMENT_UPDATED handler, there's a special consideration: Vercel only allows renaming custom environments on Pro plans, not the standard "Preview", "Production", or "Development" environments. The code includes logic to attempt the rename and gracefully handle cases where it's not supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;While preparing my pull request, I ran into several real-world challenges that highlight what contributing to an active open-source project actually looks like behind the scenes. The first issue was merge conflicts between my branch (attempt-1254) and the target develop branch. In a fast-moving repository with many contributors, this is almost inevitable. I resolved the conflicts by pulling the latest upstream changes and manually reviewing each conflicting section to understand both sides. My goal was to preserve other contributors’ work while ensuring my environment lifecycle handler implementation remained intact. After merging, I tested everything locally to confirm nothing regressed, then committed with a clear explanation of the resolution. It was a reminder that merge conflicts aren’t just mechanical fixes — they’re moments where you have to understand the intent of multiple developers and reconcile them thoughtfully.&lt;br&gt;
The next challenge surfaced during code review. A maintainer questioned my use of any type casts in TypeScript, particularly when accessing integration.id and working with the pendingCleanup metadata array. They pointed out that this could introduce long-term technical debt and suggested using @ts-expect-error instead. That feedback was valuable. While the any casts were originally a temporary measure to unblock a critical bug fix, the reviewer highlighted how @ts-expect-error is self-validating: TypeScript warns you if the suppressed error disappears later, which prevents stale workarounds from lingering in the codebase. I acknowledged the concern, added TODO comments recommending a future typed refactor, and committed to either replacing any with @ts-expect-error where appropriate or creating a follow-up issue to properly type the metadata structures. This exchange was a great example of how open-source review culture improves not just correctness, but long-term maintainability.&lt;br&gt;
The biggest blocker came from the CI/CD pipeline. My PR was failing two checks: a Snyk security scan and an API validation build. The frustrating part was that I couldn’t reproduce the failures locally. All my local tests passed — dependencies installed cleanly, the build succeeded, and every unit test ran successfully. But Snyk repeatedly failed in CI with errors related to workspace handling and package manager compatibility. The CLI didn’t fully support the project’s pnpm workspace setup in the same way the CI environment did, and I couldn’t access the GitHub Actions logs directly from my development environment. I tried multiple workarounds, including running Snyk through pnpm and downloading the standalone CLI, but nothing mirrored the CI behavior. Even rerunning the workflows with empty commits didn’t resolve the issue.&lt;br&gt;
At that point, I documented everything I had tried in a detailed PR comment and asked for help. A maintainer with admin access reviewed the CI logs and identified the root cause: a vulnerability in a transitive dependency that required updating the root package.json and regenerating the lockfile. They also explained that the project’s Snyk integration uses a specialized workspace configuration that isn’t trivial to replicate locally. This led to a broader discussion about improving CI transparency for external contributors, including the possibility of automatically surfacing relevant log snippets in PR comments. The experience reinforced an important lesson: as an external contributor, you won’t always have full visibility into infrastructure, and clear documentation of your debugging efforts is essential for maintainers to step in effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution (&lt;a href="https://github.com/keyshade-xyz/keyshade/pull/1255" rel="noopener noreferrer"&gt;PR #1255&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;After working through these issues collaboratively, the pull request was successfully merged. The final solution included environment lifecycle event handlers for both Vercel and AWS Lambda, retry logic with exponential backoff, a reconciliation system for eventual consistency, and comprehensive test coverage. All CI checks passed, and review feedback was fully addressed. More importantly, the contribution closed a high-priority bug that had been blocking production adoption of cloud integrations. It was a strong reminder that persistence, careful communication, and respect for the review process are just as important as writing the code itself. Open-source success isn’t just technical, it’s collaborative.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Did I Learn?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to read official Typescript documentation to break down confusing code&lt;/li&gt;
&lt;li&gt;How to ask beneficial questions to maintainers&lt;/li&gt;
&lt;li&gt;How to navigate CI/CD failures as an external contributor&lt;/li&gt;
&lt;li&gt;Understanding Event-Driven API Architecture&lt;/li&gt;
&lt;li&gt;Snyk improves security in development&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>ci</category>
      <category>github</category>
    </item>
    <item>
      <title>Keyshade Debugging: Mastering Workspace Role Tests and API Repair</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 08 Nov 2025 01:06:38 +0000</pubDate>
      <link>https://forem.com/jds64/keyshade-debugging-mastering-workspace-role-tests-and-api-repair-1ok6</link>
      <guid>https://forem.com/jds64/keyshade-debugging-mastering-workspace-role-tests-and-api-repair-1ok6</guid>
      <description>&lt;p&gt;"A good tester prevents problems; a great tester finds them." &lt;strong&gt;Keith Klain, Director of Quality Engineering at KPMG UK&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Four disabled tests. One cryptic comment: 'flaky.' When I dove into Keyshade's workspace role tests, I discovered the failures weren't random at all—they revealed a fundamental misunderstanding of how the API validates permissions.&lt;/p&gt;

&lt;p&gt;Keyshade is a modern solution for secure, centralized credential and configuration management, designed for developers, DevOps engineers, and open-source communities who need to manage secrets without the headache.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Issue (&lt;a href="https://github.com/keyshade-xyz/keyshade/issues/1122" rel="noopener noreferrer"&gt;#1122&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;I decided to continue my open source journey on Keyshade since my blog post going over how I solved &lt;a href="https://www.linkedin.com/pulse/fixing-cli-error-handling-deep-dive-keyshades-bug-johnny-santamaria-au5yc" rel="noopener noreferrer"&gt;issue 998&lt;/a&gt;, which was that the Keyshade command line interface’s “keyshade run” command fails to give a proper error that users can understand. Now I decided to explore Keyshade’s API since I have explored how the CLI functions in its codebase.&lt;/p&gt;

&lt;p&gt;I found an issue where included a bug in workspace role tests, which meant the problem stemmed from how workspace roles were being set up and asserted in tests, some test fixtures and assertions depended on implicit ordering and shared state, which made the tests fragile and allowed timing or state-dependent flakes to slip into CI (Continuous Integration). By making the setup deterministic and isolating role state for each test (explicitly creating the roles and their relationships, avoiding shared mutable fixtures, and tightening assertions to check the actual role assignments rather than relying on incidental data), the tests now reliably exercise the API behavior they were intended to cover.&lt;/p&gt;

&lt;p&gt;The result is a more robust test suite that accurately guards against regressions in role handling for workspaces, reduces CI noise from flaky failures, and gives us greater confidence in future changes to authorization and workspace logic. Here are some key locations in the codebase we found out to be useful in solving the issue:&lt;/p&gt;

&lt;p&gt;The apps/api/src/workspace-role/ folder includes the workspace-role feature module — contains controller, service, DTOs, and possibly unit/integration tests. Focus on business logic, dependency wiring, and any in-module role constants.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inspect the service methods (assignRole, removeRole, listRoles) for edge-case logic (no-op on duplicate role, default role applied on creation).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check module exports and DI config: ensure the controller gets the expected implementation of the role service (mock vs real) in tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example check: verify if role constants are defined here (e.g., 'admin', 'member', 'viewer') and whether they match values used in DB/entities or frontend.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The apps/api/src/workspace-role/workspace-role-controller.ts file includes the controller / HTTP handlers for workspace-role endpoints — review request DTOs/validation, how the controller calls services, status codes, and permission checks performed at the controller layer.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Example request mapping: POST /workspaces/:id/roles -&amp;gt; controller.assignRole(req.params.id, req.body). Check expected body shape (userId, role).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example validation: if controller uses decorators or a schema, show the required fields (e.g., { userId: string, role: 'admin'|'member' }).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example permission check: controller may call guard like ensureWorkspaceAdmin(currentUser, workspaceId) — confirm where that check happens and what error it throws (403 vs 401).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The apps/api/src/workspace-role/workspace-role/workspace-role.e2e.spec.ts file has end-to-end tests for workspace-role flows — tests that spin up the app (or a test server), seed DB data or fixtures, run real HTTP requests, and assert full-stack behavior and responses.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Test setup/teardown: show DB seeding (create users, create workspace) and cleanup steps to avoid cross-test leakage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example test case: an e2e test that POSTs role assignment and then GETs membership list to assert the new role is present; include expected status codes and response shapes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flakiness checks: look for timeouts, async waits, or hard-coded delays that may make these tests flaky (and thus failing intermittently).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;General Diagram Walkthrough of the Issue&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyjrp522srr83v1oolb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyjrp522srr83v1oolb7.png" alt="General Diagram Walkthrough of the Issue" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproducing the Problem
&lt;/h2&gt;

&lt;p&gt;Here are steps regarding how I reproduced the problem before assessing my plan, implementation, and solution&lt;/p&gt;

&lt;p&gt;Scenario 1 — should not be able to update the workspace role with environments that do not belong to the project Steps to reproduce the behaviour:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create (or use) a workspace W.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Project A in W and capture PROJECT_A_ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Project B in W and capture PROJECT_B_ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Environment A in Project A (ENV_A_ID) and Environment B in Project B (ENV_B_ID).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a workspace role R for Project A that includes only ENV_A_ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure your CLI to target workspace W and authenticate with a token that can update roles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the CLI (or send an API request) to update role R to set environmentIds = [ENV_A_ID, ENV_B_ID].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe the response/error shown by the CLI.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Expected behaviour&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The API should validate that ENV_B_ID does not belong to Project A and return a 4xx validation error (e.g., 400 or 422) with a clear, formatted message such as: "environment ENV_B_ID does not belong to project PROJECT_A_ID"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CLI should print that formatted message to the user (no opaque stack trace or generic 500).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The update must be rejected and the role R must remain unchanged (still only ENV_A_ID).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scenario 2 — should be able to add environment access for projects to the role with READ_WORKSPACE, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT authorities Steps to reproduce the behaviour:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create (or use) a workspace W.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Project P in W and ensure it has at least one environment (ENV_P_1, …).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a workspace role R (it may initially have no project-level environment access).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Obtain an auth token that has the authorities: READ_WORKSPACE, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure your CLI to use workspace W and that token.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the CLI (or send an API request) to add project-level environment access for Project P to role R (the endpoint that grants project environment access).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe the response/error shown by the CLI and then GET the role R to inspect its environment access.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Expected behaviour&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The API should accept the request and return 200/201 with a clear success body describing the new project-level environment access (or list of environmentIds that were added).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CLI should print a readable success message and show the role now has access to Project P environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the token lacks any required authority, the API should return 403 Forbidden with a clear formatted error and the CLI should print that message.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scenario 3 — should be able to add environment access for projects to the role (permission variation) Steps to reproduce the behaviour:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create (or use) a workspace W, a Project X with environments, and a role R.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prepare two auth tokens:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* AUTH\_ADMIN: token with UPDATE\_WORKSPACE\_ROLE (and related read authorities).

* AUTH\_RESTRICTED: token without UPDATE\_WORKSPACE\_ROLE.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Configure your CLI to use workspace W.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With AUTH_ADMIN, run the CLI command (or API request) to add Project X environment access to role R. Verify success.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With AUTH_RESTRICTED, attempt the same CLI command (or API request) to add Project X environment access to role R. Observe the response/error shown by the CLI.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Expected behaviour&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;With AUTH_ADMIN: API returns 200/201 and the role R gains access to Project X environments; CLI prints a readable success confirmation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With AUTH_RESTRICTED: API returns 403 Forbidden with a clear formatted message like "missing authority: UPDATE_WORKSPACE_ROLE" and the CLI prints that message; role R must not be modified.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scenario 4 — should not be able to create workspace role where environments do not belong to the project Steps to reproduce the behaviour:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create (or use) a workspace W.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Project A and Project B in W.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create Environment B in Project B (ENV_B_ID).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure your CLI to target workspace W with a token that can create roles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the CLI (or POST API) to create a workspace role with:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* projectId = PROJECT\_A\_ID

* environmentIds = \[ENV\_B\_ID\]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Observe the response/error shown by the CLI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Expected behaviour&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The API must reject the create request with a 4xx validation error (e.g., 400 or 422) and a clear message such as: "environment ENV_B_ID does not belong to project PROJECT_A_ID"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CLI should print that formatted error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No role should be created.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keyshade’s Codebase&lt;/p&gt;

&lt;p&gt;Here is Keyshade's codebase and API related to this issue, and how would I use the code to diagnose and fix the failing workspace-role tests, displaying the importance of code organization.&lt;/p&gt;

&lt;p&gt;High-level overview (relevant subsystems)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Schema / client shapes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;packages/schema/src/workspace-role/index.ts defines the WorkspaceRole payload shape (projects + environments arrays, authorities, etc.). That tells you the expected request/response shape for workspace role create/update operations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;API service layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;apps/api/src/workspace-role/workspace-role.service.ts contains the logic that parses project -&amp;gt; environment inputs and applies DB operations. The key function is parseProjectEnvironmentsDBOperation which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;verifies that an environment slug exists and belongs to the provided project&lt;/li&gt;
&lt;li&gt;throws NotFoundException if an environment is not part of the project&lt;/li&gt;
&lt;li&gt;calls authorizationService.authorizeUserAccessToEnvironment to ensure the acting user has READ_ENVIRONMENT on that environment&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Authorization checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/api/src/auth/service/authorization.service.ts and apps/api/src/auth/service/authority-checker.service.ts implement the authority checks and higher-level authorization plumbing. authorizationService exposes methods such as authorizeUserAccessToEnvironment and authorizeUserAccessToSecret; these both call into the authority checker and also verify workspace membership.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Tests &amp;amp; client usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;packages/api-client/tests/workspace-role.spec.ts contains tests that exercise the workspace-role APIs from a client perspective (create workspace, create project, create environments, then create/update roles).&lt;/li&gt;
&lt;li&gt;apps/platform and controller-instance reference the WorkspaceRoleController from the generated API client; you can use the API client or the CLI to reproduce e2e scenarios.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Why the tests were failing (what the issue description lists)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The failing/disabled tests are focused on cases where environments provided for a workspace role do not belong to the project, and cases that require multiple authorities (READ_WORKSPACE, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The service code enforces two separate checks:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Ownership check: the environment must belong to the provided project — otherwise parseProjectEnvironmentsDBOperation throws NotFoundException with a message like "Environment X is not part of project Y".

2. Authorization check: after confirming the environment belongs to the project, the service calls authorizationService.authorizeUserAccessToEnvironment which requires the user to have READ\_ENVIRONMENT on that environment (and also checks workspace access).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If tests tried to use an environment that belongs to a different project, the service will intentionally return 404/NotFound before attempting to grant access; tests must assert that behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If tests expected that adding environment access requires specific authorities, the test setup must give the test-user those authorities (or use a workspace-admin) before calling the endpoint.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to use the codebase to reproduce, diagnose, and fix the tests&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce the failing case manually (fastest way to see precise error):&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Use packages/api-client/tests/workspace-role.spec.ts as a reference for how tests set up the workspace/project/environment/role chain.

* From an integration/e2e test or an API client, create:

    * workspace A

    * project P1 inside workspace A

    * project P2 inside workspace A

    * environment E1 in P1 and environment E2 in P2

* Then attempt to create/update a workspace role that includes project P1 but lists environment E2 (an environment that belongs to P2).

* Observe the response: workspace-role.service.ts is expected to detect the mismatch and return a 404 Not Found with message "Environment ... is not part of project ...".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Check the authority path:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* If you provide a correct project-&amp;amp;gt;environment mapping, but the requestor lacks READ\_ENVIRONMENT (or other expected authorities like UPDATE\_WORKSPACE\_ROLE), authorizationService.authorizeUserAccessToEnvironment will throw Unauthorized/Forbidden. Ensure test user has the required authorities when the test expects success.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Fix the tests (common issues &amp;amp; fixes):&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* If a test was disabled because it used an environment from a different project but expected a different error (or success), restore the test and:

    * Either adjust the test to expect NotFound (because parseProjectEnvironmentsDBOperation intentionally rejects cross-project environments).

    * Or adjust test fixtures so the environment is created in the same project as the project entry in the request.

* For authority-related tests:

    * Make sure the test user has the necessary authorities before calling the API. Grant a role to the test user with READ\_WORKSPACE, UPDATE\_WORKSPACE\_ROLE, READ\_PROJECT, READ\_ENVIRONMENT when the test expects role creation/update to succeed.

    * If a test is verifying denial paths (should not be able to create/update), ensure the user has fewer/missing authorities and assert the API returns Unauthorized/Forbidden appropriately.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Where to change code if the behavior is incorrect:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* If you decide the server should validate authority first (instead of ownership first), modify parseProjectEnvironmentsDBOperation ordering; but be careful: the current behavior (check membership/ownership first, then authorization) is consistent with tests that expect NotFound for cross-project envs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;If messages or status codes are inconsistent with tests, adjust the thrown exceptions in parseProjectEnvironmentsDBOperation (NotFoundException) or in authorizationService (Unauthorized/Forbidden) to align with the test expectations — but prefer changing tests to reflect correct domain behavior unless an API bug is proven.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Useful files to inspect or instrument:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* packages/schema/src/workspace-role/index.ts (payload schema)

* apps/api/src/workspace-role/workspace-role.service.ts (parseProjectEnvironmentsDBOperation and create/update logic)

* apps/api/src/auth/service/authorization.service.ts (authorizeUserAccessToEnvironment)

* apps/api/src/auth/service/authority-checker.service.ts (lower-level authority checks)

* packages/api-client/tests/workspace-role.spec.ts (test setup and expected assertions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Concrete actionable checklist to resolve the issue in the repository&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Re-enable the disabled tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each disabled test, verify which of the two server behaviors it is validating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ownership validation (environment belongs to project) → expect 404 Not Found. Ensure test builds a request with a mis-matched environment and asserts a 404 and the message text if desired.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Authorization validation (user needs the listed authorities) → ensure test grants the required authorities to the requester when expecting success; when expecting failure, ensure the user lacks at least one required authority and assert Unauthorized/Forbidden.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Run the tests locally (or in CI):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The workspace-role e2e test file: packages/api-client/tests/workspace-role.spec.ts is a good starting point.&lt;/li&gt;
&lt;li&gt;Add logging in workspace-role.service.ts parseProjectEnvironmentsDBOperation if you need to trace why an environment was rejected.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If the test failure shows unexpected status codes or messages, adjust the service's thrown exceptions to match the documented API or update the tests to assert the documented behavior.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;If you change server code, add unit tests in apps/api for parseProjectEnvironmentsDBOperation to cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;environment not in project → NotFound&lt;/li&gt;
&lt;li&gt;environment in project but user lacks READ_ENVIRONMENT → Unauthorized/Forbidden&lt;/li&gt;
&lt;li&gt;environment in project and user has authority → success path produces correct DB ops&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Short example of the expected behavior (mapping to the tests listed in the issue)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;"should not be able to update the workspace role with environments that do not belong to the project":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call update role with project P1 + env from P2 → server should return 404 Not Found (environment not part of project).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;"should be able to add environment access for projects to the role with READ_WORKSPACE, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT authorities":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure requestor has those authorities (assign a role in test fixture) → call create/update and assert success and that the role contains the project-&amp;gt;environment mapping in response.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;"should be able to add environment access for projects to the role":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same as above but likely using normal granted authorities; ensure fixtures grant appropriate permissions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;"should not be able to create workspace role where environments do not belong to the project":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create role payload with mismatched environment → expect 404 Not Found.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Where to look in code to make changes or confirm behavior&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;parseProjectEnvironmentsDBOperation in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/api/src/workspace-role/workspace-role.service.ts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;authorization plumbing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/api/src/auth/service/authorization.service.ts&lt;/li&gt;
&lt;li&gt;apps/api/src/auth/service/authority-checker.service.ts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;request/response schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;packages/schema/src/workspace-role/index.ts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;packages/api-client/tests/workspace-role.spec.ts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use Case
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Goal: Create/update a workspace role that grants access to specific projects and, within those projects, specific environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Client payload shape (what the API expects)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. name, description, authorities (array), projectEnvironments: \[{ projectSlug, environmentSlugs: \[slug\] }\]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Server behavior (what the code enforces)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. For each projectEnvironments entry, resolve projectSlug -&amp;amp;gt; projectId (getProjectSlugToIdMap).

2. For each environmentSlug in environmentSlugs:

    * Verify that environmentSlug exists AND belongs to that project (prisma.environment.findFirst where slug + projectId). If not, throw NotFoundException (404) with a body "Environment not found" / "Environment X is not part of project Y".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Authorize the acting user has READ_ENVIRONMENT for that environment (authorizationService.authorizeUserAccessToEnvironment). This also verifies workspace-level access and permitted authorities (via authorityCheckerService).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Finally, upsert projectWorkspaceRoleAssociation rows connecting roleId&amp;lt;&amp;gt;projectId and connect the environment slugs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why the workspace-role tests were failing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The failing/disabled tests covered two distinct types of validation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ownership validation: environment must belong to the project in the request. If not, server should reject with 404 (Not Found).&lt;/li&gt;
&lt;li&gt;Authorization validation: even if environment belongs to project, the acting user must have proper authorities (READ_ENVIRONMENT, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_WORKSPACE_ROLE) to add environment access to a role.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Typical causes for failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tests that assert 404 were previously commented out or used incorrect fixtures (e.g., environment not created, or created but in same project), so the server behavior didn't match test expectations.&lt;/li&gt;
&lt;li&gt;Tests that assert successful updates weren't ensuring the test actor had the required authorities (so server returned Unauthorized/401/403 instead of 200).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;My PR re-enabled those tests and fixed fixtures by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating environments in the correct projects (dev, stage).&lt;/li&gt;
&lt;li&gt;Explicitly setting the membership role authorities (e.g., update the workspace member role to include READ_ENVIRONMENT and UPDATE_WORKSPACE_ROLE) when the test expected updates to succeed.&lt;/li&gt;
&lt;li&gt;Using consistent test header 'x-e2e-user-email' (alice.email) for requests.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Walkthrough of the two failing test categories and what to change&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Environment doesn't belong to the project" (ownership)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Server side: parseProjectEnvironmentsDBOperation checks project membership:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It runs prisma.environment.findFirst({ where: { slug: environmentSlug, projectId } })&lt;/li&gt;
&lt;li&gt;If not found, it throws: throw new NotFoundException(constructErrorBody('Environment not found', Environment ${environmentSlug} is not part of project ${pe.projectSlug}))&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Tests expecting 404 must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a workspace and two projects in that workspace.&lt;/li&gt;
&lt;li&gt;Ensure the environment used in the request was created in THE OTHER project, or not created at all (but prefer creating in other project to avoid false positives).&lt;/li&gt;
&lt;li&gt;Make a POST/PUT with projectSlug set to projectA and environmentSlugs containing an environment slug that actually belongs to projectB.&lt;/li&gt;
&lt;li&gt;Assert statusCode === 404.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;"Adding environment access requires specific authorities" (authorization)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Server side: after ownership check, parseProjectEnvironmentsDBOperation calls: await this.authorizationService.authorizeUserAccessToEnvironment({ user, slug: environmentSlug, authorities: [Authority.READ_ENVIRONMENT] })&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That code path will call authorityCheckerService.checkAuthorityOverEnvironment which checks the acting user's permitted authorities for that environment (it can be from project-level or workspace-level roles).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tests expecting success must ensure the acting user has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;READ_WORKSPACE (if required by the flow), UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT — in practice, the tests can mutate an existing workspace role for the test user to include these authorities and also connect appropriate project/environment associations so the user has project-scoped authority.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Exact test changes — enable one disabled test and adjust fixture&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Below is a concrete enabled test snippet for packages/api-client/tests/workspace-role.spec.ts that re-enables the “should not be able to create workspace role where environments do not belong to the project” scenario.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This patch enables the test and makes the fixture explicit: create two projects, create an environment in projectB, then attempt to create a workspace role that references projectA + the environment slug from projectB. The test asserts 404.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;packages/api-client/tests/workspace-role.spec.ts&lt;/p&gt;

&lt;p&gt;// (This is the test snippet to add/enable within the existing test suite)&lt;/p&gt;

&lt;p&gt;it('should not be able to create workspace role where environments do not belong to the project', async () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;// Precondition: two projects exist in the workspace&lt;/p&gt;

&lt;p&gt;// projects[0] -&amp;gt; projectA, projects[1] -&amp;gt; projectB (test fixture established earlier in the file)&lt;/p&gt;

&lt;p&gt;// Create an environment in projectB that should NOT be valid for projectA&lt;/p&gt;

&lt;p&gt;await prisma.environment.create({&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Notes about placement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put this enabled test near the other workspace-role create tests after the workspace + project fixtures are created and available.&lt;/li&gt;
&lt;li&gt;Ensure projects variable references are the ones created during beforeAll/beforeEach steps in that test file.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;A directly analogous enabled e2e test (what PR 1156 did)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PR 1156 enabled very similar tests in apps/api/src/workspace-role/workspace-role.e2e.spec.ts — it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created dev/stage environments in the proper projects,&lt;/li&gt;
&lt;li&gt;Updated the Member workspace role to add project associations and required authorities for the actor,&lt;/li&gt;
&lt;li&gt;Re-enabled the previously commented tests and asserted status codes 200 or 404 as appropriate.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Small server-side unit test to lock in parseProjectEnvironmentsDBOperation behavior&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I recommend adding a unit test that calls parseProjectEnvironmentsDBOperation (or exercises the public create/update API) with a project-environment mismatch and asserts a NotFoundException is thrown.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example test file (unit) to confirm rejection for cross-project environment:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;apps/api/src/workspace-role/workspace-role.service.spec.ts&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing'&lt;/p&gt;

&lt;p&gt;import { WorkspaceRoleService } from './workspace-role.service'&lt;/p&gt;

&lt;p&gt;import { AuthorizationService } from '@/auth/service/authorization.service'&lt;/p&gt;

&lt;p&gt;import { PrismaService } from '@/prisma/prisma.service'&lt;/p&gt;

&lt;p&gt;import { NotFoundException } from '@nestjs/common'&lt;/p&gt;

&lt;p&gt;Proposed server code changes — minimal / optional&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The current server code in parseProjectEnvironmentsDBOperation is already correct about ownership-first validation (it checks slug + projectId before calling authorizeUserAccessToEnvironment). The PR you provided does not require a behavior change on the server — tests should reflect the server semantics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you did want to change server behavior, the main two options are:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Keep current semantics (ownership check first, then authorization). Pros: deterministic 404 for cross-project envs; avoids running authorization queries for environment slugs that don't belong to the provided project. Cons: reveals that the environment slug exists in a different project (server replies 404 with message referencing project mismatch).

2. Run authorization first (i.e., check the caller's permissions to read the environment before checking project membership). Pros: could collapse some error channels and avoid disclosing cross-project existence if the caller lacks permission. Cons: often you still need to fetch the environment by slug (so you still learn about its existence) — and the authorization check typically requires fetching the environment anyway to know project/workspace id. It also changes the status codes returned for the cross-project case (may return 401 instead of 404), which is a breaking API semantics change for clients that currently rely on 404 in that case.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Recommendation: do NOT change the ordering of checks unless there's a clear security/privacy reason. The current behavior (404 on ownership mismatch) matches the tests in PR 1156 and is explicit. Prefer to fix test fixtures and grant/revoke authorities in test setup rather than altering server semantics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why the PR's approach (what you already did in PR 1156) is correct&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You re-enabled tests and fixed fixtures instead of changing server semantics. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created missing environments in the appropriate projects before calling the API.&lt;/li&gt;
&lt;li&gt;Updated the test user/role authorities where tests expected success.&lt;/li&gt;
&lt;li&gt;Asserted the correct status codes: 404 for ownership mismatch and 200 for successful updates when authorities exist.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;This is minimal and non-breaking.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Trade-offs if you change server behavior (ownership vs authorization ordering)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Changing the order to authorize first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;May return 401/403 instead of 404 for the cross-project environment case — tests and clients must be updated.&lt;/li&gt;
&lt;li&gt;Could obscure whether an environment exists in another project (slight security benefit).&lt;/li&gt;
&lt;li&gt;Could introduce additional database lookups if you need to check membership as well; may not yield significant performance gain.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Keeping ownership-first (current):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear, deterministic 404 response for mismatched environment ownership.&lt;/li&gt;
&lt;li&gt;Tests remain simple: assert 404 for the cross-project case.&lt;/li&gt;
&lt;li&gt;Slight information disclosure (you show that environment exists but in a different project), which may be acceptable in an internal system like Keyshade.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Summary of exact artifacts to change (concrete)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add/enable the test in packages/api-client/tests/workspace-role.spec.ts as above (or in apps/api/src/workspace-role/workspace-role.e2e.spec.ts — PR 1156 already did the same).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a small unit test in apps/api/src/workspace-role/workspace-role.service.spec.ts to lock in behavior of parseProjectEnvironmentsDBOperation for cross-project envs (example above).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure any tests that expect successful updates explicitly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create the environments in the projects they want to reference&lt;/li&gt;
&lt;li&gt;grant the test actor role(s) the required authorities (UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT) before calling create/update&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;I reviewed PR #1156 and walked the tests and service code. Below I list concrete challenges we encountered while making this PR and practical mitigations. I narrate what I checked and what I'd recommend next.&lt;/p&gt;

&lt;p&gt;What I did (quick recap)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inspected the workspace-role service logic (parseProjectEnvironmentsDBOperation) and the authorization flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reviewed the test files that were re-enabled/modified in the PR (workspace-role e2e/spec files).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confirmed the PR fixes were basically test-fixture and authority-setup issues (creating environments in right projects, granting the test user required authorities), not major server-behavior changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verified the PR merged successfully but noted a set of practical challenges that often show up in this work.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Challenges encountered (with examples and mitigations)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test fixture brittleness and DB state coupling&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: E2E tests depend on precise workspace/project/environment setup and roles. Small differences in fixture creation order or leftover DB rows cause flakiness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: A test assumed "production" env exists in projectA but CI used a different test run that already had production in projectB -&amp;gt; unexpected 200 instead of 404.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always create and assert fixtures in test setup (do not assume names).&lt;/li&gt;
&lt;li&gt;Use randomized slugs (e.g., slug-&amp;lt;timestamp&amp;gt;-&amp;lt;random&amp;gt;) to avoid collisions across parallel CI jobs.&lt;/li&gt;
&lt;li&gt;Add teardown/cleanup that removes created rows or run tests inside isolated databases/transactions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Authority/permission complexity in tests&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Tests that check success paths require several authorities (READ_WORKSPACE, UPDATE_WORKSPACE_ROLE, READ_PROJECT, READ_ENVIRONMENT). If the test doesn't explicitly grant them, the server returns Unauthorized and the test fails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: Test enabling environment access but not updating the Member role to include UPDATE_WORKSPACE_ROLE.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly set up the actor’s roles/authorities per test case.&lt;/li&gt;
&lt;li&gt;Add helper functions in tests for "grantMemberAuthoritiesForEnvironmentAccess" to make fixtures clear.&lt;/li&gt;
&lt;li&gt;Keep negative/positive authority tests separate and deterministic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Merge conflicts (simple but annoying)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Enabling tests and modifying the same test files or fixtures on different branches led to conflicts (e.g., two branches each uncommented different blocks of tests).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: Two branches changed apps/api/src/workspace-role/workspace-role.e2e.spec.ts: one enabled a test, another refactored a beforeEach. Merge resulted in conflict markers around large commented blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rebase frequently on the develop branch to reduce long-lived divergences.&lt;/li&gt;
&lt;li&gt;Split large test-enabling changes into smaller PRs (enable + fix fixtures + authority wiring).&lt;/li&gt;
&lt;li&gt;When resolving conflicts, run the full test suite locally before pushing the merge commit.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Creating temporary test files or helper tests "to be removed later" causing issues&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Developers often create throwaway tests / temporary files to debug behavior and forget to remove them. These can be picked up by CI and cause nondeterministic runs or duplicate test names.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: Added apps/api/src/workspace-role/tmp-debug.spec.ts to iterate quickly, later removed locally but remained in another branch → CI fails or duplicate DB setup occurs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid committing throwaway test files. If necessary, keep them in local-only branches or protect with a naming convention excluded from CI.&lt;/li&gt;
&lt;li&gt;Add CI test discovery rules to ignore test files matching tmp-*.spec.ts, if you must have temporary tests.&lt;/li&gt;
&lt;li&gt;Review diffs carefully before commit and run git status to ensure no debug/test files are included.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Test duplication across packages (api-client vs apps/api)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Similar workspace-role tests existed in both packages/api-client/tests and apps/api e2e test files; enabling one copy and forgetting to update the other caused inconsistent behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: One test in packages/api-client used the API client and different headers than the e2e server-side test; runtime differences led to mismatched assertions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consolidate canonical e2e tests in one place (prefer apps/api e2e that hits the server directly), keep api-client tests focused on client behavior.&lt;/li&gt;
&lt;li&gt;If duplication is unavoidable, keep test expectations aligned and use shared helpers/mocks.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Race conditions in setup/cleanup (parallel tests)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Creating projects/environments concurrently across parallelized test jobs (or even within same job) created timing-based failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make tests idempotent and isolate data per test.&lt;/li&gt;
&lt;li&gt;Use unique slugs per test run.&lt;/li&gt;
&lt;li&gt;Consider serializing tests that share DB resources or use test DB instances per worker.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Error/status-code semantics and client expectations&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Tests rely on specific status codes (404 vs 401). If server-side code ordering changes (ownership check vs authorization check) the codes change and many tests break.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: If you move authorization first, a cross-project environment case might return 401 instead of 404.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep server semantics stable; if a change is required, update all tests and document the change.&lt;/li&gt;
&lt;li&gt;Add unit tests that assert the contract (e.g., cross-project environment -&amp;gt; NotFound).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;CI flakiness from environment variables and headers&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: Some tests rely on headers like 'x-e2e-user-email'. If CI environment variable email differs or parallel runs reuse the same email, tests can mutate shared state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a test-specific email per run (e.g., alice+&amp;lt;run-id&amp;gt;@keyshade.xyz).&lt;/li&gt;
&lt;li&gt;Make test harness read and propagate headers from the same fixture source.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Commit noise and history (multiple tiny commits while fixing test)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: WIP commits to enable tests, debug, revert, add files, remove files created a messy branch and bigger diffs, increasing review overhead and merge conflicts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Squash local fixup commits before opening PR or use interactive rebase to tidy commits.&lt;/li&gt;
&lt;li&gt;Keep PRs small and focused: one PR for enabling tests and fixtures, another for refactors.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Accidental API contract changes vs test fixes&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Problem: When tests fail, there’s a temptation to change server code to make tests pass instead of fixing tests. That can mask real bugs or break clients.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mitigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer fixing tests/fixtures if the server behavior matches documented contract.&lt;/li&gt;
&lt;li&gt;If server needs change, write unit tests to cover new contract and get reviewer approval.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Concrete, practical steps I recommend next&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add a small checklist to PR templates for test-enabling PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm unique slugs in fixtures&lt;/li&gt;
&lt;li&gt;Confirm actor authorities are set explicitly&lt;/li&gt;
&lt;li&gt;Run full test suite locally (or run the specific e2e group) before pushing&lt;/li&gt;
&lt;li&gt;Clean up any temporary test files&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Add a helper in tests for deterministic unique slugs and user emails to avoid collisions in CI.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Consider adding a lint/CI guard that fails the build when "tmp-*.spec.ts" or "debug" test files are found in the commit.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If you expect future merges to touch the same big e2e files, coordinate branches or split PRs (e.g., create "enable tests" PR and a follow-up "refactor fixtures" PR).&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Here is a summarized plan of my solution:&lt;/p&gt;

&lt;p&gt;Lock the contract with unit tests by adding unit tests that assert parseProjectEnvironmentsDBOperation rejects cross-project environment slugs with NotFound. This prevents accidental server reordering from changing semantics. Make tests deterministic by ensuring every test explicitly creates its fixtures (workspace, project, environment) and set unique slugs per run, which will explicitly grant the required authorities to the test actor in success-path tests.&lt;/p&gt;

&lt;p&gt;Prevent accidental temporary test files by adding the pre-commit hook above and a CI check to refuse pushes that include tmp/debug test files. Keep good merge strategies and PR hygiene by keeping PRs small and focused (enable tests separately from refactors). Make sure to rebase frequently and squash debug commits and add a PR/TODO checklist that requires: unique slugs, explicit authority setup, no temporary files, and local e2e run before requesting review. Consolidate test suites by deciding canonical location for workspace-role e2e tests (prefer apps/api e2e) and remove duplicates, or centralize test helpers. Here is my final PR solving the issue over a month:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/keyshade-xyz/keyshade/pull/1156" rel="noopener noreferrer"&gt;PR #1156&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, Keyshade’s clean, well-structured codebase and deterministic tests make development faster, safer, and more collaborative. Clear intent, consistent conventions, and reliable CI build trust between maintainers and contributors—enabling focused changes, quicker reviews, and confident releases.&lt;/p&gt;

</description>
      <category>api</category>
      <category>devbugsmash</category>
      <category>typescript</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Fixing CLI Error Handling: A Deep Dive into Keyshade's WebSocket Communication Bug</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Tue, 12 Aug 2025 15:00:00 +0000</pubDate>
      <link>https://forem.com/jds64/fixing-cli-error-handling-a-deep-dive-into-keyshades-websocket-communication-bug-489m</link>
      <guid>https://forem.com/jds64/fixing-cli-error-handling-a-deep-dive-into-keyshades-websocket-communication-bug-489m</guid>
      <description>&lt;p&gt;“If you build software, every error message is marketing” - &lt;strong&gt;Jason Fried, &lt;a href="https://www.goodreads.com/work/quotes/6928276" rel="noopener noreferrer"&gt;Rework&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today’s fast-paced software development landscape, managing credentials and sensitive configurations securely is more critical—and more challenging—than ever. Dispersed secrets, manual processes, and unplanned storage not only slow teams down but also increase the risk of breaches and operational errors. &lt;strong&gt;Keyshade&lt;/strong&gt; addresses these challenges head-on with a centralized, automated approach to credential and configuration governance. Purpose-built for engineering teams, DevOps practitioners, startups, and open-source maintainers. Keyshade streamlines secret management while enhancing security, collaboration, and efficiency.&lt;/p&gt;

&lt;p&gt;Keyshade is an advanced platform for centralized credential and configuration governance, designed to safeguard sensitive data, eliminate human error, and streamline operational complexity. By automating secret management, it fortifies security posture, amplifies cross-team collaboration, and liberates developers from the inefficiencies of fragmented secret storage. Its primary constituency—engineering teams, DevOps practitioners, early-stage startups, and open-source maintainers—adopts Keyshade to mitigate secret proliferation, minimize security liabilities, and embed robust secret orchestration seamlessly into their development pipelines. Users gravitate toward Keyshade for its ability to render secret management secure, intuitive, and collaborative, without imposing friction upon established workflows or toolchains. Below is a flow of control diagram discussing how users would typically use the product:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn04j9jpb4md0z634g4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyn04j9jpb4md0z634g4o.png" alt=" " width="800" height="858"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user can send commands via keyshades terminal or on keyshades web app
&lt;/li&gt;
&lt;li&gt;On the web, the user can sign up, and initialize projects within workspaces

&lt;ul&gt;
&lt;li&gt;Users can do the same in the &lt;a href="https://docs.keyshade.xyz/getting-started/setting-up-your-profile" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once the a project is made a http request is made to the API websocket service
&lt;/li&gt;
&lt;li&gt;The websocket service then retrieves that data to put in the Keyshade’s database to save the data for future use&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keyshade is currently in alpha and not live so there really are not any users as of posting this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;I partnered with a member of the Computing Talent Initiative with the task of solving &lt;a href="https://github.com/keyshade-xyz/keyshade/issues/998" rel="noopener noreferrer"&gt;issue 998&lt;/a&gt; in Keyshade for a Summer Open Source Experience sponsored by . The main problem we noticed was that the Keyshade command line interface’s “keyshade run” command fails to give a proper error that users can understand. We would want to extract an error message and output it to the user. The issue is a bug that seems urgent to solve right now for users to understand errors they might make when working with Keyshade’s CLI, which is the main feature of Keyshade. Here are some key locations in the codebase we found out to be useful in solving the issue:&lt;/p&gt;

&lt;h3&gt;
  
  
  run.command.ts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Handles CLI logic for running commands, including WebSocket client interactions
&lt;/li&gt;
&lt;li&gt;Within a CLI folder&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  change-notifier.socket.ts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Contains the handleRegister method, which processes the register-client-app event
&lt;/li&gt;
&lt;li&gt;Handles authentication, authorization, and client registration logic
&lt;/li&gt;
&lt;li&gt;Emits the client-registered response to the client and logs errors
&lt;/li&gt;
&lt;li&gt;Within an API folder&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  run.types.d.ts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ClientRegisteredResponse describes the shape of the response sent by the server after registration (success, message)
&lt;/li&gt;
&lt;li&gt;Ensures type safety for client-side code handling server responses
&lt;/li&gt;
&lt;li&gt;Within a CLI folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are steps regarding how we reproduced the problem before finding the important locations in the codebase&lt;/p&gt;

&lt;p&gt;Steps to reproduce the behaviour:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a project on keyshade
&lt;/li&gt;
&lt;li&gt;Configure your CLI to tap into this project
&lt;/li&gt;
&lt;li&gt;Delete the project
&lt;/li&gt;
&lt;li&gt;Use keyshade run &amp;lt;&amp;gt; command
&lt;/li&gt;
&lt;li&gt;See the error&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Expected behaviour
&lt;/h2&gt;

&lt;p&gt;We would want the CLI to display what actually went wrong. The API should send the formatted message to the CLI. The CLI should print the error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis4b0st0wzgdaml8xn3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis4b0st0wzgdaml8xn3a.png" alt="Reproduced issue" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyshade’s Codebase
&lt;/h2&gt;

&lt;p&gt;Before delving into the problem itself, and after pinpointing the critical components, we took a step back to develop a comprehensive understanding of the codebase’s architecture. Keyshade’s backend is architected with &lt;strong&gt;NestJS&lt;/strong&gt; (a progressive Node.js framework) and &lt;strong&gt;TypeScript&lt;/strong&gt;, leveraging &lt;strong&gt;Prisma&lt;/strong&gt; as its database ORM, interfacing with a &lt;strong&gt;PostgreSQL&lt;/strong&gt; relational database. It also integrates &lt;strong&gt;Redis&lt;/strong&gt; for high-performance caching and publish/subscribe messaging, as well as &lt;strong&gt;Socket.IO&lt;/strong&gt; for real-time, bidirectional communication between its command line interface and application programming interface.&lt;/p&gt;

&lt;p&gt;On the frontend, the stack comprises &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;TypeScript&lt;/strong&gt;, &lt;strong&gt;JavaScript&lt;/strong&gt;, and &lt;strong&gt;Next.js&lt;/strong&gt;, presumably to power a performant and SEO-friendly web interface. Development workflows are streamlined through &lt;strong&gt;Nx&lt;/strong&gt; (for monorepo orchestration), &lt;strong&gt;ESLint&lt;/strong&gt; and &lt;strong&gt;Prettier&lt;/strong&gt; (for code quality and style enforcement), alongside the TypeScript compiler for rigorous static type checking.&lt;/p&gt;

&lt;p&gt;For security, Keyshade employs &lt;strong&gt;Elliptic Curve Cryptography&lt;/strong&gt; for robust public-key encryption, &lt;strong&gt;JWT&lt;/strong&gt; for token-based authentication, and API key authentication for service-to-service communication. The infrastructure is containerized via &lt;strong&gt;Docker&lt;/strong&gt; and designed with cloud deployment in mind. A high-level system diagram encapsulates the overall architecture of the codebase as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx6hcxpex283fibc2l77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx6hcxpex283fibc2l77.png" alt="Keyshade system diagram" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a use case, using the components in the diagram to give you a better understanding of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case: Developer Fetching Live Configuration Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Developer Initiates CLI Command
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keyshade run \--workspace my-company \--project web-app \--environment production

What happens: The developer runs the CLI command to start their application with live configuration updates from Keyshade.

The CLI documentation can be found [here](https://docs.keyshade.xyz/getting-started/installing-the-cli)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 2: CLI Processes Command (run.command.ts)
&lt;/h3&gt;

&lt;p&gt;The run.command.ts file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parses the command arguments (workspace, project, environment)
&lt;/li&gt;
&lt;li&gt;Reads the local configuration file to get API credentials
&lt;/li&gt;
&lt;li&gt;Validates the required parameters using types from run.types.d.ts
&lt;/li&gt;
&lt;li&gt;Prepares to establish WebSocket connection for live updates&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 3: WebSocket Connection Establishment
&lt;/h3&gt;

&lt;p&gt;The CLI creates a websocket connection:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;const socket = io('ws://api.keyshade.xyz/change-notifier')&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What happens: The client connects to the NestJS backend's WebSocket gateway (change-notifier.socket.ts).&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Client Registration Request
&lt;/h3&gt;

&lt;p&gt;The CLI emits the registration event:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;socket.emit('register-client-app', {  workspaceSlug: 'my-company',  projectSlug: 'web-app',   environmentSlug: 'production'});&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What happens: This triggers the handleRegister method in &lt;a href="http://change-notifier.socket.ts" rel="noopener noreferrer"&gt;change-notifier.socket.ts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5a: Authentication
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const userContext \= await this.extractAndValidateUser(client)  
Extracts API key from WebSocket headers (x-keyshade-token)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Queries PostgreSQL database via Prisma to validate the API key
&lt;/li&gt;
&lt;li&gt;Verifies user account is active&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5b: Authorization checks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;await this.authorizationService.authorizeUserAccessToWorkspace({...})await this.authorizationService.authorizeUserAccessToProject({...})await this.authorizationService.authorizeUserAccessToEnvironment({...})&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Checks if user has READ_WORKSPACE, READ_VARIABLE, READ_SECRET permissions&lt;br&gt;&lt;br&gt;
Validates access to the specific project&lt;br&gt;&lt;br&gt;
Confirms environment access rights&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5c: Client Registration
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await this.addClientToEnvironment(client, environment.id)  
Creates entry in PostgreSQL mapping socket ID to environment ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Adds client to Redis set for real-time notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6: Success Response
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What happens: Server sends confirmation back to CLI using the ClientRegisteredResponse interface from run.types.d.ts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 7: Configuration Fetching
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;After successful registration:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;CLI fetches initial configuration values (secrets, variables)
&lt;/li&gt;
&lt;li&gt;Application starts with these environment variables
&lt;/li&gt;
&lt;li&gt;CLI continues listening for real-time updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 8: Real-Time Updates (Ongoing)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Another developer updates a secret value through the web interface.  

await this.redisSubscriber.subscribe(CHANGE\_NOTIFIER\_RSC, this.notifyConfigurationUpdate.bind(this))  
The web interface publishes change to Redis channel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All API instances receive the notification&lt;/p&gt;

&lt;p&gt;this.server.to(clientId).emit('configuration-updated', data)&lt;br&gt;&lt;br&gt;
Server identifies all clients registered for that environment&lt;br&gt;&lt;br&gt;
Sends update notification to active CLI instances&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLI receives the configuration-updated event&lt;br&gt;&lt;br&gt;
Updates local environment variables&lt;br&gt;&lt;br&gt;
Application continues running with new values&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;One specific technical challenge I encountered while attempting to solve issue 998 was figuring out why my changes in change-notifier.socket.ts were not being reflected when I tested them through the CLI. Despite updating the logic inside the Socket.IO handlers, the CLI behavior remained unchanged, and it was unclear whether the API changes were even being registered. Here is an attempt to solve this challenge and other challenges I encountered.&lt;/p&gt;

&lt;p&gt;So I tried debugging the issue after reproducing the issue and found the debug information for keyshade issue 998&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;@johnny603 ➜ /workspaces/keyshade (teamAttempt/#998) $ DEBUG=* keyshade run "echo 'test'"INFO: Checking API key validity...INFO: API key is valid!INFO: Connecting to socket...socket.io-client:url parse wss://api.keyshade.xyz/change-notifier +0mssocket.io-client new io instance for wss://api.keyshade.xyz/change-notifier +0mssocket.io-client:manager readyState closed +0mssocket.io-client:manager opening wss://api.keyshade.xyz/change-notifier +0msengine.io-client:socket creating transport "websocket" +0msengine.io-client:socket options: {"path":"/socket.io/","agent":false,"withCredentials":false,"upgrade":true,"timestampParam":"t","rememberUpgrade":false,"addTrailingSlash":true,"rejectUnauthorized":true,"perMessageDeflate":{"threshold":1024},"transportOptions":{},"closeOnBeforeunload":false,"autoConnect":false,"extraHeaders":{"x-keyshade-token":"ks_a3adff2a9db8bf3c42fc817880ac4125983b83c171f0d04d"},"transports":[null],"hostname":"api.keyshade.xyz","secure":true,"port":"443","query":{"EIO":4,"transport":"websocket"},"socket":{"binaryType":"nodebuffer","writeBuffer":[],"_prevBufferLen":0,"_pingInterval":-1,"_pingTimeout":-1,"_maxPayload":-1,"_pingTimeoutTime":null,"secure":true,"hostname":"api.keyshade.xyz","port":"443","transports":["websocket"],"_transportsByName":{},"opts":{"path":"/socket.io/","agent":false,"withCredentials":false,"upgrade":true,"timestampParam":"t","rememberUpgrade":false,"addTrailingSlash":true,"rejectUnauthorized":true,"perMessageDeflate":{"threshold":1024},"transportOptions":{},"closeOnBeforeunload":false,"autoConnect":false,"extraHeaders":{"x-keyshade-token":"ks_a3adff2a9db8bf3c42fc817880ac4125983b83c171f0d04d"},"transports":[null],"hostname":"api.keyshade.xyz","secure":true,"port":"443"},"readyState":"opening"}} +0msengine.io-client:socket setting transport websocket +6mssocket.io-client:manager connect attempt will timeout after 20000 +8msengine.io-client:socket socket receive: type "open", data "{"sid":"qxJTaYpvOE4a6kIaAAB8","upgrades":[],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000000}" +756msengine.io-client:socket socket open +0mssocket.io-client:manager open +755mssocket.io-client:manager cleanup +0mssocket.io-client:socket transport is open - connecting +0mssocket.io-client:manager writing packet {"type":0,"nsp":"/change-notifier"} +1mssocket.io-parser encoding packet {"type":0,"nsp":"/change-notifier"} +0mssocket.io-parser encoded {"type":0,"nsp":"/change-notifier"} as 0/change-notifier, +0msengine.io-client:socket flushing 1 packets in socket +1msengine.io-client:socket starting upgrade probes +1msengine.io-client:socket socket receive: type "message", data "0/change-notifier,{"sid":"OpbhAQ0UYcfklhBoAAB9"}" +249mssocket.io-parser decoded 0/change-notifier,{"sid":"OpbhAQ0UYcfklhBoAAB9"} as {"type":0,"nsp":"/change-notifier","data":{"sid":"OpbhAQ0UYcfklhBoAAB9"}} +251mssocket.io-client:socket socket connected with id OpbhAQ0UYcfklhBoAAB9 +251mssocket.io-client:manager writing packet {"type":2,"data":["register-client-app",{}],"options":{"compress":true},"nsp":"/change-notifier"}+251mssocket.io-parser encoding packet {"type":2,"data":["register-client-app",{}],"options":{"compress":true},"nsp":"/change-notifier"} +0mssocket.io-parser encoded {"type":2,"data":["register-client-app",{}],"options":{"compress":true},"nsp":"/change-notifier"} as 2/change-notifier,["register-client-app",{}] +0msengine.io-client:socket flushing 1 packets in socket +1mssocket.io-client:socket draining queue +1msengine.io-client:socket socket receive: type "message", data "2/change-notifier,["client-registered",{"success":false,"message":{"response":{"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","error":"Not Found","statusCode":404},"status":404,"options":{},"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","name":"NotFoundException"}}]" +261mssocket.io-parser decoded 2/change-notifier,["client-registered",{"success":false,"message":{"response":{"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","error":"Not Found","statusCode":404},"status":404,"options":{},"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","name":"NotFoundException"}}] as {"type":2,"nsp":"/change-notifier","data":["client-registered",{"success":false,"message":{"response":{"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","error":"Not Found","statusCode":404},"status":404,"options":{},"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","name":"NotFoundException"}}]} +262mssocket.io-client:socket emitting event ["client-registered",{"success":false,"message":{"response":{"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","error":"Not Found","statusCode":404},"status":404,"options":{},"message":"{\"header\":\"Workspace not found\",\"body\":\"Workspace undefined not found\"}","name":"NotFoundException"}}] +261msERROR: Error registering to API: [object Object]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I came to the conclusion that the client is sending an empty object {} in the registration message, but the server expects a ChangeNotifierRegistration object with workspace, project, and environment slugs. This results in undefined values being passed to the authorization check, causing the “Workspace undefined not found” error. The code correctly creates the registrationData object with workspaceSlug, projectSlug, and environmentSlug&lt;br&gt;&lt;br&gt;
But the debug output shows it’s sending an empty object {}&lt;/p&gt;

&lt;p&gt;This suggests that the data parameter being passed to connectToSocket has undefined values for workspace, project, and environment. Our team reached out to the issue maintainer radjip-b with a question regarding our process of the issue so far.&lt;/p&gt;

&lt;p&gt;This small technical challenge was solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The solution for Keyshade’s issue 998 took five and a half weeks to complete during the eight-week internship. In the remaining time, we addressed additional related issues, including issue &lt;a href="https://github.com/keyshade-xyz/keyshade/issues/989" rel="noopener noreferrer"&gt;989&lt;/a&gt; and &lt;a href="https://github.com/keyshade-xyz/keyshade/issues/988" rel="noopener noreferrer"&gt;988&lt;/a&gt;, which involved adding Slack and Discord integration documentation, as well as contributing to &lt;a href="https://github.com/keyshade-xyz/keyshade/pull/1093" rel="noopener noreferrer"&gt;PR 1093&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Changes Introduced by PR #1093:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Slack Integration Documentation&lt;/strong&gt;: A brand-new &lt;strong&gt;“How It Works”&lt;/strong&gt; modal was added to the Keyshade platform’s UI, providing a visual, step-by-step guide—including screenshots—on how to set up Slack integration. This includes selecting Slack in the Integrations tab, entering credentials (signing secret, Bot token, channel ID), and testing with sample secrets and variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modal Improvements &amp;amp; Developer Feedback&lt;/strong&gt;: The modal component underwent adjustments—such as replacing a bare &amp;lt;DialogClose asChild /&amp;gt; (which caused rendering issues) with a proper close button, and revising instructions for better clarity (“Bot Token from Slack”). Additionally, an unused function (_handleClose) was cleaned up and textual instructions were streamlined.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Discord Integration Documentation&lt;/strong&gt;: The scope of the PR was expanded to include documentation for Discord integration as well—hence the updated title to “feat: added slack and discord integration docs.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Internal Routing and Formatting Refactor&lt;/strong&gt;: Responding to reviewer feedback, the team refactored the integration documentation routing logic—removing the DOCS_SLUG_MAP, simplifying routing, standardizing layout for project creation and event triggers, and cleaning up the formatting and positioning of images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lint Fixes&lt;/strong&gt;: Minor linting errors (such as extraneous braces in index.tsx) were corrected to ensure code consistency and avoid build issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Summary Table&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What Changed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Docs &amp;amp; UI&lt;/td&gt;
&lt;td&gt;“How It Works” modal with guide and screenshots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Component Cleanup&lt;/td&gt;
&lt;td&gt;Dialog close functionality fixed, redundant code removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discord Docs&lt;/td&gt;
&lt;td&gt;Documentation for Discord integration added&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slack Docs&lt;/td&gt;
&lt;td&gt;Documentation for Slack integration added&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation Routing&lt;/td&gt;
&lt;td&gt;Routing logic simplified, layout standardized, visuals aligned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Quality&lt;/td&gt;
&lt;td&gt;Linting issues resolved&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Solution Description For Issue #998
&lt;/h3&gt;

&lt;p&gt;Our team resolved a bug where the socket notifier and run command error handling would display [object Object] instead of a meaningful error message. The root cause was improper formatting of the error object before logging it to the user. The fix ensures that error messages are now properly stringified or formatted, providing clearer and more helpful feedback during CLI failures. To verify the fix, you can run the keyshade run command with an invalid configuration or project setup that triggers a connection error. This update significantly improves the developer experience by making error outputs more understandable.&lt;/p&gt;

&lt;p&gt;We determined that only three files required direct changes to address the issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NestJS WebSocket Gateway&lt;/strong&gt; – The server-side component uses NestJS’s @WebSocketGateway decorator with Socket.IO to handle real-time communication between the CLI and API server. The handleRegister method in change-notifier.socket.ts processes client registration requests and can return different error message formats depending on the failure type (authentication, authorization, or database errors).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI Command Handler&lt;/strong&gt; – The run.command.ts file contains the client-side logic that connects to the WebSocket server and handles the registration response. This component already included robust error parsing logic capable of handling both string and object formats, but the TypeScript interface was preventing proper type checking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type Checker&lt;/strong&gt; – The run.types.d.ts file was updated to allow both string and object types, since the server can send either format.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the maintainer approved the fix, we made additional updates to the codebase by modifying two more files: changelog.md to document the changes, and package.json to bump the semantic version to &lt;strong&gt;3.2.3&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is in the file changes
&lt;/h3&gt;

&lt;p&gt;These were changes found using git’s diff command&lt;/p&gt;

&lt;p&gt;What has been changed can also be found &lt;a href="https://github.com/keyshade-xyz/keyshade/pull/1087/files" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changelog.md:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🐛 Bug Fixes* **api, cli:** ambiguous error messages on keyshade run failure ([#1087](&lt;a href="https://github.com/keyshade-xyz/keyshade/issues/1087)" rel="noopener noreferrer"&gt;https://github.com/keyshade-xyz/keyshade/issues/1087)&lt;/a&gt;) ([206dda7](&lt;a href="https://github.com/keyshade-xyz/keyshade/commit/206dda702b3f3f0cabeb73e4f74dd2ccfc962631)" rel="noopener noreferrer"&gt;https://github.com/keyshade-xyz/keyshade/commit/206dda702b3f3f0cabeb73e4f74dd2ccfc962631)&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;apps/cli/package.json: "version": "3.2.2-stage.2",&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;apps/cli/src/types/command/run.types.d.ts:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;message: string | object // Allow both string and object types since server can send either&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/cli/src/commands/run.commands.ts:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Accurate WebSocket URL Parsing:&lt;br&gt;
The CLI’s socket connection logic now uses the full host from the base URL (via the URL class), ensuring reliable and correct WebSocket connections especially for complex URLs. &lt;/p&gt;

&lt;p&gt;Registration Timeout Added:A 30-second timeout was introduced for socket registration. If the server does not respond within this window, users receive a clear error message and the process exits gracefully. This prevents hanging connections and improves user feedback. &lt;/p&gt;

&lt;p&gt;Enhanced Error Message Extraction:The registration response error handling is now more robust: It intelligently extracts meaningful error messages whether the server responds with a string, an object, or a nested structure. Attempts to parse JSON error details for more informative output. Falls back to stringifying unknown error types, ensuring users always get useful feedback. All error messages are now logged in a consistent, user-friendly format. &lt;/p&gt;

&lt;p&gt;Minor Cleanup:Removed a redundant blank line after the socket connection initiation for improved code readability.   &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/api/src/socket/change-notifier.socker.ts: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1. Improved Error Handling &amp;amp; Feedback The registration process now provides much more detailed error messages to clients. Instead of a generic error or raw message, errors are parsed, logged, and emitted in user-friendly formats. &lt;/p&gt;

&lt;p&gt;2. Custom Authentication Logic for Socket Connections The previous decorator-based guards (@UseGuards(AuthGuard, ApiKeyGuard) and @RequiredApiKeyAuthorities) have been replaced by custom methods. New methods (extractAndValidateUser and convertToAuthenticatedUser) manually handle authentication and authority checks, mimicking guard behavior but allowing for more granular error handling and feedback. &lt;/p&gt;

&lt;p&gt;3. API Key Authority Checks The code now checks if the API key has the required authorities (READ_WORKSPACE, READ_PROJECT, and READ_ENVIRONMENT) directly within the socket handler. If the user has ADMIN authority, individual checks are bypassed. &lt;/p&gt;

&lt;p&gt;4. Enhanced Logging Connection logs now include the presence or absence of authentication headers. Errors during registration are logged with more context, including error types and constructors. &lt;/p&gt;

&lt;p&gt;5. Dependency Injection Updates The SlugGenerator service is now injected into the class, preparing for potential future use or slug-related operations. &lt;/p&gt;

&lt;p&gt;6. Cleaned-Up Imports Removed unused decorators and guards, reflecting the shift to manual authentication and authority verification. &lt;/p&gt;

&lt;p&gt;7. User Context Construction The code now constructs a detailed user context object for socket connections, including IP address, workspace, and API key authorities, improving downstream authorization and personalization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the solution
&lt;/h3&gt;

&lt;p&gt;While testing Keyshade, I encountered an issue that was easy to reproduce: create a project in Keyshade, configure your CLI to connect to it, delete the project, and then run the keyshade run &amp;lt;&amp;gt; command. This sequence would trigger an unclear error message, leaving the cause ambiguous. The expected behavior was for the CLI to clearly display the actual problem, with the API sending a properly formatted error message that the CLI would then print for the user. After applying the solution, the CLI behaved as intended, providing a clear and informative error message, making the debugging process much smoother.&lt;/p&gt;

&lt;p&gt;Another testing approach involved building custom WebSocket test clients designed to send invalid authentication data, deliberately triggering error conditions to assess system resilience. We closely monitored server-side logs to ensure errors were correctly detected and handled, while also verifying that the client could parse various error message formats. This end-to-end validation—from CLI input, through WebSocket communication and API processing, to the final CLI response—confirmed the integrity and reliability of the entire flow. This comprehensive process not only confirmed the integrity and reliability of the entire system but also successfully closed issue #998 with our &lt;a href="https://github.com/keyshade-xyz/keyshade/pull/1087" rel="noopener noreferrer"&gt;PR #1087&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We resolved a complex WebSocket bug by fixing authentication handling, type safety, and error messaging across the backend and CLI. They used systematic debugging, targeted fixes to three core components, and custom test clients to replace vague errors with clear feedback, improve authentication timeouts, and update integration docs—showcasing technical excellence, thorough testing, and a user-focused, collaborative approach.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devbugsmash</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>Product sense - Intro to Keyshade</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 12 Jul 2025 02:42:42 +0000</pubDate>
      <link>https://forem.com/jds64/product-sense-intro-to-keyshade-707</link>
      <guid>https://forem.com/jds64/product-sense-intro-to-keyshade-707</guid>
      <description>&lt;p&gt;Product sense is the intuitive understanding of what makes a product successful—the ability to identify user needs, spot market gaps, and build solutions that people actually want to use. It's the difference between building features and building the right features.&lt;/p&gt;

&lt;p&gt;At its core, product sense combines three critical elements: deep empathy for users, keen awareness of market dynamics, and the judgment to prioritize what matters most. It's what separates products that solve real problems from those that collect digital dust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Anatomy of Strong Product Sense
&lt;/h2&gt;

&lt;p&gt;Product sense isn't just about having good ideas—it's about having the right ideas at the right time. It manifests in several ways:&lt;br&gt;
User-Centric Thinking: Understanding not just what users say they want, but what they actually need. This means digging beneath surface-level requests to uncover underlying pain points.&lt;/p&gt;

&lt;p&gt;Market Awareness: Recognizing where opportunities exist in the competitive landscape and how user behavior is evolving.&lt;br&gt;
Execution Wisdom: Knowing which features to build first, how to sequence development, and when to pivot based on feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyshade: Product Sense in Action
&lt;/h2&gt;

&lt;p&gt;Keyshade exemplifies strong product sense by addressing a fundamental yet often overlooked developer pain point: secure environment variable management. While many developers resort to scattered .env files or basic cloud solutions, Keyshade's creators recognized that teams needed something more robust yet accessible.&lt;/p&gt;

&lt;p&gt;The product sense behind Keyshade reveals itself in several key decisions:&lt;br&gt;
Solving a Real Problem: Rather than building another generic developer tool, Keyshade targets the specific friction developers face when managing secrets across environments. This isn't a nice-to-have—it's a daily necessity that most teams handle poorly.&lt;br&gt;
Open Source Strategy: By making Keyshade open source, the team demonstrates understanding of developer culture and trust requirements. When it comes to handling sensitive data, transparency isn't just appreciated—it's essential.&lt;br&gt;
Developer-First Design: The focus on seamless integration and straightforward workflows shows awareness of how developers actually work. Complex security tools often go unused because they create more friction than they solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Product Builders
&lt;/h2&gt;

&lt;p&gt;Keyshade's approach illustrates how product sense translates into tangible decisions. Instead of building a comprehensive DevOps platform (which would be feature-rich but unfocused), they identified one specific workflow that teams consistently struggle with and built a targeted solution.&lt;br&gt;
This focused approach is classic product sense—recognizing that doing one thing exceptionally well often beats doing many things adequately. It's the difference between building what's technically possible and building what's strategically valuable.&lt;br&gt;
The lesson for product builders is clear: strong product sense isn't about having all the answers upfront. It's about asking the right questions, staying close to user problems, and having the discipline to build solutions that matter rather than solutions that impress.&lt;/p&gt;

&lt;p&gt;Product sense develops through experience, but it starts with genuine curiosity about user problems. Tools like Keyshade succeed because they're built by people who understand both the technical challenges and the human workflows they're trying to improve.&lt;/p&gt;

</description>
      <category>security</category>
      <category>opensource</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Mon, 23 Jun 2025 23:22:28 +0000</pubDate>
      <link>https://forem.com/jds64/-33oh</link>
      <guid>https://forem.com/jds64/-33oh</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/ben" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1%2Ff451a206-11c8-4e3d-8936-143d0a7e65bb.png" alt="ben"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ben/meme-monday-jg8" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Meme Monday&lt;/h2&gt;
      &lt;h3&gt;Ben Halpern ・ Jun 23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#discuss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#jokes&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#watercooler&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>discuss</category>
      <category>jokes</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Level Up Your Linux Skills</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Mon, 23 Jun 2025 23:17:19 +0000</pubDate>
      <link>https://forem.com/jds64/level-up-your-linux-skills-301e</link>
      <guid>https://forem.com/jds64/level-up-your-linux-skills-301e</guid>
      <description>&lt;h2&gt;
  
  
  Deep Dive into OverTheWire Bandit
&lt;/h2&gt;

&lt;p&gt;“So many books, so little time.” - &lt;strong&gt;Frank Zappa&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;How a gamified approach to cybersecurity education transforms learning from tedious to thrilling&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today’s fast-paced digital world, cybersecurity skills are no longer optional — they’re essential. But learning them through static lessons, long-winded lectures, or dry textbooks? That often leads to burnout or boredom.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;OverTheWire Bandit&lt;/strong&gt; comes in — a brilliant learning platform that transforms traditional Linux security training into a hands-on, puzzle-based game. It’s not just engaging — it’s effective, because it teaches you by doing.&lt;/p&gt;

&lt;p&gt;I started playing Bandit right after finishing a web development class, where I had learned how to navigate files and search through directories using Linux. Jumping into this wargame felt like leveling up — taking those foundational skills and applying them in a way that was both fun and deeply practical.&lt;/p&gt;

&lt;p&gt;Unlike passive learning platforms, Bandit drops you straight into a live Linux environment. Every command has consequences. Every file might contain a hidden clue. Every level challenges you to solve real problems with real tools — just like in the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes Bandit Special?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Progressive Learning Model
&lt;/h3&gt;

&lt;p&gt;Bandit follows a carefully crafted progression that mirrors real-world security scenarios. Each level builds upon the previous one, introducing new concepts while reinforcing established skills. This isn't just random command execution – it's a structured journey through the fundamentals of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File system navigation and permissions&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Text processing and pattern matching&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Network protocols and services&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cryptography and encoding&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Process management and privilege escalation&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version control systems&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real Environment, Real Skills
&lt;/h3&gt;

&lt;p&gt;What sets Bandit apart from simulated environments is its authenticity. You're working with actual Linux systems, real SSH connections, and genuine security tools. The skills you develop aren't theoretical – they're immediately applicable to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System administration tasks&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security auditing and penetration testing&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Digital forensics investigations&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DevOps and automation workflows&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Highlights: Key Learning Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File System Mastery
&lt;/h3&gt;

&lt;p&gt;Early levels focus on fundamental file operations, but with security-minded twists. You'll encounter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Working with special characters in filenames&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ./-

&lt;span class="c"&gt;# Handling spaces in filenames&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"spaces in this filename"&lt;/span&gt;

&lt;span class="c"&gt;# Finding hidden files and understanding permissions&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;".*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These aren't just command exercises – they simulate real scenarios where attackers hide malicious files or administrators need to locate specific system files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Text Processing
&lt;/h3&gt;

&lt;p&gt;As you progress, Bandit introduces sophisticated text manipulation techniques essential for log analysis and data extraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pattern matching for specific data&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"pattern"&lt;/span&gt; large_file.txt

&lt;span class="c"&gt;# Sorting and finding unique entries&lt;/span&gt;
&lt;span class="nb"&gt;sort &lt;/span&gt;data.txt | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;

&lt;span class="c"&gt;# Working with binary data&lt;/span&gt;
strings binary_file | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"readable_text"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cryptography in Practice
&lt;/h3&gt;

&lt;p&gt;Rather than abstract mathematical concepts, Bandit presents cryptography through practical applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Base64 encoding/decoding&lt;/strong&gt; for data transmission&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ROT13 cipher&lt;/strong&gt; for basic obfuscation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File compression and decompression&lt;/strong&gt; chains&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSL/TLS communication&lt;/strong&gt; with live services&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network Security Fundamentals
&lt;/h3&gt;

&lt;p&gt;Advanced levels introduce network concepts that security professionals use daily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Port scanning and service identification&lt;/span&gt;
nmap &lt;span class="nt"&gt;-p&lt;/span&gt; port_range target

&lt;span class="c"&gt;# Network communication&lt;/span&gt;
nc &lt;span class="o"&gt;(&lt;/span&gt;netcat&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;various protocols

&lt;span class="c"&gt;# SSL/TLS client connections&lt;/span&gt;
openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; host:port
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Learning Psychology Behind Gamification
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Immediate Feedback Loop
&lt;/h3&gt;

&lt;p&gt;Each level provides instant validation. Success grants access to the next challenge, while failure requires problem-solving and research. This tight feedback loop maintains engagement and builds confidence progressively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem-Based Learning
&lt;/h3&gt;

&lt;p&gt;Instead of memorizing commands, you're solving authentic problems. Need to find a file with specific properties? You'll learn &lt;code&gt;find&lt;/code&gt; command naturally. Need to analyze network traffic? &lt;code&gt;netstat&lt;/code&gt; and &lt;code&gt;nmap&lt;/code&gt; become tools, not just commands to memorize.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community and Collaboration
&lt;/h3&gt;

&lt;p&gt;The OverTheWire &lt;a href="https://discord.gg/CPDYM3G" rel="noopener noreferrer"&gt;community&lt;/a&gt; fosters collaborative learning. Forums, IRC channels, and documentation encourage discussion without spoiling solutions, creating an environment where learners help each other grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For Aspiring Security Professionals
&lt;/h3&gt;

&lt;p&gt;Bandit provides foundational skills for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Penetration testing&lt;/strong&gt; methodologies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Incident response&lt;/strong&gt; procedures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Digital forensics&lt;/strong&gt; investigations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security operations center (SOC)&lt;/strong&gt; work&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For System Administrators
&lt;/h3&gt;

&lt;p&gt;The challenges develop crucial administrative skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log analysis&lt;/strong&gt; and troubleshooting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service configuration&lt;/strong&gt; and management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation scripting&lt;/strong&gt; capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security hardening&lt;/strong&gt; techniques&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Developers
&lt;/h3&gt;

&lt;p&gt;Modern development requires security awareness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure coding&lt;/strong&gt; practices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DevSecOps&lt;/strong&gt; integration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Container security&lt;/strong&gt; fundamentals&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure as code&lt;/strong&gt; security&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Concepts and Progression
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Privilege Escalation
&lt;/h3&gt;

&lt;p&gt;Later levels introduce sophisticated privilege escalation techniques, teaching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUID/SGID&lt;/strong&gt; binary exploitation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cron job&lt;/strong&gt; manipulation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service account&lt;/strong&gt; abuse&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment variable&lt;/strong&gt; exploitation&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Version Control Security
&lt;/h3&gt;

&lt;p&gt;Git-based challenges demonstrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Repository forensics&lt;/strong&gt; for sensitive data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Branch and tag analysis&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commit history&lt;/strong&gt; investigation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remote repository&lt;/strong&gt; interaction&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building Your Learning Path
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Getting Started Strategy
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set up your environment&lt;/strong&gt; with proper SSH clients and tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document your progress&lt;/strong&gt; – maintain notes on techniques learned&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Join the community&lt;/strong&gt; for support and additional resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Practice consistently&lt;/strong&gt; – regular engagement builds muscle memory&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Advanced Techniques
&lt;/h3&gt;

&lt;p&gt;As you progress, develop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation scripts&lt;/strong&gt; for repetitive tasks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom tools&lt;/strong&gt; for specific challenges&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deep diving&lt;/strong&gt; into manual pages and documentation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-referencing&lt;/strong&gt; with real-world security frameworks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Technical Foundation for Cybersecurity Careers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Industry Relevance
&lt;/h3&gt;

&lt;p&gt;The skills developed through Bandit directly align with industry certifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CompTIA Security+&lt;/strong&gt; foundational knowledge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CEH (Certified Ethical Hacker)&lt;/strong&gt; practical skills&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OSCP (Offensive Security Certified Professional)&lt;/strong&gt; methodology&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CISSP&lt;/strong&gt; security management concepts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Portfolio Development
&lt;/h3&gt;

&lt;p&gt;Completing Bandit demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-directed learning&lt;/strong&gt; capability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Problem-solving&lt;/strong&gt; methodology&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical documentation&lt;/strong&gt; skills&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persistence&lt;/strong&gt; and attention to detail&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: More Than Just a Game
&lt;/h2&gt;

&lt;p&gt;OverTheWire Bandit represents a paradigm shift in technical education. By combining gamification with authentic security challenges, it creates an engaging learning environment that builds genuine, applicable skills.&lt;/p&gt;

&lt;p&gt;The platform's genius lies not just in its technical content, but in its understanding of how people learn best – through doing, failing, researching, and ultimately succeeding. Each level completed isn't just a game achievement; it's a step toward genuine cybersecurity competence.&lt;/p&gt;

&lt;p&gt;Whether you're starting your security journey or looking to sharpen existing skills, Bandit offers a structured, challenging, and ultimately rewarding path to technical mastery. The investment in time and effort pays dividends in real-world capability and career advancement.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ready to begin your journey? The terminal is waiting, and the first challenge is just an SSH connection away.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://overthewire.org/wargames/bandit/bandit0.html" rel="noopener noreferrer"&gt;OverTheWire Bandit&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Always approach learning platforms like OverTheWire with respect for their educational mission. Share knowledge and techniques, but avoid sharing specific solutions that might diminish the learning experience for others.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I suggest having a notepad ready!&lt;/em&gt; Whether it’s a physical notebook or a digital document, tracking your commands, mistakes, and lessons learned helps reinforce your understanding and gives you something to reference later.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>linux</category>
      <category>beginners</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 29 Mar 2025 05:28:39 +0000</pubDate>
      <link>https://forem.com/jds64/-3pl0</link>
      <guid>https://forem.com/jds64/-3pl0</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/devteam/join-our-first-ever-wecoded-challenge-celebrating-underrepresented-voices-in-tech-through-stories-5m5" class="crayons-story__hidden-navigation-link"&gt;Join Our First-Ever WeCoded Challenge – Celebrating Underrepresented Voices in Tech Through Stories &amp;amp; Code!&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/devteam"&gt;
            &lt;img alt="The DEV Team logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1%2Fd908a186-5651-4a5a-9f76-15200bc6801f.jpg" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jess" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264%2Fb75f6edf-df7b-406e-a56b-43facafb352c.jpg" alt="jess profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jess" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jess Lee
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jess Lee
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-2309869" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jess" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264%2Fb75f6edf-df7b-406e-a56b-43facafb352c.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jess Lee&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/devteam" class="crayons-story__secondary fw-medium"&gt;The DEV Team&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/devteam/join-our-first-ever-wecoded-challenge-celebrating-underrepresented-voices-in-tech-through-stories-5m5" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 5 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/devteam/join-our-first-ever-wecoded-challenge-celebrating-underrepresented-voices-in-tech-through-stories-5m5" id="article-link-2309869"&gt;
          Join Our First-Ever WeCoded Challenge – Celebrating Underrepresented Voices in Tech Through Stories &amp;amp; Code!
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/wecoded"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;wecoded&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dei"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dei&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/career"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;career&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/devteam/join-our-first-ever-wecoded-challenge-celebrating-underrepresented-voices-in-tech-through-stories-5m5" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;165&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/devteam/join-our-first-ever-wecoded-challenge-celebrating-underrepresented-voices-in-tech-through-stories-5m5#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              29&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>wecoded</category>
      <category>dei</category>
      <category>career</category>
    </item>
    <item>
      <title>Mastering Git Configuration: Essential Settings for an Efficient Workflow</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 29 Mar 2025 05:22:57 +0000</pubDate>
      <link>https://forem.com/jds64/mastering-git-configuration-essential-settings-for-an-efficient-workflow-2m5d</link>
      <guid>https://forem.com/jds64/mastering-git-configuration-essential-settings-for-an-efficient-workflow-2m5d</guid>
      <description>&lt;h2&gt;
  
  
  Thorough Exploration of Git Configuration Options
&lt;/h2&gt;




&lt;p&gt;“Every configuration of people is an entirely new universe unto itself.”&lt;br&gt;&lt;br&gt;
― &lt;strong&gt;Kristin Cashore&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Git is the backbone of modern software development, but its default configuration isn't always optimal for everyone. Customizing your Git configuration can significantly improve your workflow efficiency and help avoid common mistakes. In this guide, I'll walk you through essential Git configuration settings used by experienced developers, including Git core maintainers themselves.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding Git Config Levels
&lt;/h2&gt;

&lt;p&gt;Git configurations exist at three levels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System-wide&lt;/strong&gt; (&lt;code&gt;/etc/gitconfig&lt;/code&gt;): Applied to every user on the system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global&lt;/strong&gt; (&lt;code&gt;~/.gitconfig&lt;/code&gt; or &lt;code&gt;~/.config/git/config&lt;/code&gt;): Applied to all your repositories&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local&lt;/strong&gt; (&lt;code&gt;.git/config&lt;/code&gt; in each repository): Repository-specific settings&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each level overrides the previous one, giving you flexibility in how you apply configurations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Essential User Identity Settings
&lt;/h2&gt;

&lt;p&gt;Let's start with the basics. Your identity in Git is crucial for collaboration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Your Name"&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"your.email@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pro tip: You can set different identities for work and personal projects using conditional includes based on repository location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In ~/.gitconfig&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;includeIf &lt;span class="s2"&gt;"gitdir:~/work/"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    path &lt;span class="o"&gt;=&lt;/span&gt; ~/.gitconfig-work
&lt;span class="o"&gt;[&lt;/span&gt;includeIf &lt;span class="s2"&gt;"gitdir:~/personal/"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    path &lt;span class="o"&gt;=&lt;/span&gt; ~/.gitconfig-personal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enhancing Usability with Aliases
&lt;/h2&gt;

&lt;p&gt;Git aliases save time by shortening common commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.co checkout
git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.br branch
git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.ci commit
git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.st status
git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.last &lt;span class="s1"&gt;'log -1 HEAD'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git core developers often use more complex aliases for powerful workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.logline &lt;span class="s2"&gt;"log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&amp;gt;%Creset' --abbrev-commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Preventing Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Some settings can save you from frustrating errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Avoid pushing to wrong remote branch&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; push.default simple

&lt;span class="c"&gt;# Require explicit branch name when creating branches&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; push.autoSetupRemote &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many Git core developers recommend this safety setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Warn before pushing to multiple remotes&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; push.recurseSubmodules check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Editor and Diff Tool Configuration
&lt;/h2&gt;

&lt;p&gt;Configure your preferred editor for commit messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.editor &lt;span class="s2"&gt;"code --wait"&lt;/span&gt;  &lt;span class="c"&gt;# For VS Code&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.editor &lt;span class="s2"&gt;"vim"&lt;/span&gt;  &lt;span class="c"&gt;# For Vim&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Improve diff readability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; diff.colorMoved zebra
git config &lt;span class="nt"&gt;--global&lt;/span&gt; diff.algorithm patience
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Merge and Rebase Preferences
&lt;/h2&gt;

&lt;p&gt;Customize your merge strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a backup file (.orig) when conflicts occur&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; merge.keepBackup &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Auto-stash before rebasing&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; rebase.autoStash &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git core developers often use this to maintain clean history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable fast-forward only merges by default&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; merge.ff only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Color and UI Enhancements
&lt;/h2&gt;

&lt;p&gt;Make Git output more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; color.ui auto
git config &lt;span class="nt"&gt;--global&lt;/span&gt; color.status auto
git config &lt;span class="nt"&gt;--global&lt;/span&gt; color.branch auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Productivity Settings
&lt;/h2&gt;

&lt;p&gt;These settings are favorites among Git power users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remember conflict resolutions for future merges&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; rerere.enabled &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Set global gitignore file&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.excludesFile ~/.gitignore_global
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An often-overlooked setting praised by Git core developers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Automatically prune remote-tracking branches during fetch/pull&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; fetch.prune &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Your Personalized Config
&lt;/h2&gt;

&lt;p&gt;The best configuration is one that matches your workflow. Start with these essentials and gradually add what you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Configure your identity first&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add safety measures to prevent mistakes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up time-saving aliases for commands you use often&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customize merge and rebase behavior based on your team's workflow&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember that you can always check your current configuration with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And see where a specific setting is defined with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--show-origin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manual for the git config command could be found by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A well-configured Git setup is like a finely tuned instrument—it helps you work faster and with fewer errors. Take the time to customize your Git configuration, and you'll reap the benefits with every commit.&lt;/p&gt;

&lt;p&gt;Whether you're a Git beginner or experienced developer, these settings provide a solid foundation for an efficient workflow. Start implementing them today, and watch your Git experience transform.&lt;/p&gt;

&lt;p&gt;What's your favorite Git configuration trick? Share in the comments below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>git</category>
      <category>github</category>
      <category>programming</category>
    </item>
    <item>
      <title>Enhancing Asset Visualization in Dagster: A UI Filtering Implementation</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Thu, 27 Feb 2025 19:28:00 +0000</pubDate>
      <link>https://forem.com/jds64/enhancing-asset-visualization-in-dagster-a-ui-filtering-implementation-3p7d</link>
      <guid>https://forem.com/jds64/enhancing-asset-visualization-in-dagster-a-ui-filtering-implementation-3p7d</guid>
      <description>&lt;p&gt;&lt;strong&gt;"The ability to simplify means to eliminate the unnecessary so that the necessary may speak."&lt;/strong&gt; — Hans Hofmann&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Over the past four weeks in February of 2025, I have contributed to Dagster with a team of other two CTI members. Dagster is a powerful data orchestration tool that organizes data from multiple sources. During the first week of this micro-internship, we were introduced to the project and learned about collaborating in open-source development. The tech stack we were given to examine in the issue we were given was Python and Docker. Since I had no experience with Docker, I looked at the official documentation to console on what it is and how it is used in Dagster.&lt;/p&gt;

&lt;p&gt;CTI is &lt;a href="https://computingtalentinitiative.org/" rel="noopener noreferrer"&gt;Computing Talent Initiative&lt;/a&gt; which is a program designed to support and accelerate the careers of students from underrepresented backgrounds in computing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dagster-io/dagster" rel="noopener noreferrer"&gt;Dagster&lt;/a&gt; is an important application for modern data orchestration because it provides a robust and scalable way to develop, test, and deploy data pipelines. Unlike traditional workflow schedulers, Dagster offers a declarative approach to defining data dependencies, ensuring reliability and maintainability. It integrates seamlessly with various data tools, supports modular pipeline development, and enhances observability through built-in monitoring and logging features. By enabling teams to track data lineage, enforce data quality checks, and automate workflows, Dagster helps organizations improve efficiency, reduce errors, and ensure data integrity in complex data engineering processes.&lt;/p&gt;

&lt;p&gt;Dagster is typically used by data engineers, data scientists, and DevOps teams that need to build, manage, and monitor reliable data pipelines. These teams use it to automate workflows, ensure data quality, and track dependencies across complex data systems. For example, a financial services company could use Dagster to orchestrate daily data ingestion from multiple stock market APIs, validate the data for accuracy, and generate real-time reports for analysts, ensuring seamless and error-free data processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Here is how Dagster is used&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Once the product is installed, run it on your machine and then click on assets -&amp;gt; Global asset lineage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on Materialize to run the pipeline of the assets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click View and Run Details&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdm2kpnSmz_f7ww_Ui2Xgksqu5E2ax2Ib0Mx24mGPNcgVZCSjWfvi61vTMzYtUkkOokMyP_6AaC5N8M7-35-l2KXevFUAfLKeuTi1Y0Y5RfoN_0MlTyo3qbb0yENlnEKeRJ0dtPIA%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdm2kpnSmz_f7ww_Ui2Xgksqu5E2ax2Ib0Mx24mGPNcgVZCSjWfvi61vTMzYtUkkOokMyP_6AaC5N8M7-35-l2KXevFUAfLKeuTi1Y0Y5RfoN_0MlTyo3qbb0yENlnEKeRJ0dtPIA%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeXrXSraYTlfg51jfxgKonAUM4eORLF7p1oR9zt5fh7bydoPYpv13f-ktpS9DMvfjgif-iHZFZwmu_cVGwfSDvKodfsxw3mLIVHuA5J2FtAklLzzta1oSYSFdDqT2l7tbc8dJsQ0A%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeXrXSraYTlfg51jfxgKonAUM4eORLF7p1oR9zt5fh7bydoPYpv13f-ktpS9DMvfjgif-iHZFZwmu_cVGwfSDvKodfsxw3mLIVHuA5J2FtAklLzzta1oSYSFdDqT2l7tbc8dJsQ0A%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;This is where you can view asset logs and metadata&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;provide essential information for tracking, managing, and maintaining assets efficiently; like images or a piece of code&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;You can change how the assets are displayed while the program is running by toggling the view buttons on the top left corner&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Dagster has around 3.4k users right now to manage data pipelines!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The issue (#26669)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The issue discusses the need for customizable asset ordering in Dagster's UI, particularly in graphs. Currently, the order of asset kinds (e.g., Python, BigQuery, GCS) is unclear and changes unpredictably when asset properties (such as location) are modified. The user wants to define a consistent order and have more flexibility in customization, including the ability to use custom icons or emojis beyond the existing compute_kind field.&lt;/p&gt;

&lt;p&gt;Link to the issue: &lt;a href="https://github.com/dagster-io/dagster/issues/26669" rel="noopener noreferrer"&gt;https://github.com/dagster-io/dagster/issues/26669&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This issue is important to the Dagster open-source project because it enhances usability and clarity in visualizing data assets. Allowing users to customize the order and representation of asset kinds improves consistency, making data pipelines easier to interpret and manage. This flexibility is especially valuable for teams working with multiple asset types across different regions or services. Addressing this issue would enhance the user experience, making Dagster more adaptable to diverse workflows and increasing its adoption among data engineers.&lt;/p&gt;

&lt;p&gt;I was with two other teammates to tackle the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Files that may support the issue&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The following folders are central to the filtering functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;js_modules/dagster-ui/packages/ui-core/src/ui/Filters&lt;/strong&gt;: This folder contains the necessary code for implementing different filter types within the UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;js_modules/dagster-ui/packages/ui-core/src/ui/BaseFilters&lt;/strong&gt;: Here, the core base filter logic resides, acting as a foundation for all other filtering operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;js_modules/dagster-ui/packages/ui-core/src&lt;/strong&gt;: This broader directory encompasses the various filter components, including those related to emojis and icons, which are key for visualizing the data filtering process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Files for Filtering and Asset Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;useKindFilter.tsx&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This file manages a filter labeled kind, allowing the user to filter based on specific asset types. It is a vital component that ensures users can easily categorize assets based on predefined kinds, streamlining the process of narrowing down the dataset.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#### &lt;strong&gt;useStaticSetFilter.tsx&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Found through React imports, this file is responsible for processing how filters are applied across the UI. It manages the logic that enables users to filter assets according to static sets, ensuring a flexible and efficient filtering system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#### &lt;strong&gt;useStaticSetFilterSorte.oss.tsx&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although this file is invoked within the previous one, it primarily returns null, which suggests it either serves as a placeholder for further functionality or is conditionally used based on certain criteria.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#### &lt;strong&gt;AssetGraphFilterBar.oss.tsx&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AssetGraphFilterBar plays a critical role in the rendering of assets. It integrates the filters and determines how assets are displayed on the user interface, contributing to the visual aspect of the filtering system.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Dagsters Codebase&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When you peek under the hood of Dagster, you'll find a fascinating ecosystem of technologies working in harmony to deliver robust data orchestration. Let's explore the key components that make this powerful platform tick.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Foundation: Core Infrastructure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;At its heart, Dagster relies on a Backend-as-a-Service (BaaS) infrastructure, eliminating the need for manual backend setup. Docker containers ensure consistent deployment across environments, while Vercel handles frontend and serverless applications with ease.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Data Processing Powerhouse&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The data processing capabilities are particularly impressive. Spark and Dask work together to handle distributed computing and scale data science workflows. For analytical queries, DuckDB provides lightning-fast in-memory database operations. When it comes to streaming data, Kafka steps in as the backbone for real-time processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Modern Frontend Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The user interface is built on React, enhanced with Next.js for server-side rendering. Style management is handled through a combination of Sass and Styled Components, providing a flexible and maintainable approach to CSS. For bundling and optimization, Webpack and Rollup ensure efficient delivery of frontend assets.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AI and Machine Learning Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;What sets Dagster apart is its embrace of cutting-edge AI technologies. The platform integrates with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;OpenAI and Anthropic for natural language processing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PyTorch for deep learning capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SciKit Learn for traditional machine learning tasks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hugging Face Hub for access to a vast repository of models and datasets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Monitoring and Analytics&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Reliability is crucial for data orchestration, and Dagster takes this seriously with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Prometheus for metrics collection and analysis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sentry for error tracking and performance monitoring&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PostHog and Mixpanel for user behavior analytics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apache Airflow integration for workflow management&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Developer Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The development experience hasn't been overlooked. Tools like iPython provide an enhanced development shell, while Pytest and Jest ensure code quality through comprehensive testing. For documentation, Docusaurus and Sphinx generate clear, maintainable technical documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Data Visualization and Reporting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Data visualization is powered by a robust stack including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Matplotlib for core plotting capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Seaborn for statistical visualizations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Graphviz for structured data representation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rive for interactive motion graphics&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;API and Communication&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The API layer leverages GraphQL for flexible data fetching, while FastAPI and Flask provide high-performance web frameworks. For handling concurrent requests, aiohttp enables asynchronous communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scientific Computing Foundation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;At its core, Dagster benefits from Python's scientific computing ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;NumPy for numerical operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SciPy for scientific computations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Arrow for precise handling of dates and times&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This comprehensive technology stack allows Dagster to handle complex data orchestration tasks while remaining flexible and maintainable. Whether you're dealing with big data processing, machine learning workflows, or real-time analytics, Dagster's thoughtfully chosen technology stack provides the tools needed for success.&lt;/p&gt;

&lt;p&gt;The beauty of this architecture lies not just in the individual components, but in how they work together to create a seamless experience for data engineers and scientists. As data orchestration needs continue to evolve, Dagster's modern technology stack positions it well for future growth and adaptation.&lt;/p&gt;

&lt;p&gt;Here is a System diagram of the codebase regarding the issue&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdUiex_nt7snUo6KSCBKXqUh9DFcdqu_r-_6OV_pS8gSmBanCF_im1WUkxb-KmUFB7ovDJXH1m3zgCkSkHdCDadAmijZBloW9ySGgutQ1sdgit4dvaXLePACvtaUK3bx0x0FysxRw%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdUiex_nt7snUo6KSCBKXqUh9DFcdqu_r-_6OV_pS8gSmBanCF_im1WUkxb-KmUFB7ovDJXH1m3zgCkSkHdCDadAmijZBloW9ySGgutQ1sdgit4dvaXLePACvtaUK3bx0x0FysxRw%3Fkey%3DJnBqwGm-IdTO1m70XHOKB1uw%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The workflow of how the codebase functions regarding the issue&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;User Interface Layer&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The user starts by interacting with the Asset Graph UI (A)

* They access the filtering functionality through the Asset Graph Filter Bar (B)

* The Kind Filter Component (C) provides the interface for selecting asset types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Filter Logic Layer&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* When a user selects filter criteria, the useKindFilter Hook (D) is triggered

* This hook coordinates with useStaticSetFilter (E) for managing filter states

* Filter Configuration (F) defines how different asset kinds should be displayed and sorted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data Processing Layer&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Asset Kind Sorting (G) handles the prioritization of asset types (like python, bigquery, gcs)

* Asset Metadata Processing (H) processes the raw asset data

* Filter State Management (I) maintains the current state of selected filters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Storage Layer&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Asset Definitions (J) store the core information about each asset

* Asset Metadata Store (K) contains additional information like kinds and compute resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's a specific use case workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user wants to filter assets to show only Python and BigQuery assets:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* They start at the Asset Graph UI (A)

* Click on the filter icon in the Asset Graph Filter Bar (B)

* The Kind Filter Component (C) displays available asset types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;When the user selects "python" and "bigquery":&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* useKindFilter (D) receives these selections

* The hook applies the prioritized sorting defined in the code

* useStaticSetFilter (E) updates the filter state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The Data Processing Layer then:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Sorts the assets according to the prioritized order (G)

* Processes the metadata to match the filter criteria (H)

* Updates the filter state (I)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Finally:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The UI updates to show only the selected asset types

* Custom icons are applied (python shows code\_block icon, bigquery shows graph icon)

* The filtered view maintains the prioritized ordering
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This workflow implements the original issue's custom ordering and visualization requirements, ensuring consistent asset ordering and proper representation of different asset kinds in the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Challenges Overcame&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I first started working with Dagster, I encountered an interesting challenge during the installation process. Despite following the documentation carefully on my Mac M2, including some specific commands for M2 compatibility, I ran into a puzzling error with the assets.py file.&lt;/p&gt;

&lt;p&gt;After pushing my changes to a separate branch and returning to the project a few days later, I was greeted with a DagsterUserCodeLoadError. The error message was clear but cryptic at first glance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;dagster._core.errors.DagsterUserCodeLoadError: Error occurred during the loading of Dagster definitions in&lt;br&gt;executable_path=/workspaces/dagster/venv/bin/python, python_file=quickstart/assets.py, working_directory=/workspaces/dagster&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_grpc/server.py", line 417, in &lt;strong&gt;init&lt;/strong&gt;&lt;br&gt;    self._loaded_repositories: Optional[LoadedRepositories] = LoadedRepositories(&lt;br&gt;                                                              ^^^^^^^^^^^^^^^^^^^&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_grpc/server.py", line 239, in &lt;strong&gt;init&lt;/strong&gt;&lt;br&gt;    with user_code_error_boundary(&lt;br&gt;  File "/usr/local/python/3.12.1/lib/python3.12/contextlib.py", line 158, in &lt;strong&gt;exit&lt;/strong&gt;&lt;br&gt;    self.gen.throw(value)&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_core/errors.py", line 299, in user_code_error_boundary&lt;br&gt;    raise new_error from e&lt;br&gt;The above exception was caused by the following exception:&lt;br&gt;FileNotFoundError: [Errno 2] No such file or directory: 'quickstart/assets.py'&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_core/errors.py", line 289, in user_code_error_boundary&lt;br&gt;    yield&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_grpc/server.py", line 250, in &lt;strong&gt;init&lt;/strong&gt;&lt;br&gt;    loadable_targets = get_loadable_targets(&lt;br&gt;                      ^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_grpc/utils.py", line 41, in get_loadable_targets&lt;br&gt;    else loadable_targets_from_python_file(python_file, working_directory)&lt;br&gt;        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_core/workspace/autodiscovery.py", line 24, in loadable_targets_from_python_file&lt;br&gt;    loaded_module = load_python_file(python_file, working_directory)&lt;br&gt;                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;  File "/workspaces/dagster/venv/lib/python3.12/site-packages/dagster/_core/code_pointer.py", line 73, in load_python_file&lt;br&gt;    os.stat(python_file)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What I did to solve this challenge&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;1. Version Control&lt;/p&gt;

&lt;p&gt;My first instinct was to check if this was a version mismatch issue. I systematically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Uninstalled the current Dagster version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed specifically version 1.8.4&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updated the requirements.txt file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verified the version using Python's import system&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2. File Location Detective Work&lt;/p&gt;

&lt;p&gt;When the version fix didn't solve the issue, I realized it might be a path problem. The error message suggested that Dagster couldn't find assets.py, so I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Used the file finder to check my current directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discovered I was in the wrong folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Attempted to run the command with the correct path: dagster dev -f quickstart/assets.py&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3. Documentation Deep Dive&lt;/p&gt;

&lt;p&gt;Finally, I traced the issue back to a potential documentation unclear point. The docs stated "navigate to your project's root directory," but this needed more specificity. I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reviewed the environment setup steps&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Followed the "getting started" section&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Realized I needed to be in the "dagster-quickstart" directory specifically&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the &lt;a href="https://docs.dagster.io/about/contributing" rel="noopener noreferrer"&gt;Dagster documentation&lt;/a&gt; I consulted for the entirety of this issue, as well as tackling this challenge&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Solution&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The breakthrough came when I used Git's find command to locate the exact path of the assets.py file:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;find /quickstart -name "assets.py"&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Lessons learned&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This experience taught me several valuable lessons about working with Dagster:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Always verify file paths when working with Dagster's file-based configuration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Git commands to help locate files in complex project structures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay close attention to the working directory when running Dagster commands&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep track of Dagster versions to ensure compatibility&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For anyone else setting up Dagster, I recommend double-checking your working directory and using the find command if you encounter similar path-related errors. Sometimes the simplest solutions are the most effective!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Solution of issue #26669 - A Breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The solution has two main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prioritized Asset Ordering&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Implemented a priority system for asset kinds (python, bigquery, gcs)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created a consistent sorting mechanism that maintains order even when asset properties change&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Used React's useMemo hook for performance optimization&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Custom Icon Mapping&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Added a configurable icon mapping system for different asset types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented fallback to default icons for undefined asset kinds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enhanced visual distinction between different asset types&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Technical Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The solution leverages several key technologies from our stack:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;React Components and Hooks&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Used React's useMemo hook for efficient asset kind sorting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented custom hooks for state management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrated with Dagster's existing UI component library&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Styled Components&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Utilized Styled Components for consistent visual styling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented flexible layout using Box component&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintained visual hierarchy through consistent spacing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useKindFilter.tsx file is central to the repositories issue since it handles two critical aspects of the Dagster UI enhancement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Asset Type Filtering&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It's a React custom hook that manages how different types of assets (Python, BigQuery, GCS, etc.) are filtered in the UI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Controls what users see when they want to view specific types of assets in their data pipelines&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Asset Ordering&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This file contains the logic for how assets are sorted and displayed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implements the prioritization system that determines which asset types appear first&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solves the original issue where asset ordering was inconsistent and unpredictable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main issue was that users had no control over how their assets were ordered in the UI, and the ordering would change unexpectedly. By modifying useKindFilter.tsx, we could add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Consistent ordering rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom icons for different asset types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A more predictable filtering experience&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as the "traffic controller" for how assets appear and are organized in Dagster's interface - it's where we define the rules for what shows up where and how it looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pathway to Pull request #26669: Asset Filtering and Metadata System&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The main parts of the tech stack we needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Python, hosts the UI of the assets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React, displays the assets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our team tackled the challenge of enhancing asset filtering and visualization in our data pipeline management system. The solution involved several key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customization of Icons&lt;/strong&gt;: We expanded the icon options in the useKindFilter.tsx file, allowing users to associate custom icons with different asset types. This improvement leverages the @dagster-io/ui-components library, a core part of our tech stack for building intuitive user interfaces.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asset Metadata Enhancement&lt;/strong&gt;: My teammate Brent made significant contributions by introducing a new location field to the asset metadata. This update required modifications to several core Dagster files:  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* python\_modules/dagster/dagster/\_core/assets.py  

* python\_modules/dagster/dagster/\_core/definitions/asset\_out.py  

* python\_modules/dagster/dagster/\_core/definitions/decorators/asset\_decorator.py  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;These changes allow us to specify where an asset is hosted, enhancing our system's ability to track and manage assets across different locations.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filter Optimization&lt;/strong&gt;: We implemented a prioritized sorting system for asset kinds in the useKindFilter hook. This improvement ensures that commonly used asset types like 'python', 'bigquery', and 'gcs' appear at the top of the filter list, improving user experience and efficiency.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with Existing Components&lt;/strong&gt;: Our solution integrates seamlessly with the Asset Catalog component of our system diagram. By enhancing the filtering and metadata capabilities, we've improved how users interact with and visualize assets within the catalog.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To verify the functionality of our solution, we ran a series of tests:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We created a test pipeline to ensure the new icon customizations rendered correctly in the UI.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We manually tested the asset kind filter to confirm that prioritized kinds appeared at the top of the list.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While Brent's changes to the asset metadata weren't fully tested, we plan to create comprehensive unit tests to verify the correct handling of the new location field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We ran the local development version of the app in the Dagster documentation in the section titled “Developing the Dagster webserver/UI”&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a code snippet showcasing the icon customization in useKindFilter.tsx:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;const customIcons: {[key: string]: IconName | string} = {&lt;br&gt;  python: 'code_block',&lt;br&gt;  bigquery: 'graph',&lt;br&gt;  gcs: 'cloud',&lt;br&gt;  bug: 'bug',&lt;br&gt;  calendar: 'calendar'&lt;br&gt;  // More icons can be added here&lt;br&gt;};&lt;br&gt;&lt;br&gt;// Use custom icon or emoji if available, otherwise default to 'compute_kind'&lt;br&gt;const icon = customIcons[value.value] || 'compute_kind';&lt;br&gt;&lt;br&gt;return (&lt;br&gt;  &amp;lt;Box flex={{direction: 'row', gap: 4, alignItems: 'center'}}&amp;gt;&lt;br&gt;    {typeof icon === 'string' ? &amp;lt;span&amp;gt;{icon}&amp;lt;/span&amp;gt; : &amp;lt;Icon name={icon} /&amp;gt;}&lt;br&gt;    &amp;lt;TruncatedTextWithFullTextOnHover tooltipText={value.value} text={value.value} /&amp;gt;&lt;br&gt;  &amp;lt;/Box&amp;gt;&lt;br&gt;);&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This code allows for easy expansion of custom icons for different asset types, improving the visual representation of assets in our system.&lt;/p&gt;

&lt;p&gt;While we haven't submitted a pull request yet, we plan to do so once we've completed thorough testing of all components, especially the new asset metadata features introduced by Brent.&lt;/p&gt;

&lt;p&gt;—--&lt;/p&gt;

&lt;p&gt;To-Do after meeting with our CTI Codeday assigned mentor: Dhiraj Patil&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add customization of icons, be able to customize what icons users can use in icon.tsx&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More icons in useKindFilter.tsx&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run a pipeline to see how the issue functions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a pull request with the work so far with tests&lt;/p&gt;

&lt;p&gt;File I changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;useKindFilter.tsx&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file with what code I changed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;import {Box, Icon, IconName} from '@dagster-io/ui-components';&lt;br&gt;import {useMemo} from 'react';&lt;br&gt;&lt;br&gt;import {COMMON_COLLATOR} from '../../app/Util';&lt;br&gt;import {TruncatedTextWithFullTextOnHover} from '../../nav/getLeftNavItemsForOption';&lt;br&gt;import {StaticBaseConfig, useStaticSetFilter} from '../BaseFilters/useStaticSetFilter';&lt;br&gt;&lt;br&gt;const &lt;strong&gt;emptyArray&lt;/strong&gt;: any[] = [];&lt;br&gt;&lt;br&gt;export const useKindFilter = ({&lt;br&gt;allAssetKinds,&lt;br&gt;kinds,&lt;br&gt;setKinds,&lt;br&gt;}: {&lt;br&gt;&lt;strong&gt;allAssetKinds&lt;/strong&gt;: string[];&lt;br&gt;kinds?: null | string[];&lt;br&gt;setKinds?: null | ((s: string[]) =&amp;gt; void);&lt;br&gt;}) =&amp;gt; {&lt;br&gt;// Sort asset kinds with prioritized kinds first&lt;br&gt;const sortedAssetKinds = useMemo(() =&amp;gt; {&lt;br&gt;  // Define prioritized kinds&lt;br&gt;  const prioritizedKinds = ['python', 'bigquery', 'gcs'];&lt;br&gt;  return [&lt;br&gt;    ...prioritizedKinds,&lt;br&gt;    ...allAssetKinds.filter((kind) =&amp;gt; !prioritizedKinds.includes(kind)).sort((a, b) =&amp;gt; COMMON_COLLATOR.compare(a, b)),&lt;br&gt;  ];&lt;br&gt;}, [allAssetKinds]);&lt;br&gt;&lt;br&gt;return useStaticSetFilter&amp;lt;string&amp;gt;({&lt;br&gt;  ...BaseConfig,&lt;br&gt;  &lt;strong&gt;allValues&lt;/strong&gt;: useMemo(&lt;br&gt;    () =&amp;gt;&lt;br&gt;      sortedAssetKinds.map((value) =&amp;gt; ({&lt;br&gt;        value,&lt;br&gt;        &lt;strong&gt;match&lt;/strong&gt;: [value],&lt;br&gt;      })),&lt;br&gt;    [sortedAssetKinds],&lt;br&gt;  ),&lt;br&gt;  &lt;strong&gt;menuWidth&lt;/strong&gt;: '300px',&lt;br&gt;  &lt;strong&gt;state&lt;/strong&gt;: kinds ?? emptyArray,&lt;br&gt;  &lt;strong&gt;onStateChanged&lt;/strong&gt;: (values) =&amp;gt; {&lt;br&gt;    setKinds?.(Array.from(values));&lt;br&gt;  },&lt;br&gt;  &lt;strong&gt;canSelectAll&lt;/strong&gt;: true,&lt;br&gt;});&lt;br&gt;};&lt;br&gt;&lt;br&gt;export const getStringValue = (value: string) =&amp;gt; value;&lt;br&gt;&lt;br&gt;export const &lt;strong&gt;BaseConfig&lt;/strong&gt;: StaticBaseConfig&amp;lt;string&amp;gt; = {&lt;br&gt;&lt;strong&gt;name&lt;/strong&gt;: 'Kind',&lt;br&gt;&lt;strong&gt;icon&lt;/strong&gt;: 'compute_kind',&lt;br&gt;&lt;strong&gt;renderLabel&lt;/strong&gt;: (value) =&amp;gt; {&lt;br&gt;  // Define custom icons or emojis for specific kinds&lt;br&gt;  const &lt;strong&gt;customIcons&lt;/strong&gt;: {[&lt;strong&gt;key&lt;/strong&gt;: string]: IconName | string} = {&lt;br&gt;&lt;br&gt;    // icons pulled from icon.tsx&lt;br&gt;    &lt;strong&gt;python&lt;/strong&gt;: 'code_block', // Emoji for python&lt;br&gt;    &lt;strong&gt;bigquery&lt;/strong&gt;: 'graph', // Emoji for bigquery&lt;br&gt;    &lt;strong&gt;gcs&lt;/strong&gt;: 'cloud', // Emoji for gcs&lt;br&gt;    &lt;strong&gt;bug&lt;/strong&gt;: 'bug',&lt;br&gt;    &lt;strong&gt;calendar&lt;/strong&gt;: 'calendar'&lt;br&gt;&lt;br&gt;    // Add more custom icons or emojis here&lt;br&gt;  };&lt;br&gt;&lt;br&gt;  // Use custom icon or emoji if available, otherwise default to 'compute_kind'&lt;br&gt;  const icon = customIcons[value.value] || 'compute_kind';&lt;br&gt;&lt;br&gt;  return (&lt;br&gt;    &amp;lt;Box flex={{&lt;strong&gt;direction&lt;/strong&gt;: 'row', &lt;strong&gt;gap&lt;/strong&gt;: 4, &lt;strong&gt;alignItems&lt;/strong&gt;: 'center'}}&amp;gt;&lt;br&gt;      {typeof icon === 'string' ? &amp;lt;span&amp;gt;{icon}&amp;lt;/span&amp;gt; : &amp;lt;Icon name={icon} /&amp;gt;}&lt;br&gt;      &amp;lt;TruncatedTextWithFullTextOnHover tooltipText={value.value} text={value.value} /&amp;gt;&lt;br&gt;    &amp;lt;/Box&amp;gt;&lt;br&gt;  );&lt;br&gt;},&lt;br&gt;getStringValue,&lt;br&gt;&lt;strong&gt;getKey&lt;/strong&gt;: getStringValue,&lt;br&gt;&lt;strong&gt;matchType&lt;/strong&gt;: 'all-of',&lt;br&gt;};&lt;br&gt;&lt;br&gt;export function useAssetKindsForAssets(&lt;br&gt;&lt;strong&gt;assets&lt;/strong&gt;: {definition?: {kinds?: string[] | null} | null}[],&lt;br&gt;): string[] {&lt;br&gt;return useMemo(&lt;br&gt;  () =&amp;gt;&lt;br&gt;    Array.from(new Set(assets.map((a) =&amp;gt; a?.definition?.kinds || []).flat())).sort((a, b) =&amp;gt;&lt;br&gt;      COMMON_COLLATOR.compare(a, b),&lt;br&gt;    ),&lt;br&gt;  [assets],&lt;br&gt;);&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One of my  teammates made a change toward the issue solution&lt;/p&gt;

&lt;p&gt;“I introduced a new location field to the asset metadata to specify where an asset is hosted, I then updated relevant classes and decorators to support the location, I modified three files:&lt;/p&gt;

&lt;p&gt;python_modules/dagster/dagster/_core/assets.py&lt;/p&gt;

&lt;p&gt;python_modules/dagster/dagster/_core/definitions/asset_out.py&lt;/p&gt;

&lt;p&gt;-I included a location parameter to the AssetOut class&lt;br&gt;&lt;br&gt;
-Modified the constructor to handle the location field and ensure it is correctly passed to the asset metadata.&lt;/p&gt;

&lt;p&gt;python_modules/dagster/dagster/_core/definitions/decorators/asset_decorator.py&lt;/p&gt;

&lt;p&gt;-Modified the asset decorator to hand the location parameter&lt;br&gt;&lt;br&gt;
-Made sure that the location is correctly propagated in the asset definition&lt;/p&gt;

&lt;p&gt;Unfortunately, I wasn't able to test these changes for now, I might do so in the following days, I will submit a new pull request if I succeed”&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Throughout this four-week micro-internship, my team and I achieved a lot on the topic given to us in Dagster, even though we could not finish it fully. We learned and applied Python and Docker in our tasks, and even though I had no experience with Docker at first, I soon knew about it through the official documentation that I went through. Collaboration with an open-source community provided invaluable hands-on experience in integration of a wider group of code, debugging, and problem-solving. Our mentor, Dhiraj Patil, acknowledged our development, reaffirming the value of our work. Through this process, my data orchestration expertise further gained strength while both my technical ability and teamwork potential were established well for potential projects in the open-source community.&lt;/p&gt;

&lt;p&gt;Following is the link to our solution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dagster-io/dagster/pull/28007" rel="noopener noreferrer"&gt;https://github.com/dagster-io/dagster/pull/28007&lt;/a&gt;&lt;/p&gt;




</description>
      <category>opensource</category>
      <category>ui</category>
      <category>git</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Mastering Bug Identification Using Git Bisect Techniques</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Fri, 14 Feb 2025 05:36:04 +0000</pubDate>
      <link>https://forem.com/jds64/mastering-bug-identification-using-git-bisect-techniques-59n5</link>
      <guid>https://forem.com/jds64/mastering-bug-identification-using-git-bisect-techniques-59n5</guid>
      <description>&lt;h2&gt;
  
  
  A deep dive into dissecting a line of code
&lt;/h2&gt;

&lt;p&gt;“Beware of bugs in the above code; I have only proved it correct, not tried it.”&lt;br&gt;&lt;br&gt;
― &lt;strong&gt;Donald Knuth&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Through my experience debugging complex codebases and helping teams track down elusive bugs, I've found &lt;code&gt;git bisect&lt;/code&gt; to be an invaluable tool. This guide explores how this powerful command can save developers hours of manual debugging time by using binary search to pinpoint exactly when a bug was introduced.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Git Bisect?
&lt;/h2&gt;

&lt;p&gt;Git bisect is a debugging command that uses &lt;em&gt;binary search&lt;/em&gt; to find the commit that introduced a bug. Instead of manually checking every commit, git bisect helps you identify the problematic commit in a logarithmic number of steps.&lt;/p&gt;
&lt;h2&gt;
  
  
  How Git Bisect Works Under the hood
&lt;/h2&gt;

&lt;p&gt;Git bisect works by traversing Git's internal commit graph structure. Here's what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Git maintains a Directed Acyclic Graph (DAG) of commits&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each commit node contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SHA-1 hash (commit identifier)&lt;/li&gt;
&lt;li&gt;Parent commit reference(s)&lt;/li&gt;
&lt;li&gt;Timestamp&lt;/li&gt;
&lt;li&gt;Author information&lt;/li&gt;
&lt;li&gt;Complete snapshot of the codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you start bisect, Git:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Creates a &lt;code&gt;.git/BISECT_LOG&lt;/code&gt; file to track the bisect session&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stores the following information:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* List of "good" commits

* List of "bad" commits

* Current bisect state

* Reference to the original HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Git uses this binary search algorithm to find the first bad commit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;findFirstBadCommit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldest_good_commit&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newest_bad_commit&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_marks_as_bad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middle&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middle&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;  &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;First&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  But what makes a bad commit?
&lt;/h3&gt;

&lt;p&gt;A "bad" commit in git bisect is entirely determined by YOU, the developer. There's no automatic detection - a commit is "bad" if it exhibits the problem you're trying to track down. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A feature stops working&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A test starts failing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance degrades significantly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UI elements render incorrectly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The security vulnerability is present&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any undesired behavior appears  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Git Bisect Works Over the hood
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Start the bisect process:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect start
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mark the current (broken) state:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect bad
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mark a known good commit:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect good &amp;lt;commit-hash&amp;gt; &lt;span class="c"&gt;# you can find commit hashes using "git log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;G”it will automatically check commits between these points, and you mark each as 'good' or 'bad' until the problematic commit is found:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect good  &lt;span class="c"&gt;# If the current commit works&lt;/span&gt;
git bisect bad   &lt;span class="c"&gt;# If the current commit has the bug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Example
&lt;/h2&gt;

&lt;p&gt;Let's say you have a web application where the login button suddenly stopped working. You know it was working a month ago, but with hundreds of commits since then, finding the exact change that broke it would be like finding a needle in a haystack.&lt;/p&gt;

&lt;p&gt;Here's how git bisect helps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect start
git bisect bad                          &lt;span class="c"&gt;# Current version is broken&lt;/span&gt;
git bisect good release-2024-01-15      &lt;span class="c"&gt;# Last known working version&lt;/span&gt;

&lt;span class="c"&gt;# Git checks out a commit halfway between these points&lt;/span&gt;
&lt;span class="c"&gt;# You test the login button&lt;/span&gt;

git bisect good                         &lt;span class="c"&gt;# If it works&lt;/span&gt;
&lt;span class="c"&gt;# OR&lt;/span&gt;
git bisect bad                          &lt;span class="c"&gt;# If it's broken&lt;/span&gt;

&lt;span class="c"&gt;# Repeat until Git identifies the problem commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a test script&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automate the process with &lt;code&gt;git bisect run ./test-script.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ensures consistent testing across commits&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Keep commits atomic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small, focused commits make bisect more effective&lt;/li&gt;
&lt;li&gt;Easier to identify exactly what change caused the issue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Document the findings&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record the problematic commit and root cause&lt;/li&gt;
&lt;li&gt;Share learnings with the team to prevent similar issues&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Time Efficiency&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binary search is dramatically faster than linear searching&lt;/li&gt;
&lt;li&gt;Find bugs in O(log n) steps instead of O(n)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Precision&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinpoints the exact commit that introduced the bug&lt;/li&gt;
&lt;li&gt;Shows who made the change and why&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Learning Opportunity&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding what caused bugs helps prevent future ones&lt;/li&gt;
&lt;li&gt;Improves team's code quality awareness&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Git bisect transforms bug hunting from a tedious manual process into an efficient, systematic approach. Whether you're dealing with regression bugs, performance issues, or unexpected behavior, git bisect is your detective tool for tracking down when and why things went wrong.&lt;/p&gt;

&lt;p&gt;Useful Bisect Commands to Remember&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;git bisect start              &lt;span class="c"&gt;# Begin the bisect process&lt;/span&gt;
git bisect bad               &lt;span class="c"&gt;# Mark current version as broken&lt;/span&gt;
git bisect good &amp;lt;commit&amp;gt;     &lt;span class="c"&gt;# Mark a known good commit&lt;/span&gt;
git bisect &lt;span class="ss"&gt;reset&lt;/span&gt;            &lt;span class="c"&gt;# End the bisect session&lt;/span&gt;
git bisect run &amp;lt;script&amp;gt;     &lt;span class="c"&gt;# Automate the process&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Want to learn how to create good commits?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-workflow-tips-and-tricks.hashnode.dev/mastering-git-essential-tips-and-tricks-for-clean-code-collaboration" rel="noopener noreferrer"&gt;Git in ~5 minutes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>git</category>
      <category>github</category>
      <category>devbugsmash</category>
    </item>
    <item>
      <title>Learn to Make a Location Tracking App file Using React and Mapbox</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sun, 09 Feb 2025 02:04:49 +0000</pubDate>
      <link>https://forem.com/jds64/learn-to-make-a-location-tracking-app-file-using-react-and-mapbox-2bci</link>
      <guid>https://forem.com/jds64/learn-to-make-a-location-tracking-app-file-using-react-and-mapbox-2bci</guid>
      <description>&lt;h2&gt;
  
  
  Easy guide to developing the map component in a React location tracking app
&lt;/h2&gt;

&lt;p&gt;If you want to see yesterday's challenge: &lt;a href="https://dev.to/jds64/building-a-dynamic-game-leaderboard-modal-with-react-and-tailwind-css-3dna"&gt;Building a leaderboard component&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're going to try the challenge yourself: &lt;a href="https://www.dailyui.co/" rel="noopener noreferrer"&gt;DailyUI&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Today we will create a location tracking app using React and Mapbox. Our application will allow users to share their location with friends and track each other's movements in real time. We will build a user interface using React and utilize Mapbox, a mapping and location cloud platform, for the mapping and geolocation features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Mapbox?
&lt;/h2&gt;

&lt;p&gt;Mapbox is a powerful mapping and location cloud platform that offers a comprehensive suite of tools and services for building custom, interactive maps, location-based applications, and data visualizations. It is an open-source platform designed to be highly customizable and scalable, making it suitable for a wide range of industries, including transportation, logistics, real estate, and social networking.&lt;/p&gt;

&lt;p&gt;now let’s get to building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before getting started, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Node.js installed&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used to run Javascript everywhere&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A &lt;a href="https://account.mapbox.com/auth/signin/?route-to=https%3A%2F%2Fconsole.mapbox.com%2F%3Fauth%3D1" rel="noopener noreferrer"&gt;Mapbox&lt;/a&gt; account and access token&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Terminal to write commands&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Begin by creating a new React project using Create React App:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app location-tracker
&lt;span class="nb"&gt;cd &lt;/span&gt;location-tracker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command uses npx, a package runner tool that comes with Node.js, to execute the create-react-app command. This popular CLI tool generates a new React project with a default configuration and no build configuration required. In this case, location-tracker is the project name. The next line changes the directory to the location-tracker folder where the project will be.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the required dependencies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add react-mapbox-gl mapbox-gl geolocation react-map-gl-geocoder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command installs the required dependencies for building a React application that uses Mapbox and geolocation features. Here's a brief explanation of each package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;react-mapbox-gl&lt;/strong&gt;: A React binding library for Mapbox GL JS, which allows you to create interactive, customizable maps within your React application using WebGL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;mapbox-gl&lt;/strong&gt;: The core Mapbox GL JS library that provides the mapping functionality, including map rendering, interactive map controls, and support for various map sources and styles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;geolocation&lt;/strong&gt;: A package that enables you to retrieve the user's current geolocation coordinates (latitude and longitude) in the browser using the HTML5 Geolocation API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;react-map-gl-geocoder&lt;/strong&gt;: A React component that provides geocoding functionality for Mapbox GL JS maps. It allows you to convert addresses and place names into map coordinates and vice versa, enabling search and location input in your application&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing the Mapbox app
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a Map component in your src directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components/Map.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MapGL&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-mapbox-gl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;geolocate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geolocation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MapGlGeocoder&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-map-gl-geocoder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geocoderRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MapGL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[your_mapbox_access_token]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mapbox://styles/mapbox/streets-v11&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geocoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MapGlGeocoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[your_mapbox_access_token]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;geocoderRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geocoder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Geolocate user&lt;/span&gt;
&lt;span class="nf"&gt;geolocate&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jumpTo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;15.5&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Cleanup&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MapGL&lt;/span&gt;
        &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mapRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;onViewportChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;geocoderRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MapGlGeocoder&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;geocoderRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update your App.js to include the &lt;strong&gt;Map&lt;/strong&gt; component:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Map&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding User Location Sharing and Tracking
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Implement a backend API for user authentication and sharing locations. This will require knowledge of backend development using a technology such as &lt;strong&gt;Node.js, Express.js, and MongoDB&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add user authentication to the React application using libraries like &lt;strong&gt;React Hooks&lt;/strong&gt; for authentication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement features to share and track users' locations on the map by fetching user coordinates from the backend API.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what the entire structure would look like in a &lt;strong&gt;repository&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- public
  - index.html
- src
  - assets
    - logo.svg
    - images
  - components
    - Map.js
    - MapGeocoder.js
    - UserLocationMarker.js
    - LoginForm.js
    - RegistrationForm.js
    - UserProfile.js
  - pages
    - Home.js
    - Login.js
    - Register.js
    - UserProfile.js
  - styles
    - App.css
    - Map.css
  - index.js
  - App.js
  - setUpTests.js
- .gitignore
- package.json
- README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt;: This folder contains the index.html file, which serves as the entry point of the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;src&lt;/strong&gt;: The source code of your application resides here. It contains the following subfolders:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;assets&lt;/strong&gt;: Houses static files like images, logos, and icons.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;components&lt;/strong&gt;: Contains reusable UI components, including Map.js, MapGeocoder.js, UserLocationMarker.js, LoginForm.js, RegistrationForm.js, and UserProfile.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pages&lt;/strong&gt;: Stores top-level React components, such as Home.js, Login.js, Register.js, and UserProfile.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;styles&lt;/strong&gt;: Contains CSS stylesheets for your components, like App.css and Map.css.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Root Files&lt;/strong&gt;: Inside the src folder, you'll find the following important files:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;index.js: The entry point of your application, responsible for rendering the top-level App component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;App.js: The main component that serves as the container for your entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;setUpTests.js: A file for setting up testing environments, if needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Root Files in Project Directory&lt;/strong&gt;: The following files are located in the root directory:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.gitignore: A file specifying which files and directories should be ignored by Git.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;package.json: The main project configuration file for &lt;a href="https://node.js/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; and React applications, containing dependencies, scripts, and metadata.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;README.md: A file providing general information, installation instructions, and usage details for your project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we learned how to create a basic location-tracking application using React and Mapbox. We implemented a map with geolocation capabilities, which is the foundation for user location sharing and tracking. To further enhance the app, consider adding features like search, user markers, and detailed user information. Happy coding!&lt;/p&gt;




&lt;p&gt;Here you just saw only a few files made, here are some notes  &lt;/p&gt;

&lt;p&gt;Creating small files in software development, particularly in a React project, offers several benefits that can improve code maintainability, collaboration, and overall project organization. Here are some reasons why developers may choose to focus on small files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Smaller files help promote modularity in code, making it easier to separate concerns, test, and reuse code. This approach also helps with the Single Responsibility Principle, which suggests that a module or function should have only one responsibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Readability&lt;/strong&gt;: Small files with a specific focus make the codebase more readable and easier to navigate, allowing developers to quickly understand the purpose of each file and its contents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;: In a team setting, smaller files simplify collaboration by enabling multiple developers to work on different components, services, or features simultaneously, with fewer merge conflicts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: While modern development tools like Webpack and &lt;a href="https://rollup.js/" rel="noopener noreferrer"&gt;rollup.js&lt;/a&gt; can efficiently handle large files, splitting the code into smaller chunks can sometimes help with tree-shaking, lazy-loading, and improving initial load times, especially in browser-based applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging and Testing&lt;/strong&gt;: It's easier to debug and test small, focused files compared to large monolithic files. Developers can pinpoint issues faster and ensure that each component or function works as expected, leading to better code quality and fewer bugs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Reusability&lt;/strong&gt;: Small files with specific functionality can be easily reused across a project or even in other projects. This leads to a more maintainable and DRY (Don't Repeat Yourself) codebase.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, focusing on creating small, modular files in a React project can enhance code organization, readability, and maintainability, and improve collaboration among team members.&lt;/p&gt;

</description>
      <category>react</category>
      <category>mapbox</category>
      <category>api</category>
      <category>ui</category>
    </item>
    <item>
      <title>Building a Dynamic Game Leaderboard Modal with React and Tailwind CSS</title>
      <dc:creator>Johnny Santamaria</dc:creator>
      <pubDate>Sat, 08 Feb 2025 23:37:42 +0000</pubDate>
      <link>https://forem.com/jds64/building-a-dynamic-game-leaderboard-modal-with-react-and-tailwind-css-3dna</link>
      <guid>https://forem.com/jds64/building-a-dynamic-game-leaderboard-modal-with-react-and-tailwind-css-3dna</guid>
      <description>&lt;h1&gt;
  
  
  Explore the steps to create a sleek and adaptive leaderboard modal using React and Tailwind CSS.
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;“In a world that’s changing really quickly, the only strategy that is guaranteed to fail is not taking risks.” – &lt;strong&gt;Mark Zuckerberg&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Mark Zuckerberg&lt;/em&gt; is the co-founder and CEO of Facebook, who has seen firsthand how competitive elements in social platforms, including gaming, drive user engagement and innovation. The quote &lt;em&gt;is from an October 2011 interview at&lt;/em&gt; &lt;a href="http://www.cbsnews.com/news/facebooks-mark-zuckerberg-insights-for-entrepreneurs/" rel="noopener noreferrer"&gt;&lt;em&gt;Y Combinator’s Startup School&lt;/em&gt;&lt;/a&gt; &lt;a href="http://www.cbsnews.com/news/facebooks-mark-zuckerberg-insights-for-entrepreneurs/" rel="noopener noreferrer"&gt;&lt;em&gt;in Palo Alto, California.&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you want to see yesterday's challenge: &lt;a href="https://dev.to/jds64/mastering-react-day-17-building-powerful-analytics-charts-2n97"&gt;Analytics in React&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're going to try the challenge yourself: &lt;a href="https://www.dailyui.co/" rel="noopener noreferrer"&gt;DailyUI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I missed a total of two challenges, life happens…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So I came up with a prompt combining the idea of creating a leaderboard with the idea of creating a popup overlay screen&lt;/p&gt;

&lt;p&gt;Prompt: Create a popup of a leaderboard&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it a for a game? politics? movies? How would the overlay be closed?&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;So today, we're designing a game leaderboard popup, combining engaging competitive elements with smooth user interaction. I've created an interactive popup that displays player rankings while maintaining performance and accessibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interface should include:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Animated popup overlay with a backdrop&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Player rankings with scores&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Visual indicators for top positions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Player avatars and status&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smooth transitions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Close button functionality&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsive design&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The solution 💡
&lt;/h2&gt;

&lt;p&gt;Here's the React component that brings together these requirements using &lt;strong&gt;Tailwind CSS&lt;/strong&gt; and &lt;strong&gt;Lucide&lt;/strong&gt; icons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;{/* LeaderBoardPopup.js */}

import React, { useState } from 'react';
import { X, Trophy, Medal } from 'lucide-react';

const LeaderboardPopup = () =&amp;gt; {
  const [isOpen, setIsOpen] = useState(true);

  const leaderboardData = [
    { rank: 1, username: "ProGamer123", score: 25000, wins: 48 },
    { rank: 2, username: "NinjaWarrior", score: 23450, wins: 45 },
    { rank: 3, username: "PixelMaster", score: 22100, wins: 42 },
    { rank: 4, username: "GameKing99", score: 21000, wins: 39 },
    { rank: 5, username: "StarPlayer", score: 20500, wins: 37 }
  ];

  const getMedalColor = (rank) =&amp;gt; { {/* Use CSS to edit the color */}
    switch(rank) {
      case 1: return "text-yellow-500";
      case 2: return "text-gray-400";
      case 3: return "text-amber-600";
      default: return "text-gray-600";
    }
  };

  if (!isOpen) return null;

  return (
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"bg-white rounded-lg shadow-xl w-full max-w-md mx-4 relative overflow-hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {/* Header */}
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"bg-indigo-600 p-4 flex justify-between items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center space-x-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Trophy&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-white"&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;{24}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-bold text-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Top Players&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; 
            &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; setIsOpen(false)}
            className="text-white hover:text-gray-200 transition-colors"
          &amp;gt;
            &lt;span class="nt"&gt;&amp;lt;X&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;{24}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

        {/* Leaderboard Content */}
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"p-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          {leaderboardData.map((player) =&amp;gt; (
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; 
              &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;{player.rank}&lt;/span&gt;
              &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between mb-4 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center space-x-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-center w-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                  {player.rank &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;= 3 ? (
                    &lt;span class="nt"&gt;&amp;lt;Medal&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;{getMedalColor(player.rank)}&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;{24}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                  ) : (
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 font-medium"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{player.rank}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                  )}
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"font-semibold text-gray-800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{player.username}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-sm text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{player.wins} wins&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"font-bold text-indigo-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{player.score.toLocaleString()}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-xs text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;points&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          ))}
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

        {/* Footer */}
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"bg-gray-50 p-4 border-t"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"text-center text-sm text-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Rankings update every hour
          &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  );
};

export default LeaderboardPopup;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: This code looked like HTML didn’t it?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; uses a syntax called &lt;strong&gt;JSX&lt;/strong&gt; (JavaScript XML), which allows you to write HTML-like code within JavaScript. Although it looks like HTML, it's actually a syntactic sugar over JavaScript and isn't pure HTML. JSX is compiled into JavaScript at runtime, where React elements are created.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  To use this component in your application:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;{/* app.js */}

import LeaderboardPopup from './LeaderboardPopup';

function App() {
  return (
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"min-h-screen bg-gray-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;LeaderboardPopup&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the code using &lt;strong&gt;Github codespaces:&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Create a Repository on GitHub&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to GitHub and create a new repository (e.g., &lt;code&gt;leaderboard-app&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize it with a README, or leave it empty.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Open GitHub Codespaces&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once your repository is created, go to the repository’s page on GitHub.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the "Code" button and then select "Open with Codespaces"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on "New codespace" to open a fresh Codespace instance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Set up Your React App in Codespaces&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the terminal within GitHub Codespaces, run the following commands to set up a new React app:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app leaderboard-app
&lt;span class="nb"&gt;cd &lt;/span&gt;leaderboard-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This will create a new React application and navigate into the &lt;code&gt;leaderboard-app&lt;/code&gt; directory&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Install Dependencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install any required dependencies, like &lt;code&gt;lucide-react&lt;/code&gt; for the icons:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;lucide-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Add Your Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the Codespaces editor, go to the &lt;code&gt;src&lt;/code&gt; folder and create a new file called &lt;code&gt;LeaderboardPopup.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste your &lt;code&gt;LeaderboardPopup&lt;/code&gt; component code into this file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;code&gt;src/App.js&lt;/code&gt; and import the &lt;code&gt;LeaderboardPopup&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LeaderboardPopup&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./LeaderboardPopup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, add &lt;code&gt;&amp;lt;LeaderboardPopup /&amp;gt;&lt;/code&gt; within the &lt;code&gt;App&lt;/code&gt; component’s JSX.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;6. &lt;strong&gt;Run Your App&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the Codespaces terminal, start your React development server:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub Codespaces will automatically open a preview window for your app, where you can see the &lt;code&gt;LeaderboardPopup&lt;/code&gt; in action.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;: Make sure all necessary dependencies (like &lt;code&gt;lucide-react&lt;/code&gt;) are installed in the Codespace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React app initialization&lt;/strong&gt;: By running &lt;code&gt;npx create-react-app leaderboard-app&lt;/code&gt;, you're initializing a new React app, so ensure the folder structure is correct (the app should be created in the &lt;code&gt;leaderboard-app&lt;/code&gt; directory).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preview&lt;/strong&gt;: GitHub Codespaces automatically sets up a preview for your React app, so you'll be able to see your changes live.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6xct4k3suazv6t6cxy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6xct4k3suazv6t6cxy2.png" alt="Daily UI day 16 and 19" width="800" height="663"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The component leverages several key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Tailwind CSS for responsive and modern styling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lucide icons for consistent visual elements&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React hooks for state management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modal overlay for focused user attention&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsive design that works on all devices&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key features implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clean, modern interface with a clear, visual hierarchy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Medal indicators for the top 3 players&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Score and win statistics display&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interactive close functionality&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hover states for enhanced user feedback&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistent spacing and typography&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsive layout that adapts to screen size&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enhance this component further, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adding entrance/exit animations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing sorting options&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Including player avatars&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding filtering capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supporting real-time updates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Including player progression tracking&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building an effective game leaderboard requires balancing visual appeal with functionality. This implementation demonstrates how modern React features and Tailwind CSS can be combined to create an engaging and responsive leaderboard interface. The modal approach ensures focused attention on the rankings while maintaining accessibility and user experience.&lt;/p&gt;

&lt;p&gt;For future development, this approach offers several advantages. The component structure allows for easy feature expansion, while Tailwind CSS ensures consistent styling and responsiveness. The clear visual hierarchy helps players quickly understand their standing and encourages healthy competition.&lt;/p&gt;

&lt;p&gt;Remember that a great leaderboard is more than just a list of scores – it's a tool for driving engagement and creating community within your game. This implementation provides the foundation for building an engaging competitive feature that can enhance player retention and satisfaction.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>tailwindcss</category>
      <category>webdev</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
