Let’s wire one end‑to‑end loop so the whole system is real:

Let’s wire one end‑to‑end loop so the whole system is real:

Create a task in issues-db → automation mirrors it to data-hub → frontend-app shows it.

I’ll define:

• The issue format
• The automation behavior
• The data file shape
• The frontend view

You can implement this exactly as‑is.

1. Record type: `Task`

Repo: issues-db
Representation: each Issue = one Task.

Labels:

• record:task
• status:backlog / status:in-progress / status:done
• priority:high|medium|low (optional)

Issue template (.github/ISSUE_TEMPLATE/task.yml):

name: Task
description: Create a new task record
title: “task: ”
labels: [“record:task”, “status:backlog”]
body:
– type: input
id: summary
attributes:
label: Summary
placeholder: “Short task description”
validations:
required: true
– type: textarea
id: details
attributes:
label: Details
placeholder: “Longer description, context, links”
– type: dropdown
id: priority
attributes:
label: Priority
options:
– high
– medium
– low
default: 1

Every new Task issue is now structured.

2. Automation: mirror tasks into `data-hub`

Goal: whenever a record:task issue is opened/edited/closed in issues-db, backend-automation writes/updates a JSON file in data-hub/data/tasks/.

2.1 `issues-db` → repository_dispatch

We already sketched on-issue.yml. Now specialize it for tasks.

.github/workflows/on-issue.yml in issues-db:

name: Process Issue Records

on:
issues:
types: [opened, edited, closed, labeled, unlabeled]

jobs:
dispatch-task:
if: contains(github.event.issue.labels.*.name, ‘record:task’) runs-on: ubuntu-latest
steps:
– name: Send to backend-automation
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.GH_PAT }}
repository: max-github-system/backend-automation
event-type: task-record
client-payload: |
{
“number”: ${{ github.event.issue.number }},
“action”: “${{ github.event.action }}”,
“title”: “${{ github.event.issue.title }}”,
“state”: “${{ github.event.issue.state }}”,
“labels”: ${{ toJson(github.event.issue.labels) }},
“body”: ${{ toJson(github.event.issue.body) }}
}

GH_PAT = a Personal Access Token with repo access, stored as a secret in issues-db.

2.2 `backend-automation` handles `task-record`

.github/workflows/on-dispatch-task-record.yml:

name: Handle Task Records

on:
repository_dispatch:
types: [task-record]

jobs:
process-task:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4

– uses: actions/setup-node@v4
with:
node-version: 20

– name: Install deps
run: npm ci || true

– name: Process task
env:
PAYLOAD: ${{ toJson(github.event.client_payload) }}
GH_TOKEN: ${{ secrets.GH_PAT }}
run: node scripts/processTaskRecord.mjs

scripts/processTaskRecord.mjs:

import { Octokit } from ‘@octokit/rest’;

const payload = JSON.parse(process.env.PAYLOAD);
const octokit = new Octokit({ auth: process.env.GH_TOKEN });

function extractField(body, id) {
// naive parse: look for “### Summary” style or use JSON block if you prefer return null; // keep simple for now or extend later
}

function mapStatus(labels, state) {
const statusLabel = labels.find(l => l.name.startsWith(‘status:’)); if (statusLabel) return statusLabel.name.replace(‘status:’, ”); return state === ‘closed’ ? ‘done’ : ‘backlog’;
}

async function main() {
const labels = payload.labels || [];
const status = mapStatus(labels, payload.state);

const task = {
id: payload.number,
title: payload.title,
status,
labels: labels.map(l => l.name),
updatedAt: new Date().toISOString()
};

const content = Buffer.from(JSON.stringify(task, null, 2)).toString(‘base64’);

await octokit.repos.createOrUpdateFileContents({
owner: ‘max-github-system’,
repo: ‘data-hub’,
path: `data/tasks/${payload.number}.json`,
message: `chore: sync task #${payload.number}`,
content
});
}

main().catch(err => {
console.error(err);
process.exit(1);
});

Now every Task issue has a mirrored JSON file in data-hub/data/tasks/.

3. Data shape in `data-hub`

Repo: data-hub
Folder: data/tasks/
Example file: data/tasks/42.json

{
“id”: 42,
“title”: “task: build task list view”,
“status”: “backlog”,
“labels”: [
“record:task”,
“status:backlog”,
“priority:medium”
],
“updatedAt”: “2026-02-09T01:23:45.000Z”
}

You can later extend this with summary, details, etc.

4. Frontend: show tasks in `frontend-app`

Goal: at build time, frontend-app pulls all tasks/*.json from data-hub and renders a simple list.

You have two options:

• Static import (if you sync files into the repo)
• Build‑time fetch from GitHub API

I’ll give you the build‑time fetch version—it keeps frontend-app decoupled.

4.1 Add a small fetch script

In frontend-app, create scripts/fetchTasks.mjs:

import { Octokit } from ‘@octokit/rest’;
import fs from ‘fs’;
import path from ‘path’;

const octokit = new Octokit({ auth: process.env.GH_TOKEN });

async function main() {
const { data: files } = await octokit.repos.getContent({
owner: ‘max-github-system’,
repo: ‘data-hub’,
path: ‘data/tasks’
});

const tasks = [];

for (const file of files) {
if (file.type !== ‘file’ || !file.name.endsWith(‘.json’)) continue;

const { data: fileData } = await octokit.repos.getContent({
owner: ‘max-github-system’,
repo: ‘data-hub’,
path: file.path
});

const content = Buffer.from(fileData.content, fileData.encoding).toString(‘utf8’); tasks.push(JSON.parse(content));
}

const outDir = path.join(process.cwd(), ‘src’, ‘generated’); fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(path.join(outDir, ‘tasks.json’), JSON.stringify(tasks, null, 2)); }

main().catch(err => {
console.error(err);
process.exit(1);
});

This script runs at build time, writes src/generated/tasks.json.

4.2 Wire it into the build

Update package.json in frontend-app:

{
“scripts”: {
“prebuild”: “node scripts/fetchTasks.mjs”,
“build”: “vite build”
}
}

In the deploy workflow (deploy.yml), add GH_TOKEN:

– name: Build
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
run: npm run build

4.3 Render tasks in React

Create src/generated/tasks.json (will be auto‑generated after first build).

Create src/Tasks.tsx:

import tasks from ‘./generated/tasks.json’;

type Task = {
id: number;
title: string;
status: string;
labels: string[];
updatedAt: string;
};

export function Tasks() {
const typedTasks = tasks as Task[];

return (

Tasks

  • {typedTasks.map(task => (
  • #{task.id} {task.title} — {task.status}

    ))}

);
}

Use it in src/main.tsx or wherever your root component is:

import React from ‘react’;
import ReactDOM from ‘react-dom/client’;
import { Tasks } from ‘./Tasks’;

ReactDOM.createRoot(document.getElementById(‘root’)!).render(

);

5. What you get with this loop

You now have a closed, GitHub‑only system:

1. Create a Task via Issue in issues-db.
2. issues-db workflow dispatches to backend-automation.
3. backend-automation writes/updates JSON in data-hub.
4. frontend-app build pulls tasks from data-hub.
5. GitHub Pages deploys the updated UI.

No external infra. Everything is GitHub repos, Actions, Issues, Pages, and API.

If you want, next layer is:

• Add status filtering and priority badges in the UI.
• Add AI summaries of tasks via ai-workflows and show them in frontend-app.

Leave a comment