Generated Computers
Locals는 Apple Silicon 엔진으로 로컬 LLM을 최대 3배 빠르게 실행하는 Generated Computers 제품
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A TurboRepo starter for a multi-tenant web app: accounts, organisations, roles and per-tenant data, with the isolation checks that keep them honest.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A TurboRepo starter for a multi-tenant web app: accounts, organisations, roles and per-tenant data, with the isolation checks that keep them honest.
It runs on nothing. No account, no container, no native build — npm install && npm run dev
gives you a working app with a seeded demo tenant.
Pre-1.0 — a reference implementation, not a dependency. The schema, the API and the layout of the packages still change breakingly, with no migrations between versions until 1.0.
Two accounts, in separate organisations on purpose: sign in as one and the other's projects, members and audit log are simply not there.
| Sign in as | Password | What you land in |
|---|---|---|
[email protected] | hamster-wheel-9000 | TurboHam & Co Wheelwrights, as its owner |
[email protected] | hamster-wheel-9000 | Teemo Industries, as its owner |
Break whatever you like — the database is rebuilt from the seed on every restart.
The GitHub Pages copy — https://artoriun.github.io/turbohamscaler/ — is the public marketing pages as static files, with no server behind them.
/appthere says so rather than offering a sign-in form that cannot work.
| File | The decision |
|---|---|
packages/api/src/repo.ts | Every tenant-owned query lives here and takes orgId first. Routes never write SQL, so a tenant filter can only be forgotten in one file. |
scripts/check-tenancy.mjs | That rule is a build failure, not a convention: CI fails if a query touches a tenant table without filtering on org_id, or if SQL appears outside the repository layer. |
packages/api/src/isolation.test.ts | The same rule from the attacker's side — a signed-in user of one organisation asking for another's rows by id. Non-members get 404, never 403, because 403 confirms the organisation exists. |
packages/api/src/db/postgres.ts | The third Driver, and the one that makes the interface mean something: a different wire protocol, different placeholders, and an INTEGER a millisecond timestamp overflows. |
scripts/check-deploy.mjs | Runs the deploy blueprint's own commands against a clean checkout and then signs in — a health check that never touches the database cannot tell you the deploy works. |
packages/api/src/password.ts | PBKDF2 via Web Crypto, 600,000 iterations, scheme and cost stored in the hash so they can be raised later. An unknown scheme fails closed. Web Crypto is also what lets the same code run on Workers. |
The comments explain why, not what. npm run ci runs the fourteen checks CI runs, in order.
The signed-in app: per-tenant projects, members and roles, invitations, organisation and account settings, and an audit log of who did what.
The prerendered public pages in front of it.
Light and dark are both first-class; the theme is chosen before first paint, so it never flashes.
Building a portfolio or marketing site instead? That is TurboHamstarter.
| Front end | React, TypeScript, Vite, React Router |
| Back end | Hono, SQLite (node:sqlite), Cloudflare D1 or Postgres |
| Tooling | TurboRepo, Biome, Playwright |
Three workspaces: packages/web, packages/api, packages/shared.
Use this template for your own repository, or clone it to keep the history.
npm install
npm run db:seed # a demo tenant, so the app opens on something
npm run dev # web on 3410, API on 4410
Node 22 or newer (.nvmrc) — node:sqlite is what makes the database work with no native build,
and the install refuses anything older. Sign in with either account from the table above. No
.env is needed to run it; for production see .env.example.
npm run build # production build
npm run prerender # build, then write each public route out with its text in the markup
npm run ci # everything CI runs, in order
npm run test # API and unit tests
npm run test:api:postgres # the same API tests against real Postgres
npm run test:api:worker # the same API tests against a local Worker + D1
npm run test:e2e # Playwright, against the dev server
npm run test:e2e:dist # the same, against the built output
npm run check:tenancy # structural guards on tenant isolation
npm run check:deploy # build and boot render.yaml's commands, then sign in
npm run check:budgets # bundle and image size ceilings
npm run db:migrate # apply pending migrations
npm run db:reset # delete the local database and reseed
member / admin / owner roles and per-tenant projects. Anyone may
leave except the last owner, who would strand everybody elsemailer.ts is the seam, with a worked example in
its comments. Without one the token comes back for the admin to pass on; with one it does notobservability.ts is the seam, with a worked Sentry
example and a default that reaches nobodysitemap.xml, a pointing at it, and social tags carrying the origin
they were built forEvery tenant-owned query lives in repo.ts and takes orgId first.
Routes never write SQL.
npm run check:tenancy fails the build if a query touches a tenant-owned table without filtering
on org_id, or if SQL appears outside the repository layer.
isolation.test.ts proves the behaviour end to end.
A non-member gets 404, never 403: a 403 confirms the organisation exists, which tells anyone
enumerating ids which ones are real.
app.ts.ROUTE_MANIFEST at the bottom of that file, with what it requires.repo.ts, taking orgId first.authMatrix.test.ts reads that manifest and checks every route against an anonymous caller, a
non-member, and a member holding too low a role. A route missing from the manifest is untested,
which is why step 2 is not optional.
npm run ci runs CI's pipeline in CI's order: Biome, tsc, the tenancy guards, API and unit
tests, a check that the deploy blueprint builds and signs in, the API tests again on Postgres and
again on a local Worker + D1, the build, bundle and image budgets, Playwright against the dev
server, the suite again against the built output, and Lighthouse.
The API suite runs three times. The same 146 assertions pass on SQLite and Postgres, and 133 of them on a Worker with D1 — the thirteen skipped reach into this process's database or swap a module-level seam, which a separate Worker does not share. It is all local: wrangler runs on Miniflare and Postgres runs as WebAssembly, so no account, container or database server is needed.
Accessibility is checked twice. Lighthouse audits the public pages and /app but cannot sign
in, so e2e/a11y.spec.ts sweeps the signed-in portal with axe in both themes, with real content
on screen and with a project open for editing. It gates serious and critical findings only.
Neither check makes the app accessible — a green sweep is a floor, not a verdict.
Lighthouse gates accessibility, SEO, best-practices and CLS, all properties of the code. It
prints performance without gating it, because a shared runner's timings drift more than the thing
being measured; the bundle budget is the deterministic half. npm run ci skips it locally — run
npm run check:lighthouse on a quiet machine.
The two halves deploy separately, and nothing has to be deployed for the starter to be useful.
The public pages are static. CI builds them with VITE_BASE and publishes to GitHub Pages on
every push to main. Set BASE_PATH at the top of .github/workflows/ci.yml to your repository
name, or / for a custom domain.
The app needs a server, and runs on three databases. The routes are a
Hono app on Web-standard Request and Response, so the same code serves a Node
process or a Cloudflare Worker. Nothing in packages/api/src changes between them: the database
sits behind Driver (db/index.ts, db/d1.ts, db/postgres.ts) and password hashing uses Web
Crypto rather than node:crypto.
One free instance, both halves — render.yaml deploys everything to Render's
free plan, which is what the demo runs on. The API serves the built front end so both share an
origin, and that is not a shortcut: the session cookie is SameSite=Lax, so a browser will not
send it cross-site. app.example.com with api.example.com is fine, one origin is fine, but
pages and API on different sites means nobody can sign in. Splitting them for real means
SameSite=None; Secure and CSRF tokens.
Cloudflare Workers + D1 — wrangler.toml:
npx wrangler d1 create hamscaler # paste the id into wrangler.toml
npx wrangler d1 migrations apply hamscaler --remote
npx wrangler deploy
Workers' free plan allows 10ms of CPU per request, and hashing a password properly costs more than that on purpose, so this means the paid plan. Lowering the iteration count to fit the free tier trades every stored password's security for the hosting bill.
Postgres — the same Driver against any pg client:
import { Pool, types } from 'pg';
types.setTypeParser(types.builtins.INT8, Number); // timestamps, not strings
setDriver(postgresDriver(new Pool({ connectionString: process.env.DATABASE_URL })));
| Variable | What it does |
|---|---|
DATABASE_URL | Where the database lives. node:sqlite writes a local file, which suits one instance; point it at a hosted database for anything real |
DEMO_SEED | Seeds the two demo organisations on start-up. Leave unset anywhere real |
SITE_URL | The origin the pages are served from, scheme and host only. The sitemap and social tags are built from it |
VITE_API_URL | Where the front end looks for the API, if they are built separately |
LOG_LEVEL | debug / info / warn / error / silent |
A free instance has no persistent disk, so the database is rebuilt from the seed on every
restart — good for a demo, wrong for anything else. Attach a disk or use a hosted database, and
turn DEMO_SEED off.
A free instance sleeps after about fifteen idle minutes, and waking it costs half a minute of the
host's holding page. Any uptime monitor that requests a URL on a schedule prevents it — point one
at /health, which answers without touching the database, at an interval under fifteen minutes.
Staying awake around the clock spends roughly 730 of Render's 750 free instance-hours a month,
which fits one service and not two. healthCheckPath in render.yaml does not
help: Render only uses it while a deploy is going out. Nor is the deploy window itself avoidable
on the free plan — there is no zero-downtime rollout, so the holding page is what visitors get
while a new build is promoted.
See CONTRIBUTING.md — in particular the rules the build enforces, which are checks rather than preferences.
MIT — see LICENSE.
robots.txt