agentleFS
simtlixsimtlix/simfinity.js/.cursor/rules/simfinity-barber-examples.mdc

simfinity.js / rules

Cursor rule11 starsChanged 17 days agoApache-2.0View on GitHub

Maintain the independent Barber applications, shared frontend, Docker stacks and dedicated CI

  • Reads credentials

We split this simfinity-barber-examples.mdc into the rules it gives an agent

6 rules. About 0 are common, 0 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Keep the apps outside packages/* workspaces and library release/version scripts.

    line 12
  2. Very specific:

    Run Compose from examples/barber with -f compose.mongodb.yaml or -f compose.postgres.yaml.

    line 21
  3. Very specific:

    Default host ports are MongoDB 57417, API 4400, frontend 4401.

    line 22
  4. Very specific:

    Keep the per-route limiters in routes/rateLimits.js (graphql, mcp, uploadIp, upload) and their environment names (GRAPHQL_RATE_LIMIT_MAX, …

    line 27
  5. Very specific:

    Do not track real environment files, user uploads, dependency directories, generated frontend output, vendor archives, or PostgreSQL schema …

    line 31
  6. Very specific:

    Update examples/barber/README.md, the affected app README, and docs/resources/barber.md when setup or documented behavior changes.

    line 39

≈ “Common” is an estimate: at least 1 in 5 of the 6,350 Cursor rule files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
simfinity-barber-examples.mdc
---
description: Maintain the independent Barber applications, shared frontend, Docker stacks and dedicated CI
globs: examples/barber/**, .github/workflows/barber.yml
alwaysApply: false
---

# Barber application examples

## Ownership and dependencies

- `examples/barber/mongodb/`, `postgres/`, and `frontend/` are private npm apps with their own manifests and lockfiles. Run `npm ci` inside the affected app; root workspace installation does not install them.
- Keep the apps outside `packages/*` workspaces and library release/version scripts. Backend Simfinity runtime packages use exact released version `3.7.0` from npm. Do not restore local vendor archives or file dependencies.
- The frontend source is shared. Its GraphQL endpoint is selected by the environment at build time and must be reachable by the browser. Treat IDs as opaque GraphQL `ID` strings: MongoDB uses ObjectIds and PostgreSQL uses UUIDs.
- Scopes must intersect caller filters with server restrictions. Use `intersectScopeFilter` instead of overwriting an existing scalar, relation, ID or OR filter.
- Scopes run once per parent row and per resolved reference. Express restrictions on related records as relation-path terms (`ownedBarbershopTerm`/`approvedBarbershopTerm` in `types/scopeHelpers.js`, e.g. `barbershop.state`, `barbershop.owner.id`) instead of loading ID lists inside a scope.
- Keep `auth/ownership.js` and the booking, bundle, service and review controllers mirrored in both backends. `protect()` counts a field as written only when it differs from the stored value (`writtenFields`, `clears`), and refuses a non-admin delete of a shop that bookings or reviews reference, or of a booking that a review references, with `RESOURCE_IN_USE` (409) on both backends. Derive booking and bundle values (line prices and durations, totals, `endTime`, confirmation codes, creation times) on the server from the shop's catalog; never trust client-sent values. A service's duration change or delete refreshes the stored `totalDurationMinutes` of the bundles that list it (`refreshBundleDurationsForService`), and the frontend derives a bundle's duration with the same rule (`src/lib/catalog.ts`).
- Preserve the same domain concepts, relationship metadata, scopes, controller responsibilities, and state transitions. Native Mongoose and PostgreSQL model/session calls remain separate. Choose the backend at startup; do not add runtime switching or automatic data migration.

## Operation and data

- Run Compose from `examples/barber` with `-f compose.mongodb.yaml` or `-f compose.postgres.yaml`. Retain the distinct project names `simfinity-example-barber-mongodb` and `simfinity-example-barber-postgres`, named volumes, and loopback bindings so both stacks can coexist.
- Default host ports are MongoDB `57417`, API `4400`, frontend `4401`; PostgreSQL `55441`, API `4500`, frontend `4501`. Backend/frontend container ports are `4300`/`4301`. Changes must update `.env.example` files, scripts, tests and READMEs together.
- Await database readiness before serving `/health`, `/graphql` and `/mcp`. HTTP, stdio, seeds and operational scripts should reuse each backend's application/database initialization and auth context.
- Request entry points read the account: GraphQL and uploads use `resolveUserContext` (an expired or invalid bearer, or a suspended or deleted account, is anonymous), HTTP `/mcp` and `mcp:stdio` use `resolveMcpUserContext` (it throws `UNAUTHENTICATED` or `ACCOUNT_SUSPENDED` for each of these; only a request without a bearer is anonymous). Both take the role from the database. `buildUserContext` is token-only; do not use it for requests.
- Mount the HTTP MCP handler with `app.all('/mcp', limiters.mcp, express.json(), mcpBodyErrors, rejectJsonRpcBatch, mcpHandler)` so non-POST methods get its `405` with `Allow: POST`, not an Express `404`, and unparsable bodies get JSON-RPC errors. Keep `jsonErrorHandler` (`routes/errors.js`) as the app's last middleware, so no error answers with Express's HTML page or a stack trace. In `useErrorHandler`, pass each entry of `errors` to the `buildErrorFormatter` logger; never pass the formatter itself, which then logs only `Unexpected error value`.
- `mcpOptions` in `application.js` is the single source of MCP options for `index.yoga.js`, `mcp:stdio` and the integration tests; entry points add only their `context`. Never publish the auth mutations (`AUTH_OPERATIONS`: `login`, `register`, `registerOwner`, `refreshSession`) as MCP tools, and reject JSON-RPC batches before the MCP handler.
- Keep the per-route limiters in `routes/rateLimits.js` (`graphql`, `mcp`, `uploadIp`, `upload`) and their environment names (`GRAPHQL_RATE_LIMIT_MAX`, `MCP_RATE_LIMIT_MAX`, `UPLOAD_IP_RATE_LIMIT_MAX`, `UPLOAD_RATE_LIMIT_MAX`). The per-account upload limiter runs after `requireAuth`.
- Uploads take their type and extension from the file's bytes (JPEG, PNG, WebP, GIF; no SVG) and stage under `uploads/.incoming`, never in memory. They accept one `file` part and no other fields or parts; a Node system error while staging answers 500 without server paths. `createUploadRouter` sweeps abandoned staged files at startup, and shutdown awaits `router.settled()` after closing connections. `serveUploads` sends nosniff and the sandbox CSP on every file and serves non-raster files as `application/octet-stream` attachments, except legacy `.svg`, which keeps `image/svg+xml` (still an attachment) so `<img>` shows it.
- `seed:admin` precedes `seed:demo` and never promotes an existing non-admin account. The synthetic demo uses `barber-demo`, `admin@demo.com`, `propietario@demo.com`, `cliente@demo.com`, and password `demo1234`. Preserve repeatable seeding and browser-test compatibility.
- Reset only the selected example project. Data-changing scripts and tests must use disposable databases. `dataset:delete` deletes all records of its covered entity types at its endpoint, not only records bearing a fixture marker.
- Do not track real environment files, user uploads, dependency directories, generated frontend output, vendor archives, or PostgreSQL schema exports. `schema:export` writes current SDL, SQL and real catalog FK descriptions under ignored `postgres/generated/`.

## Verification and documentation

- `.github/workflows/barber.yml` owns backend unit tests, the database HTTP/MCP matrix, frontend checks and browser coverage, and database integration checks. Root ESLint and Vitest exclude examples.
- Each app exposes `npm run test:security` and its CI job audits its own complete lockfile, including development tools. Keep Vitest/browser/coverage versions compatible and do not bypass peer conflicts with `--force` or `--legacy-peer-deps`. Preserve the supported majors and exact released Simfinity dependencies when updating security baselines.
- `test:query-mutations` runs the shared HTTP filter/aggregate/nested-mutation matrix. Its missing-reference case explicitly distinguishes PostgreSQL FK rejection from MongoDB dangling-reference acceptance. It leaves synthetic fixtures in the disposable API database; CI saves its JSON reports.
- Run both database HTTP/browser paths for shared contracts. Preserve `test:mongodb` and both `test:dataset` suites for transactions, derived booking/bundle/review values and fixture operations. Keep PostgreSQL native model, FK, transaction and frontend-query regression checks. Do not use library unit tests as a substitute for app validation.
- Update `examples/barber/README.md`, the affected app README, and `docs/resources/barber.md` when setup or documented behavior changes. Preserve source-commit provenance and `frontend/LICENSE`.
- Describe the app as a synthetic local MVP. Its presence in the monorepo does not change the runtime library compatibility contract or require an npm library release.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.