openreachtech/hora-core/hora-spec-backend

Claude Code and agent skill by openreachtech/hora-core

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Stage 4 of /hora-spec. Declare the repositories and servers, then design the data model, the operation list and the background jobs that every stage-1 use case can be walked against. Invoked by /hora-spec, or directly.

Install

npx vskill@latest install openreachtech/hora-core/hora-spec-backend

SKILL.md

hora-spec-backend

Stage 4 of `/hora-spec`. Design what holds the data, what operates on it, and what runs outside the request — and prove, use case by use case, that the result can serve them.

Read ../hora/references/structure.md and ../hora-spec/references/principles.md first. ../hora-spec/references/stages.md is the authority on this stage's exit condition, ../hora/references/spec-format.md on the format of every table written here, and ../hora/references/asking.md on how anything is put to a person.

This stage holds no design rule of its own. How a table is shaped, how an API schema is named, where a job belongs and how a queue is tuned all live in the @openreachtech/hora-skills-ort-* packages. Invoke the skills the delegates table names and read them — never restate one of their rules here.

What this stage reads

This is the stage that reads the backend properly: the migrations, the models, the API schemas, the REST routes, the job definitions and the entry points, at depth.

The whole existing data model and operation list goes out as checks, batched per area — one for the tables, one for the operations, one for what runs outside the request. A person confirming the fourteenth table in a row has stopped reading (../hora-spec/references/investigation.md).

A check on the data model says what the product remembers, not which columns hold it (../hora/references/asking.md, "What changes for the person").

A feature listed under `Baseline: inventoried` still owes its tables and its operations a row each here. The section itself carries a name and one line (../hora/references/spec-format.md, "baseline") — but its tables are in the database everything designed here has to fit around, and its operations sit on a server stage 6 has to state a caller for. It costs almost no exchanges, since those rows sit inside the batched checks above.

Read it, put it up as a checkAsk, or propose
which tables exist, and what columns they holdwhy the model came out that way, and what it rules out
which operations exist, and what each returnswho each operation is for
which work already runs outside the request pathwhether work that runs in the request still belongs there
what the existing tests assertwhether what they assert is what anybody wanted

A shortfall found while reading is a proposal, never a check. "There is no index on this foreign key" states a fact; "add one" is this stage's own thinking.


What this stage decides

which repositories exist, and which servers run inside the backend
one endpoint switched on role, or an endpoint per audience
what tables hold, in logical terms
which operations exist, of which kind, against which server
which processing does not run inside a request, and why not

What it must not decide

Whose it is
a new use case, or a use case's wordingstage 1
whether a feature is in this releasestage 2
a user count, a retention period, an availability targetstage 3
which screen calls an operationstage 5
who may call an operationstage 6. This stage writes the operation; stage 6 writes its caller
a class name, a table name, a column name that lint has to accept`/hora-plan`, against the lint rules
the migration, the model, the resolver, the job class`/hora-build`, at checkpoints 3 to 7

The order inside this stage

1. The repositories, and the servers inside the backend
2. Roles on one endpoint, or endpoints of their own
3. The data model
4. The operations, per server
5. What runs outside the request
6. Walk every stage-1 use case against 3, 4 and 5

Step 6 is the exit condition, not a review. A data model that is internally tidy and cannot represent one stated use case passes every other check in this document.


1. The repositories and the servers

Declared, never assumed — /hora-setup reads this table and stops without it.

markdown
| Repository | Origin | Role |
|---|---|---|
| `acme-backend` | `<a backend origin>` | the API and jobs (holds the DB) |
| `acme-frontend-employee` | `<a frontend origin>` | the employee-facing screens |
| `acme-frontend-admin` | `<a frontend origin>` | the admin screens |
### 2.1 Servers
| Server | protocol | consumer |
|---|---|---|
| `employee-api` | (the default style) | `frontend-employee` |
| `admin-api` | (the default style) | `frontend-admin` |
| `worker` | — | an API server in the same repository (no contract needed) |
  • `Origin` comes from the stack handbook's catalog, and so does each origin's row count. A count outside an origin's stated bounds — a second backend, say — stops the run
  • Frontends are zero or more. An API-only release declares none, and stage 5 is then not applicable
  • Names read `<myproject>-<role>-<purpose>`, from stage 1's project name
  • The server table is the unit contracts are cut from, so it is always written. consumer decides whether a contract exists at all
  • A repository that already existed gets the optional Directory column, and /hora-setup then never clones it

Everything else about this table is in ../hora/references/spec-format.md.

2. Roles on one endpoint, or endpoints of their own

The most consequential choice this stage makes. ../hora-spec/references/principles.md holds the full decision table; the three cases in one line each:

The situationWhat to do
roles come and goone endpoint, switched on role
genuinely different entities — a different login, a different lifecycleseparate endpoints, separate authentication
one identity model, but unusually high security or unmanageably tangled permissionsendpoints per role. Not the default

Decide it from stage 1's actor table, not from the feature list. Two actors who share a login are roles; two who do not are entities.

Write the reason down, in .hora/spec/<version>/_stages.md under "Decided in conversation". Stage 6 checks that it is there, and the next version's new role is decided against that reason or against nothing.

The package owns what an endpoint is and how its auth filter is wired. What belongs here is how many there are and who each is for.

3. The data model

Delegate to the skills covering the logical shape of a table. They own whether to normalize, how to hold a status or a category, which type to pick, how to store a time, how to version a master table, how to keep a history, and how to scale reads. Invoke them and design against what they say.

What belongs in the spec is the logical shape:

markdown
### 9.1 `attendances`
| Column | Type | Constraint | Description |
|---|---|---|---|
| `id` | bigint | PK | |
| `staff_id` | bigint | FK → `staffs.id`, NOT NULL | who clocked in |
| `worked_on` | date | NOT NULL, unique with `staff_id` | the day, in the staff member's timezone |
| `started_at` | datetime | NOT NULL | |
| `finished_at` | datetime | NULL until they clock out | |
  • Every table names which use cases it serves — except a table belonging to a listed feature, which names that feature instead, since a listed section states no use case (../hora/references/spec-format.md, "baseline")
  • Stage 3's numbers are inputs here. Whether a monthly total is a stored column or a query is decided by the volume, and the decision is recorded with the number that produced it
  • A deferred feature's seam is honored here — stage 2 named it, and this is where it is left open
  • Do not name the model class or the migration. /hora-plan decides identifiers against the lint rules

4. The operations

The stack handbook's default API style is what a silent spec has chosen; another style needs a stated reason (../hora-spec/references/principles.md).

markdown
| schema | input | result | kind |
|---|---|---|---|
| `attendances` | `AttendancesInput(pagination, month)` | `AttendancesResult` | query |
| `createAttendance` | `CreateAttendanceInput` | `CreateAttendanceResult` | mutation |
| `closeMonth` | `CloseMonthInput` | `CloseMonthResult` | mutation |

Every operation states its kind, and the kind is never inferred. /hora-build branches on the value at three separate checkpoints. Ask, and write what was said.

Ask it as what the operation does — whether it only shows something, or changes something somebody else then sees.

An input whose fields nobody has decided stops the run. Writing it anyway means inventing the shape of an API.

AttendancesInput(pagination, month) the contents indicated in parentheses
→ derivable from an existing schema. Fine
AttendancesInput fields unknown
→ ask. blocking: yes

Writing the schema definition directly, in the form the handbook names for the server's protocol, is the most reliable option, and a spec may do that instead of the table.

A REST server's row is written only when the server table declares a REST protocol, and the renderer's own name is what gets implemented:

markdown
| method | path | renderer | request | response |
|---|---|---|---|---|
| `GET` | `/v1/attendances` | `GetAttendancesRenderer` | `?page=&limit=` | `AttendancesResponse` |

5. What runs outside the request

Ask one question of every write: does it have to have finished before the person sees a response?

markdown
## 12. Background jobs
| Job | Trigger | Queue | Payload | Why not in the request path |
|---|---|---|---|---|
| close a month | `closeMonth` mutation | `close` | `{ month, staffIds }` | reads every record for the month; minutes at 5000 staff (#nfr) |
| email a filed correction | after `createAttendance` | (post-worker) | `{ attendanceId }` | the caller does not wait on somebody else's mail server |
  • "Why not in the request path" is a required column. A job with no reason is a job somebody will move back into the request later
  • A job that must scale alone gets its own queue. Stage 3 already named which thing it is
  • Anything that leaves the process is worth naming here. An external call in the request path makes somebody else's outage your error page
  • The queue's store must be in stage 3's middleware table if this section has any row at all (the handbook's middleware rules). Go back and add it

6. Walk the use cases

Take each use case from stage 1 and walk it, step by step, against the tables, the operations and the jobs as drafted.

Look forIt means
a step with no operation behind itthe operation list is short
a state the model cannot representthe data model is wrong, not the use case
a step that needs data from two places that are not connecteda relation is missing
a use case that completes but takes minutes in the requeststep 5 was not applied to it
an operation no use case needseither a use case is missing (stage 1) or the operation is — unless it belongs to a listed feature, which justifies it by name

Where a walk fails, fix the design here and say what changed. A screen built on an operation list that cannot serve a use case is a screen that will be rebuilt.

Where the fix needs somebody who is not here, record unmet-usecase (blocking: yes), naming the use case and the step that fails, and carry on.


Delegates

This table lists work, not names. Match each row against the equipped skills' own descriptions when you reach it (../hora/references/structure.md, "No hora file ever names one of those skills").

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
56
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/openreachtech/hora-core/hora-spec-backend/badge)](https://verified-skill.com/skills/openreachtech/hora-core/hora-spec-backend)

Something wrong with this skill or its page? Tell us.