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.