Lalabase
티켓·문서·근무시간·고객대화를 한 곳에 모아 KI로 검색, 소프트웨어 기업 고객 프로젝트용, 오픈소스로 자체 서버·독일 클라우드에 배포
EDOSPMIS 구매 요청부터 결제 및 마감까지 전 과정 관리
Requisition, approval, sourcing, award, delivery, inspection, three-way match, payment and close-out — one case, one timeline, one audit trail. Built in Kenya.
비즈니스TypeScript · PLpgSQLGitHub @edoscentre-coder온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Enterprise Procurement, Workflow, Queue and Service Delivery Management
Platform — multi-tenant SaaS. See PRD.md and
ARCHITECTURE.md for the full product and technical
blueprint; this file only covers running what's built so far.
Phase 1 — Platform Foundation: implemented.README 전문 보기 ↗Enterprise Procurement, Workflow, Queue and Service Delivery Management Platform — multi-tenant SaaS. See PRD.md and ARCHITECTURE.md for the full product and technical blueprint; this file only covers running what's built so far.
Phase 1 — Platform Foundation: implemented.
edospmis_provision_tenant, one transaction: tenant row, membership,
a starter set of 10 tenant-scoped roles seeded from the PRD's persona
list, Tenant Administrator assignment).legal.contract.*,
seeded ahead of the module itself — see below), tenant-scoped custom
roles, a Roles admin screen (create a role, toggle its permissions by
category, delete an unused custom role — system roles are read-only)./update-password is where they land after
accepting), change their role, suspend/reactivate.edospmis_audit_logs) — every invite, role change, role
permission change, suspension and tenant-provisioning event is written
here; nothing updates or deletes an existing row.Phase 2 — Case + PR + Workflow + Queue + Approval + SLA (MVP): implemented.
PR-{year}-{seq} — default as of
migration 0031_pr_numbering_format, tenant-configurable in Settings >
Organization, atomically sequenced), and is submitted for approval from
the Case detail page. The Case entity and case_id FK are unchanged —
only the displayed/stored number string moved from CASE- to PR-, to
match the "PR No." label used everywhere in the UI.draft → approval → approved workflow is
seeded per tenant, versioned and stored as data (edospmis_workflow_versions.definition)
so the Case detail chevron (WorkflowStepper) reads real stage labels —
see ARCHITECTURE.md §1.2/§4.2 for the scope cut (procedural, not a fully
generic interpreter yet).edospmis_submit_pr and
edospmis_decide_approval run the chain as single atomic transactions.0004_admin_holds_dept_manager.sql.Phase 3 — Procurement + Legal/Contract Provisioning: implemented (v1 cuts).
procurement.rfq.create), which opens an RFQ seeded
from the PR's own items. From the Case detail page's Procurement panel:
invite suppliers, record what they quoted, and award — issuing a PO
(PO-2026-000001, derived from the case number) and moving the case to
Awarded. Suppliers get their own admin screen, same pattern as Clients.Phase 4 — Fulfilment: implemented (v1 cuts).
GRN-2026-000001
off the case number (-01, -02, ... for partial/repeat receipts). The
case moves to Receiving on the first GRN.receiving.grn.approve records one pass/fail/
conditional outcome per GRN, with comments and a free-text evidence
reference — no file upload yet (see the migration header), so a report
number or photo filename stands in for an attached document.procurement.case.close and the case not already being in a terminal
state — deliberately not hard-blocked on "delivery confirmed", since a
case can legitimately end without one (a services-only PR, a client
collecting in person). The Case detail screen nudges toward closing after
delivery confirms; it never refuses the button.Draft › Approval › Approved › Procurement › Awarded › Receiving › Delivery › Completed — Finance is Phase 5, not in this chevron yet).
Existing tenants' default workflow was also given this fuller stage list
via a new workflow version, so this applies to their next case too, not
only brand-new tenants.Phase 5 — Finance + Advanced Controls: implemented (v1 cuts).
edospmis_decide_approval now honours an active
delegation the same way it honours directly holding the role, drawing
the permission from the delegated role itself so the delegate doesn't
need to separately hold it. Delegating and revoking are both audited.finance stage. One
real design bug was caught and fixed during this pass: delegation was
only granted routing authority, not the underlying permission check, so
a delegate with no independent grant on the delegated permission could
never actually act — fixed by drawing the permission from the delegated
role rather than the acting user's own role set.Flow Alignment — implemented. A real client's own turnaround-time export (SAP Business One PR/PO/GRPO day-counts) and their target 12-stage procure-to-pay diagram were audited against the build above; this closed the gaps that came out of it, fitted additively rather than as a rework:
edospmis_case_stage_history): a database trigger
on edospmis_cases — not a call threaded through every RPC — opens a
stage row on creation and closes/reopens one on every status change,
automatically, for every past and future write path. This is the exact
"days from X to Y" metric the client's Excel report computes by hand,
now live per case. The Case detail page shows it as "Time in each
stage", and the current stage's SLA (if the tenant has configured one
for it — edospmis_sla_policies was always generic per stage, only
approval ever had a row) shows a live breach/warning status the same
way approval SLA already did.requires_po_approval,
off by default) between Procurement and Awarded — the client's data
proved this is a real, distinct step (PO Created ≠ PO Approved dates)
that most tenants don't need. Reuses a procurement.po.approve
permission that had existed in the catalogue, unused, since Phase 1.cancelled status has existed since Phase 2 with
no path to reach it; closed with one RPC + button, reusing the
procurement.pr.cancel permission (also unused since Phase 1).Phase 6 — Reporting/Analytics: implemented (v1 cuts).
reports.view, already granted to several roles
since Phase 1 and never used until now): open requests by age, time
spent in each stage plus how many cases are sitting in each one right
now (a live bottleneck view), approval SLA compliance, supplier
performance (spend, GRN acceptance rate, average lead time from award to
first receipt), and spend by category.case_stage_history from Flow Alignment, workflow_tasks, GRNs/
GRN items, POs, PRs/categories). Nothing is scheduled or pre-computed;
each report runs live.department_id exists on cases/PRs but nothing sets it yet, while
category_id is populated on every PR and, since the flow-alignment
audit, reflects each tenant's real vocabulary instead of a generic
placeholder.edos.ai — implemented. The same assistant every EDOS Centre sibling app (edos-poa, edoshatch360) ships, brought to EDOSPMIS:
src/lib/ai/llm.ts)
— the model never touches the database. Each tool (src/lib/ai/tools.ts)
is a query already scoped to the signed-in tenant: open-request aging,
stage cycle times/bottlenecks, SLA compliance, supplier performance,
spend by category, "what's waiting on me", case lookup and full case
detail, supplier lookup, and a contracts overview. The model decides
which to call and phrases the answer, but can't quote a figure this
tenant's own data doesn't hold, because no tool returns one that isn't
there.ANTHROPIC_API_KEY; without one, edos.ai says so
plainly and points at the Reports screen instead of guessing. This
deliberately does not replicate the sibling apps' deterministic
natural-language fallback ("answers of last resort" without a model
configured) — real, separate work; matching its full breadth wasn't
needed to bring the same assistant to this product.user_id = auth.uid(), like everything else in this app) rather than
copying edos-poa's differing "RLS on, no policies, service-role only"
arrangement — consistency within this codebase over matching a
sibling's internal choice.Phase 7 — Integrations: implemented (v1 cuts).
edospmis_audit_logs (one event pipeline, two consumers, per
ARCHITECTURE.md §14 — the same log every RPC since Phase 1 already
writes to, not a new parallel events table) dispatches a signed POST via
pg_net for every matching action, tenant-wide, automatically, with no
changes needed to any existing RPC. Each payload carries an
X-EDOSPMIS-Signature: sha256=<hex> HMAC over the raw body, and a
Settings screen shows recent deliveries with an on-demand status check
(reads net._http_response). A misconfigured endpoint can never break
the transaction that produced the event — the trigger swallows its own
dispatch errors per webhook.httpbin.org, which echoes back exactly what it received): a genuine
HTTPS POST left Supabase's infrastructure via pg_net, and the HMAC
signature independently recomputed from the raw bytes that endpoint
actually received matched exactly — the one subtlety worth flagging for
anyone verifying a delivery themselves: hash the raw request body, never
a reparsed-and-reserialized copy of it, the same rule Stripe/GitHub
document for their own webhook signatures. Also verified: non-https://
endpoints rejected, a paused webhook receiving no further deliveries,
and deletion.finance stage
no longer sits empty in the demo's own stage-timing report.Not yet built (later phases, see ARCHITECTURE.md §18): the rest of Phase 8's AI scope (PR classification, spec extraction, duplicate detection, SLA-breach prediction — PRD FR-39). Also not yet built: the Platform Super Admin role (cross-tenant oversight for EDOS Centre as the SaaS operator) — every account today is scoped to one tenant only, by design, with no back door across tenants.
A persistent, read-only demo tenant for onboarders to explore without signing up or risking real tenant data:
[email protected] / AmaniDemo2026!procurement.pr.view, legal.contract.view, reports.view,
admin.audit.view — no create/edit/approve/close permissions anywhere),
so every write action across the app is correctly refused if attempted;
nothing an onboarder does can corrupt the shared demo data. It was
seeded by first provisioning the tenant normally (temporarily Tenant
Administrator, so every seeded record was created through the same real
RPCs a genuine user would call — not hand-crafted rows) and only
stripping the account down to Demo Viewer once seeding finished.src/lib/nav-items.ts) — the demo account sees "My Work" and
"Requests" (its own 9 seeded cases) and "Contracts"; the admin/config
screens (Users, Roles, Suppliers, Clients, Approval Rules) require a
.manage permission the demo role deliberately doesn't hold, so they're
hidden rather than shown-but-broken.Next.js (App Router) + TypeScript + Tailwind v4, Supabase (Postgres + Auth + Storage), deployed to Vercel — see ARCHITECTURE.md §13 for why.
This app's tables all live in the same shared Supabase project as EDOS
Centre's other products (edospoa_, edoshatch360_ prefixes), under the
edospmis_ prefix — see ARCHITECTURE.md §2.
npm install
cp .env.example .env.local # fill in the Supabase project's URL/keys
npm run dev
Required env vars are documented in .env.example. The service-role key
is only needed for tenant sign-up's admin-invite path and inbound
webhooks (see src/lib/supabase/admin.ts) — never used from a page or
component.
Migrations live in supabase/migrations/, applied directly against the
shared project (no local Supabase stack is run for this app currently —
see MULTI_TENANCY.md, a Phase 1 documentation deliverable, for the
full reasoning once written).
0001_platform_foundation.sql — Phase 1: org structure, users,
memberships, RBAC, audit log, edospmis_provision_tenant().0002_legal_contract_rbac.sql — forward-seeds the Phase 3 Lawyer/Advocate
role and legal.contract.* permissions (module itself not built yet).0003_phase2_case_pr_workflow.sql — Phase 2: cases, PRs, workflow/queue/
approval/SLA tables, edospmis_submit_pr(), edospmis_decide_approval().0004_admin_holds_dept_manager.sql — fixes a gap the pre-commit smoke
test caught: the founding admin now also holds Department Manager so
the seeded default approval rule is immediately actionable solo.0005_phase3_procurement.sql — Phase 3a: suppliers, RFQs, quotations,
evaluations, purchase orders, edospmis_start_procurement(),
edospmis_award_po(); extends the case lifecycle past "approved".0006_phase3_contracts_v1.sql — Phase 3b: contracts + signing parties
(v1 cut — see the migration header), edospmis_send_contract(),
edospmis_record_contract_signature(), edospmis_void_contract().npx tsc --noEmit, npx eslint ., npm run build — all three gate
every change; npm run build specifically catches the "server-only
imported from a client component" class of bug that tsc alone misses.
A dedicated tenant-isolation test suite (ARCHITECTURE.md §17) is a
near-term follow-up, not yet written.
src/
app/ Next.js App Router — auth pages, /app (the product), /auth/callback
components/
ui/ shared design-system primitives (Button, Card, Field, Badge, Spinner)
app/ app-shell components (sidebar/mobile nav)
lib/
data/ server-only data-access modules (session, rbac)
supabase/ client/server/admin Supabase client factories
audit.ts logAudit() — the one place anything writes to edospmis_audit_logs
supabase/migrations/
cancelled