Remote Work Tools

Client Project Status Dashboard Setup for Remote Agency Teams

Build a custom dashboard using Node.js, Express, and GitHub/Linear APIs to display real-time project status, active tasks, time tracking, and deliverable links. Alternatively, use Basecamp or Monday.com for out-of-the-box solutions with client visibility settings. This guide shows you how to consolidate scattered Slack, email, and spreadsheet updates into a single source of truth for distributed agency teams.

Core Requirements for Remote Agency Dashboards

Before selecting tools or writing code, define the essential features your dashboard must provide:

Remote teams need dashboards that update automatically. Manual updates quickly become outdated and create additional overhead that defeats the purpose of consolidation.

Building a Custom Dashboard with Existing Tools

Rather than purchasing expensive enterprise solutions, many agencies construct dashboards from APIs they already use. Here’s a practical implementation using Node.js, Express, and the GitHub API.

Project Structure

project-status-dashboard/
├── server.js
├── package.json
├── public/
│   ├── index.html
│   ├── styles.css
│   └── script.js
└── .env

Backend Server Setup

Create a server that aggregates data from your existing tools:

// server.js
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const app = express();

const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const ORGANIZATION = 'your-agency-org';

async function getProjectData() {
  const [issues, prs, deployments] = await Promise.all([
    axios.get(`https://api.github.com/repos/${ORGANIZATION}/client-project/issues?state=open`, {
      headers: { Authorization: `token ${GITHUB_TOKEN}` }
    }),
    axios.get(`https://api.github.com/repos/${ORGANIZATION}/client-project/pulls?state=open`, {
      headers: { Authorization: `token ${GITHUB_TOKEN}` }
    }),
    // Add more API calls for other services
  ]);

  return {
    issues: issues.data,
    pullRequests: prs.data,
    lastUpdated: new Date().toISOString()
  };
}

app.get('/api/status', async (req, res) => {
  try {
    const data = await getProjectData();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.use(express.static('public'));
app.listen(3000, () => console.log('Dashboard running on port 3000'));

Frontend Display

// public/script.js
async function loadDashboard() {
  const response = await fetch('/api/status');
  const data = await response.json();

  document.getElementById('issue-count').textContent = data.issues.length;
  document.getElementById('pr-count').textContent = data.pullRequests.length;
  document.getElementById('last-updated').textContent =
    new Date(data.lastUpdated).toLocaleString();

  const issueList = document.getElementById('issues-list');
  data.issues.forEach(issue => {
    const li = document.createElement('li');
    li.textContent = `#${issue.number}: ${issue.title}`;
    issueList.appendChild(li);
  });
}

setInterval(loadDashboard, 60000); // Refresh every minute
loadDashboard();

This minimal example demonstrates the core pattern: aggregate data from your existing tools into a unified view.

Integrating Project Management Platforms

If your agency uses tools like Linear, Jira, or Notion, use their APIs to pull project data into a central dashboard. Many teams use n8n or Zapier to create no-code integrations that push updates to a dashboard without custom development.

For Notion databases, the integration pattern looks like this:

const { Client } = require('@notionhq/client');
const notion = new Client({ auth: process.env.NOTION_KEY });

async function getProjectStatus(databaseId) {
  const response = await notion.databases.query({
    database_id: databaseId,
    filter: {
      property: 'Status',
      status: { does_not_equal: 'Done' }
    }
  });

  return response.results.map(page => ({
    title: page.properties.Name.title[0]?.plain_text,
    status: page.properties.Status.status.name,
    owner: page.properties.Assign.people[0]?.name
  }));
}

No-Code and Low-Code Dashboard Alternatives

Not every agency has the bandwidth for custom development. Several platforms offer substantial project visibility out of the box with minimal configuration.

Monday.com provides client-facing views through its “guest” user model. You can configure boards that show only deliverable status and milestone dates without exposing internal conversations, time logs, or budget data. The automation rules (if status changes to “Review”, notify client via email) reduce the manual overhead of status updates. Pricing is per seat but guest users are typically free or discounted.

Basecamp takes a different approach with its clientside feature. You create a dedicated client area within a project where you selectively share messages, files, and to-dos. The client never sees internal discussions. The limitation is that it requires manual curation of what goes into the client area, which creates some overhead.

Notion works well when your agency already uses it for documentation. A public Notion page linked to an internal database can serve as a lightweight client-facing status board. The challenge is that Notion’s permission model is coarser than dedicated project tools, so you need to be careful about what data is connected to the public page.

Linear has a recently added “project updates” feature that generates shareable status pages. If your engineering team already uses Linear for issue tracking, this is the lowest-friction path to a client-facing view — the data is already there, and you just enable sharing.

Remote Team Patterns for Dashboard Success

The technology choice matters less than the team habits you build around it. Here are the patterns that separate agencies with effective dashboards from those where dashboards go stale.

Automate status changes wherever possible. Every manual status update is a cognitive tax on your team. When a PR is merged, the associated task should automatically move to “In Review” or “Done.” When a deployment succeeds, the milestone should update. Invest time in the automation configuration upfront and the dashboard stays current without effort.

Define ownership for the dashboard. In distributed agencies, nobody owns the dashboard by default, which means nobody maintains it. Assign a rotating “dashboard DRI” (directly responsible individual) each sprint. That person is accountable for ensuring integrations are working and stale data gets cleaned up.

Use the dashboard in client calls. If your dashboard exists but you never reference it during client calls, it signals that you don’t trust it either. Open the dashboard at the start of each client review call and walk through it together. This forces you to keep it accurate and shows clients the transparency they are paying for.

Set expectations about refresh frequency. Tell clients explicitly what the dashboard shows and how often it updates. “This dashboard reflects our GitHub state and refreshes every 15 minutes” is much better than letting clients think it is real-time when it is not. Managing expectations prevents the dashboard from becoming a trust issue when data is temporarily stale.

Client-Facing Versus Internal Views

Remote agencies must balance transparency with security. Create separate views for different audiences:

Internal Dashboard: Full access to issues, time logs, internal notes, budget calculations, and team communication.

Client Dashboard: Filtered view showing only deliverables, milestone completion, and scheduled reviews. Use read-only tokens or generate shareable links that expire.

A practical approach uses role-based rendering on the frontend:

function renderDashboard(userRole) {
  if (userRole === 'client') {
    document.getElementById('internal-notes').style.display = 'none';
    document.getElementById('budget-section').style.display = 'none';
  }
  // Load data based on role permissions
}

Deployment Considerations

Host your dashboard where team members can access it reliably. Common options include:

Set up HTTPS through Let’s Encrypt or your hosting provider. Remote teams accessing dashboards from various locations need encrypted connections.

Configure health checks and uptime monitoring. A dashboard that goes offline defeats its purpose — team members will revert to checking email and Slack.

Automating Status Updates

Reduce manual entry by automating status changes:

# .github/workflows/update-dashboard.yml
on:
  pull_request:
    types: [closed]
jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Update project status
        run: |
          curl -X POST $DASHBOARD_WEBHOOK \
          -H "Content-Type: application/json" \
          -d '{"event": "pr_merged", "project": "${{ github.repository }}"}'

Measuring Dashboard Effectiveness

Track whether your dashboard actually improves team workflow:

Iterate based on usage patterns. Remove features nobody uses, and add integrations for tools your team adopts.

Frequently Asked Questions

How much does it cost to build and run a custom dashboard? The compute cost is minimal. A small DigitalOcean or Fly.io instance runs under $10/month. The real cost is developer time for initial setup (typically 4–8 hours) and ongoing maintenance (1–2 hours per month to update integrations when APIs change). If that time cost is a concern, Monday.com or Basecamp’s out-of-the-box options pay for themselves quickly.

How do we handle projects that span multiple repositories or tools? Design the aggregation layer to query multiple sources. Your /api/status endpoint can call GitHub for code-related status, Linear for task status, and a Google Sheet for budget data, then merge the responses before returning them to the frontend. The complexity is manageable as long as each integration is modular — a single failing API call should not crash the entire dashboard.

What if a client wants to see more data than we want to expose? Treat this as a scoping conversation, not a technical problem. Define in your contract what the dashboard shows and what it does not. Clients who want granular time logs or internal notes are really asking for a different kind of engagement. Address that conversation directly rather than building dashboard features that expose more than your team is comfortable with.

How do we keep the dashboard accurate when the team is busy? Accuracy depends almost entirely on automation rather than manual effort. If your team has to remember to update the dashboard, it will go stale within days of a busy sprint. Audit your workflow to identify status changes that happen in your tools (merged PRs, closed tickets, completed deployments) and automate those changes into dashboard updates. The dashboard should be accurate because it reflects tool state, not because someone updated it manually.

Built by theluckystrike — More at zovo.one