Lalabase
티켓·문서·근무시간·고객대화를 한 곳에 모아 KI로 검색, 소프트웨어 기업 고객 프로젝트용, 오픈소스로 자체 서버·독일 클라우드에 배포
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기thinkfirststudios/ThinkFirst-Studios-CRM
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A Salesforce-style CRM for ThinkFirst Studios — customers, vendors, work orders and
an everyday tracker, built on the brand guide (orange #FA7700 on near-black).
No build step. No install. Runs as static files, backed by Supabase for the shared
team version or by localStorage for offline use.
Or just open index.html — the app uses classic scripts, so file:// works for the
offline mode. Use a served URL for the Supabase version, since auth email links need
somewhere real to return to.README 전문 보기 ↗A Salesforce-style CRM for ThinkFirst Studios — customers, vendors, work orders and
an everyday tracker, built on the brand guide (orange #FA7700 on near-black).
No build step. No install. Runs as static files, backed by Supabase for the shared
team version or by localStorage for offline use.
npx serve .
Or just open index.html — the app uses classic scripts, so file:// works for the
offline mode. Use a served URL for the Supabase version, since auth email links need
somewhere real to return to.
| Section | What it does |
|---|---|
| Home | Open pipeline, recurring revenue, close rate, overdue work, your queue, billing radar, team activity |
| Customers | Filterable list view, full record page, CSV export |
| Pipeline | Drag-and-drop kanban across the statuses |
| Daily Tracker | The everyday work-order board — see below |
| Work Orders | Every job across customers and vendors, with time logging |
| Vendors | Same fields as customers, plus vendor type, payment terms and rating |
| Billing | One calendar of incoming (customer) and outgoing (vendor) billing dates |
| Admin | Users & roles, service catalog, statuses, vendor types, backup/restore, audit log |
The everyday work-order screen:
Vendors carry the same categories as customers — status, billing date, services, notes, owner — plus vendor type (Subcontractor, Supplier, Freelancer, Software/SaaS, Agency Partner, Print/Fabrication, Media Buyer — all editable in Admin) and their own work orders, which flow into the same Daily Tracker as customer work.
The app reads js/config.js at boot and runs one of two ways.
| Offline (blank config) | Live (Supabase configured) | |
|---|---|---|
| Storage | localStorage, this browser only | Shared Postgres |
| Accounts | None — pick a teammate from the chip | Real sign-in |
| Sharing | Nothing is shared | Whole team, updating live |
| Roles | UI-level only | Enforced by the database |
The top bar shows which one you're in: Live or Offline.
The offline mode is the demo — it ships with sample accounts so every screen has something in it. If the backend is configured but unreachable, the app stops with an error rather than silently falling back, so a connection problem never looks like your team's data vanished.
1. Create the tables. Supabase Dashboard → SQL Editor → New query → paste all of
supabase/schema.sql → Run. It's idempotent, so re-running is safe.
This creates the tables, the row-level security policies, realtime, and the reference data.
If the dashboard itself is down (
Failed to fetch (api.supabase.com)), the SQL Editor is unavailable but your project's database is a separate service and is usually still fine.supabase/apply-schema.mjsapplies the same file directly over the connection pooler:cd supabase && npm install pg && node apply-schema.mjs. It prompts for your database password locally. Thatpginstall is for this script only — the app itself stays dependency-free.
2. Point the app at your project. Fill in url and anonKey in
js/config.js. That key is the publishable/anon key — it's designed to
ship in client code and is safe to commit. Your security is the RLS policies from step 1,
which is why step 1 is not optional. A service_role key must never go in this file.
3. Host it. Auth email links need a real URL to return to — they can't redirect to a
file:// path. Either:
main / / (root), ornpx serve -l 3000Then set Supabase → Authentication → URL Configuration → Site URL to that address.
If you leave it as the default http://localhost:3000 and nothing is running there,
confirmation links land on "This site can't be reached" — the account is still created
and confirmed, the redirect just has nowhere to go.
4. Sign up. The first account becomes the admin; everyone after starts as a rep,
and an admin promotes them in Admin → Users & Roles. If you signed up before running
step 1, re-run schema.sql — it backfills a profile for any existing login and makes the
earliest account the admin.
For a small internal team, consider turning off Authentication → Sign In / Providers → Email → Confirm email. Sign-up then works instantly with no email round-trip and no redirect to get wrong.
Every signed-in teammate sees everything — all customers, vendors, work orders and notes.
Reads and writes are open to the whole team; deletes and setup are restricted. Those rules live in the database policies, not just the interface, so they hold even if someone pokes at the API directly. In offline mode the acting-user switcher is a convenience, not authentication — it exists so you can see how multi-author notes behave.
Stripe is mirrored into the CRM so the Billing screen shows what customers actually paid, rather than dates somebody typed in. It is read-only in one direction: the CRM never writes to Stripe, and nothing in the app can write to the mirror tables — they have SELECT policies and no INSERT/UPDATE/DELETE policies, so only the Edge Function's service role can fill them. The CRM therefore cannot drift out of step with what you billed.
Customers are linked by stripeCustomerId. Anyone without one keeps their manual
billing fields and is labelled Tracked manually — deliberately not styled as
unpaid, because "we don't bill them through Stripe" and "they haven't paid" are
very different things.
sk_live_ secret key — it can move money.STRIPE_SECRET_KEY.supabase/stripe.sql in the SQL Editor.index.html):
npx supabase login
npx supabase functions deploy stripe-sync --project-ref xfczbofrfsgumeicjuoy
login opens a browser once. JWT verification is switched off for this
function in supabase/config.toml — Stripe signs
webhooks with stripe-signature, not a Supabase JWT, so the platform gate
would reject every event before the code ran. The function does its own
checks instead: signature verification on webhooks, admin role on backfill.https://<ref>.supabase.co/functions/v1/stripe-sync). Subscribe to
invoice.paid, invoice.payment_failed, invoice.finalized, invoice.updated,
invoice.voided, customer.subscription.created/updated/deleted.whsec_… → Supabase secret STRIPE_WEBHOOK_SECRET.
Until this is set the function rejects webhooks — without signature verification
anyone could POST a fake "paid" event.Unmatched invoices (Stripe customers with no CRM counterpart) are listed in Admin → Stripe. The function auto-links by email once, then remembers.
Admin → Data & Backup exports the whole database as JSON and restores it, in either mode. Because record ids are plain text and carry across, a backup taken from the offline version imports straight into Supabase with its ids intact — that's the migration path if you've already entered real data locally.
Customers, vendors and billing also export to CSV.
js/backend.js is an adapter with two implementations behind one interface; js/store.js
keeps a synchronous in-memory cache either way — hydrate once at boot, write through on
every change, fold teammates' realtime changes back in. That's why moving from localStorage
to Postgres needed no changes to any view file.
/ — focus global search (customers, vendors, work orders, note bodies)Ctrl+Shift+N — quick createCtrl+Enter — post a noteEsc — close a dialogindex.html shell: topbar, nav rail, overlay roots
css/app.css design tokens from the brand guide + all components
assets/ logo mark (SVG)
js/store.js schema, seed data, CRUD, audit trail ← the only persistence layer
js/ui.js rendering primitives: tables, badges, modals, notes, timeline
js/app.js hash router, global search, user switcher, shortcuts
js/views/ one file per screen