ReviewOS

stacks/reportshq

Scaffold the ReportsHQ Stacks app and repo foundation

#2
Closed chris opened this 8 days ago ·
8 days ago

Context

The repo at /Users/chris/Code/Apps/reportshq is an empty clone (only .git). Turn it into a running Stacks app and the repo foundation every other issue builds on.

Scope

  • Scaffold via ./buddy new reportshq. Known snag on this machine: gitit's output is swallowed under the buddy/bunx --bun wrapper and reports a bare "Failed to execute" - if that happens, run bun node_modules/@stacksjs/gitit/dist/bin/cli.js stacks reportshq directly. Scaffold into a temp dir and move contents into the existing clone if buddy new refuses a non-empty target.
  • Local dev config: the scaffold's .env defaults to Postgres with bogus credentials; set DB_CONNECTION=sqlite + DB_DATABASE_PATH=database/stacks.sqlite for local dev. SUDO_PASSWORD in .env enables the rpx HTTPS proxy (https://reportshq.localhost).
  • App identity: APP_NAME=ReportsHQ, production URL reportshq.org, dev URL reportshq.localhost. In config/cloud.ts, set project.slug: 'reportshq' - never leave the template's slug: 'stacks' (a tenant that keeps the template slug has overwritten another site's routing fragment before; see the 2026-08-07 outage note in loghq's sibling repos).
  • .gitignore must cover both /storage/cloud/ and /.ts-cloud/ (machine-local deploy state; repos with only one rule have committed stale server pins that pointed deploys at somebody else's box).
  • Port and adapt loghq's AGENTS.md house-style guide (/Users/chris/Code/Apps/loghq/AGENTS.md, ~18 KB, chapter-numbered and referenced from code comments) for ReportsHQ, and run buddy setup:ai.
  • Tooling: pickier lint + gitlint hooks wired in package.json, better-dx present with linker = "hoisted" in bunfig.toml, no catalog: protocol anywhere.
  • CI skeleton: .github/workflows/ci.yml running lint, typecheck, and tests on push/PR (deploy job comes in #21).
  • Initial conventional commits pushed to main.

Acceptance

  • ./buddy dev serves the scaffolded app locally; buddy migrate runs (its final auth-table "guarantee" step throwing no such table: oauth_access_tokens is a known non-fatal).
  • ./buddy lint, ./buddy typecheck, ./buddy test all green in CI on main.

Part of #1 (M1 Foundation). Ground rules: see #1.

8 days ago

Done in f8969ea, 647e6c3 and a906f77.

./buddy new reportshq scaffolded straight into the existing clone (the command already treats a directory holding nothing but .git as a valid target). Two hazards this issue called out are now handled upstream by the template itself and needed no work here: the cloud config derives slug: 'reportshq' from the directory rather than leaving the template's slug: 'stacks', and .gitignore already covers both /storage/cloud/ and /.ts-cloud/. SQLite is also the scaffold default now, so the Postgres-credentials snag in the issue no longer applies.

AGENTS.md was rewritten around the product: what ReportsHQ is, the architecture, the seven house rules, and a section of traps that have already cost time in this repo. CI runs lint, typecheck and tests on every push to main and is green.

Three defects surfaced while getting there, all fixed at the source rather than worked around:

A freshly scaffolded app could not typecheck. The scaffold ships config/mobile.ts importing MobileConfig, while buddy new pins the last published framework, which does not export it. Underneath that sits a bigger problem: @stacksjs/mobile statically imports craft-native/mobile, and the published craft-native is 0.0.55, whose only export is ".". Ten tagged versions (v0.0.56 to v0.0.65) were never published, so that package is unusable from npm for everyone, and it is what keeps typecheck red on the framework's main and therefore blocks any release. Filed as stacksjs/stacks#2322 rather than fixed by me: publishing ten held-back versions of a native SDK is a call for @chrisbbreuer, not a side effect of scaffolding an app. ReportsHQ ships no native surface, so it carries no mobile config, and that is recorded in AGENTS.md with the link.

buddy migrate:fresh --force is broken on a clean scaffold, which matters because it is the documented development reset. It fails with no such table: notification_deliveries and leaves fifteen duplicate migration files behind for tables the committed corpus already creates. Reproduced from a clean tree and filed as stacksjs/stacks#2323. Until it lands, reset locally with rm database/stacks.sqlite && ./buddy migrate.

The scaffold's labeler workflow had no config to read, so every generated app fails its first pull request with HttpError: Not Found. The action was also pinned to v4 while the framework has moved to v6, and the two read different config formats, so a v4-shaped file under a v6 action parses to zero rules and labels nothing silently. Fixed in the template with an app-shaped config and three tests (stacksjs/stacks@5c24c5c), then applied here.

Also fixed upstream along the way, because it was hiding the cause of the above: handleError('label', error) was filing the thrown error as opaque context and JSON.stringifying it to {}, since message, stack and cause are all non-enumerable. A dozen call sites across database, cloud and deploy reported nothing but their own label. See #5 for that thread.

Sign in to comment on this issue.