Lalabase
Tickets, Doku, Zeiterfassung und Kundengespräche an einem Ort, durchsuchbar per KI. Für Softwarefirmen mit Kundenprojekten. Open Source: auf deinem eigenen Server oder in unserer Cloud in Deutschland.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Multi-tenant hospitality SaaS for Nepal's F&B industry. One React app on one Supabase project;
inventory, HR and POS are modules toggled per client, Crest Customization (sizes, extras and "No …"
choices on a dish, and build-your-own dishes walked step by step) is a paid add-on to POS, and Crest Suite Pro is the owner layer sold on top.
Repo: C:\crest-suite · E-drive backup: E:\CREST SUITE MANAGEMENT\查看完整 README ↗Multi-tenant hospitality SaaS for Nepal's F&B industry. One React app on one Supabase project; inventory, HR and POS are modules toggled per client, Crest Customization (sizes, extras and "No …" choices on a dish, build-your-own dishes walked step by step, and combos sold at one price) is a paid add-on to POS, and Crest Suite Pro is the owner layer sold on top.
Repo: C:\crest-suite · E-drive backup: E:\CREST SUITE MANAGEMENT\
This file is a map, not a summary. Everything below points somewhere; nothing here restates what it points at. A line that describes rather than points is a line that goes stale without anyone noticing — that is how this file reached 1.8 million characters (see S666). Add new material to the file that owns the subject, and add a pointer here only if there is nowhere else.
npm start # Dev server → http://localhost:3000
npm run build # Production build (this is what Vercel runs)
npm run build:verify # Same build, for checking a change locally: clears the stale
# ESLint cache first and treats warnings as errors. Use this
# while `npm start` is running — the two share
# node_modules/.cache, and a dev server writing stale entries
# back is what produces build errors that are not in the code.
npm test # Jest suite
npm run check:docs # Rules-glob, rules-stub and CLAUDE.md-size checks. Also run by
# build:verify, so a rule that silently stopped loading fails a
# pre-push check rather than waiting for the next /doctor pass.
Env vars required:
REACT_APP_SUPABASE_URL
REACT_APP_SUPABASE_ANON_KEY
REACT_APP_USDA_API_KEY
REACT_APP_VAPID_PUBLIC_KEY
REACT_APP_SITE_ORIGIN
.env.example says what each one is for. REACT_APP_SITE_ORIGIN is the only one whose absence is
silent in dev and visible on paper: it is the production domain the printed Subscription Agreement
quotes as the evidence of what a signed contract incorporated by reference, so unset it prints
[SET REACT_APP_SITE_ORIGIN]/legal/terms rather than a plausible wrong domain, and
legalReadiness() refuses to call the documents publishable.
REACT_APP_SUPABASE_SERVICE_ROLE_KEY must never be set here or in Vercel — admin operations go through the admin-user-ops Supabase Edge Function instead (see S311).
| Path | What lives there |
|---|---|
src/modules/ | The product, one directory per area: ims/, hr/, pos/, admin/, dashboard/, ownerReport/ |
src/pages/ | Routes belonging to no single module — login, signup, pricing, help, settings, periods |
src/shared/ | Cross-module code: the scoped data-access layer, paged reads, error text, hooks |
src/components/ | Reusable UI, and the route guards every protected route stacks |
src/context/ | Auth, settings and theme providers. Singular context — the plural is a glob that has already rotted once |
src/utils/ | Standalone helpers: BS calendar, expression evaluator, subscription state, timeouts |
src/data/ | pricingPlans.js — the plans, their feature lists, and the SHIPPED prices. What a screen prints is resolvePricing() over the admin's Settings > Plan Pricing figures, reached as useSettings().pricing |
src/legal/ | The published Terms and Privacy Policy as markdown, their content hashes, and the registry the acceptance flow stamps. Edit a .md and re-run node scripts/hash-legal.mjs; a test fails if you forget |
supabase/ | Migrations and Edge Functions |
scripts/ | Build, audit and docs-check scripts, all reachable from package.json — except check-design-layers.mjs, run by hand after a theme change |
public/ | PWA shell and service worker, plus the second manifest for the staff app |
| Read this | For |
|---|---|
CLAUDE.md | Commands, stack, and the rules that must be known before you think to ask: the gate model, tenant isolation, the privilege invariants, the Supabase and BS-date traps, plus a pointer table into .claude/rules/. Loaded on every request of every session, so it holds nothing module-specific. |
.claude/rules/ | The same kind of rule, scoped by a paths: glob so it loads only when a matching file is open. Check npm run check:docs still passes after moving a file. |
.claude/skills/new-feature-checklist/ | The steps between "it works" and "it shipped". Invoke it before any new page, report or module feature. |
DESIGN.md | The design system as it actually exists in the code: tokens, scales, components, and the named rules that are already enforced. |
PRODUCT.md | Who buys this and why — users, positioning, brand personality, anti-references. |
IMS_TODO.md | The S756 IMS re-analysis: the owner's 28 decisions and the fix list by stage, with what is still open. |
POS_TODO.md | POS open items. Shipping something listed there closes the entry in the same commit. |
There is no ARCHITECTURE.md and there should not be. CLAUDE.md plus .claude/rules/ already is
that document, and a fourth copy of the gate model would drift from the three that exist.
.gitattributes normalises the tree to LF on commit, which is not the same
as the working tree being LF, and it is not. Measured 2026-09-09: MenuPricing.js is pure LF and
MenuRepricing.js, its sibling in the same directory, is pure CRLF; several .claude/rules/*.md
are mixed within one file. Git never reports this, because it normalises on the way in. So a
script that searches for a string containing \n silently matches nothing in half the repo —
assert your match count, and try \r\n before \n per replacement block rather than per file.
Do not "fix" a file by normalising it: that turns a 12-line diff into a whole-file rewrite.
Separately, do not write files with PowerShell's Set-Content -Encoding utf8 — it emits a BOM —
or read them with Get-Content, which reads ANSI and mangles every em dash. Use
[System.IO.File]::ReadAllText / WriteAllText, or a shell that is not PowerShell.CACHE_NAME bumped in public/service-worker.js and APP_VERSION in
src/shared/appVersion.js moved to match — appVersion.test.js fails when they disagree.
They had drifted nine bumps apart before S689 noticed, so the test is doing real work.
CLAUDE.md explains why a plain deploy is not enough.React.lazy and xlsx is imported inside the click handler, so the app fetches its own
code by hashed filename; Vercel replaces those files and the worker's activate deletes the
cached copies on the same event. src/shared/chunkReload.js recognises that failure and reloads
once — never more than once a minute, never while offline. Do not widen its patterns to catch
ordinary errors: a real crash misread as a stale deploy is hidden by the mechanism meant to
recover from it./ plus the one js/css pair named in the
build's asset-manifest.json. A route whose own chunk has not been fetched since the last deploy
still cannot render offline, and the error boundary says so in those words. No Supabase response
is ever cached; anything that must survive a lost connection needs its own IndexedDB store, which
is what Stock Count and POS order-taking have and nothing else does.POS_DECISIONS.md| POS shipped history and everything decided against, rationale intact. Read before proposing POS work. |
SUITE_TODO.md | Crest Suite (the owner layer) open items: the S848 re-analysis index, the owner decisions SU1–SU23 and what the live checks found. Evidence per ID in docs/suite-review-s848/. |
CHANGELOG/ | The session log, S023 to now, split by S-range. CHANGELOG/README.md is the index and holds the convention for adding an entry. |
DOCS-REMEDIATION.md | The open work order this layout came from. T1–T14, with mechanical acceptance criteria. |
CHANGELOG/CHANGELOG/README.mdpublic/manifest.json declared orientation: portrait-primary for a year with nothing to show
for it, because desktop Chrome ignores manifest orientation and that is where the app is
developed, demoed and run on a Windows till. Under display: standalone on Android — a count
tablet or an Android POS terminal added to the home screen — Chrome honours it, and it would have
locked a bolted-down landscape screen to portrait with nothing in the app able to override it
(S764). There are two manifests and they serve different devices: staff.webmanifest is
phones only and keeps portrait-primary. .claude/rules/staff-app.md has the rest.window.innerWidth < 768. iPad portrait is 768, so <
excluded it; landscape is 1024+, a 10" Android is ~800. No tablet had ever reached the one
screen in the product designed for a tablet, and it went unnoticed for as long as it existed
because the phone branch worked and the desktop branch worked (S765). Decide by INPUT METHOD:
matchMedia('(pointer: coarse)') reads the primary pointer, so a touchscreen laptop driven by a
mouse correctly keeps the dense screen — which a width test can never express. That is already
the documented rule for touch SIZING (@media (pointer: coarse), S603); this is the same rule
applied to choosing a whole layout. Keep a narrow-width clause only so a desktop browser dragged
narrow still behaves, and watch the media query as well as resize — a detachable tablet docked
to a keyboard changes its primary pointer without changing its width.localStorage on whatever phone opens the page, and a shared phone may belong to staff.
The guest QR menu and the public booking page are pinned to the default preset in
ThemeContext.js (isPinnedGuestSurface, S767) — pinned at the provider, so the lazy-load
fallback and the error screens are covered too, which a per-page palette never was. A new public,
customer-facing route joins PINNED_GUEST_PREFIXES.top: -<padding>; at top: 0
Chrome pushed it down over the content beneath it (measured on the guest choices sheet, S767).
The bottom edge did not behave symmetrically, so the guest sheets' pinned footers cover the
padding strip with a same-colour shadow instead. Measure it; do not reason it.PRESETS in
src/context/ThemeContext.js is what a user sees; DESIGN.md's frontmatter is the normative
copy the /impeccable hook checks literals against; its prose is what gets read; and
.impeccable/design.json is generated from both. Nothing renders from the lower three, so
nothing fails when they are wrong. Run node scripts/check-design-layers.mjs after moving one.