Lalabase
티켓·문서·근무시간·고객대화를 한 곳에 모아 KI로 검색, 소프트웨어 기업 고객 프로젝트용, 오픈소스로 자체 서버·독일 클라우드에 배포
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기aquatrack
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A mobile-first Progressive Web App for a water-selling business in Sri Lanka. Two
employees register sales in ~10 seconds each; the owner gets a real-time
dashboard, transaction history with corrections/audit log, and automatic
daily/weekly/monthly email reports.README 전문 보기 ↗A mobile-first Progressive Web App for a water-selling business in Sri Lanka. Two employees register sales in ~10 seconds each; the owner gets a real-time dashboard, transaction history with corrections/audit log, and automatic daily/weekly/monthly email reports.
Currency: LKR (Rs.) · Timezone: Asia/Colombo
prisma/schema.prisma) — swap the DATABASE_URL provider for Postgres/MySQL in production without touching app codenpm install
cp .env.example .env # fill in AUTH_SECRET, CRON_SECRET, and SMTP_* when ready
npx prisma migrate dev # creates prisma/dev.db and applies the schema
npm run db:seed # creates the owner + 2 employee accounts below
npm run dev
Seeded accounts (change these passwords after first login — there's no in-app "change my own password" screen yet, so ask an admin to reset it via Team → employee → Reset Password):
| Role | Username | Password |
|---|---|---|
| Owner | owner | Admin@123 |
| Employee | employee1 | Employee@123 |
| Employee | employee2 | Employee@123 |
Open the deployed URL on a phone:
No App Store / Play Store listing needed. Icons and manifest live in
public/icons/ and public/manifest.webmanifest (regenerate icons with
python3 scripts/generate_icons.py).
Report delivery is driven by /api/cron/reports. It's idempotent — safe to
call as often as you like; it only sends once per (report type, period,
recipient) and retries failed sends automatically, logging every attempt to
the EmailLog table (visible under Reports in the admin app).
On Vercel, vercel.json already wires this up automatically: a Vercel Cron
job hits GET /api/cron/reports once a day (see the crons entry there —
currently 5 16 * * * UTC, i.e. 21:35 Asia/Colombo, five minutes after the
default 21:30 daily send time configured in the app). Vercel authenticates
that request itself using the CRON_SECRET env var (sent as
Authorization: Bearer $CRON_SECRET) — no extra setup needed beyond having
that env var set.
Hobby-plan note: Vercel's free tier only allows one cron firing per day,
and the exact time can drift by up to an hour. If you change the daily send
time in Settings to something later than the cron schedule in
vercel.json, update the cron schedule too (and redeploy) so it still fires
after your new time — otherwise that day's report is skipped and goes out
on the next day's cron run instead.
Two other ways to trigger it manually if needed:
POST /api/cron/reports with header x-cron-secret: $CRON_SECRET (e.g. via curl) — useful for testing.npm run cron:reports on an interval (system
crontab, pm2, etc.) with APP_URL and CRON_SECRET set in the environment.Recipients, send times, and which reports are enabled are all configured
under Settings → Email Reports in the admin app (ReportSettings table).
Gmail SMTP: use an App Password
for SMTP_PASS, not your normal Gmail password (Google requires 2FA + app
passwords for SMTP).
PricingSetting.pricingMode): MANUAL (V1 default —
employee enters liters + amount), PER_LITER (owner sets a fixed price,
amount is calculated automatically), and PRODUCT (reserved for future
multi-product/customer-category pricing — schema-ready, not exposed in the UI yet).src/lib/pricing.ts): compares a manually
entered rate against the recent average and asks the employee to confirm
if it's out of range. It never auto-corrects the amount.requestId (UUID)
once per sale attempt; resubmitting the same requestId (double-tap, retry
after a dropped connection) returns the original sale instead of creating a
duplicate. The sale screen shows "SAVING…" until the server confirms.PATCH /api/sales/:id updates the sale but
also writes an AuditLog row with the old/new values and the admin's
reason — nothing is silently overwritten.src/middleware.ts (not just hidden in
the UI) — employees get 401/403 from admin-only APIs even if they guess the URL.public/sw.js caches the app shell for fast loads and an
offline fallback page. Sale submission is deliberately network-only for V1
(queued offline sales are a listed future enhancement, not implemented —
see section 22/26 of the product spec) so a sale is never silently lost or
double-counted.npm run dev / npm run build / npm run startnpm run db:migrate — create a new Prisma migrationnpm run db:seed — re-run the seed (upserts, safe to re-run)npm run db:studio — Prisma Studio to browse the databasenpm run cron:reports — trigger the report cron once (see above)