FloCafe
FloCafe는 구독 없이 무료로 주문·테이블·주방 디스플레이·로컬 데이터를 관리하는 로컬 퍼스트 레스토랑 POS입니다
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A returns and reverse-logistics centre for an e-commerce business. A customer asks to return an item, an agent picks it up, the warehouse checks it in, QC grades it A/B/C, and the item is restocked, refurbished or scrapped. Then the refund is worked out to the rupee.
Built with Flask (Blueprints), Jinja2, SQLite through Flask-SQLAlchemy, and pytest. The frontend is plain CSS and vanilla ES modules: Three.js r160 for the 3D scenes, GSAP 3.12 with ScrollTrigger on the landing page, and Chart.js on the admin dashboard. All of them load from CDNs. There is no npm and no build step.
pip install -r requirements.txt && python seed.py && python app.py
Then open http://127.0.0.1:5000. Python 3.10 or newer is required.
python seed.py deletes the database and rebuilds it with demo data. Run it again any time you want a clean demo.python -m pytest.The "Switch role" menu in the top bar stores a role and a user id in the session. The same choice is on the /switch page, which the landing page's "Staff entry" button opens. "Start a return" signs you in as the first customer. If you open a page that belongs to another role, you get a friendly 403 page with a one-click switch. You rarely need the menu, though: after each step the app hands the return to the next desk for you (see below).
| Role | Seeded people | Pages |
|---|---|---|
| Customer | Chirag | /customer/orders, /customer/return/new?item=ID, /customer/return/<code>/schedule, /customer/returns, /customer/return/<code> (tracking) |
| Pickup agent | Ayush Dubey | /agent/pickups, /agent/pickup/<id> |
| Warehouse manager | Ansuman Singh | /warehouse/receive, /warehouse/inventory |
| QC inspector | Aadi Srivastava | /qc/queue, /qc/inspect/<code> |
| Refurbisher | Anumeet | /refurb/jobs |
| Admin | Aryan Singh | /admin/dashboard |
| Anyone | / (landing page), /switch, /ppt (presentation), /docs (documentation), /team (the crew), /maker (who built it) | |
| API (customer only) | /api/return/<code>/status |
After anyone finishes their part of a return, a handoff card slides up: Your part is done, what just happened, who is next and what they'll do, and a strip of all six desks (done, next, skipped). Continue as … switches to that person and opens the exact item waiting for them: the agent's pickup slip, the QC inspection form, or the highlighted row on the warehouse dock or repair bench. The relay runs Customer → Pickup agent → Warehouse → QC → (Refurbisher → QC again, grade B only) → Customer, who confirms the refund and closes the return → Admin, where a Loop complete card offers Start another return.
If the card is closed, the same Continue as … button is still around:
The rules for who is next live in next_desk() in services/handoff.py. The card shows once, right after the action; switching by hand through the menu drops it.
All the numbers live in config.py, each with a comment. All the logic lives in services/.
| Rule | Value | Where |
|---|---|---|
| Return window | 7 days from delivered_at, counted in whole days (delivered on the 1st, returnable until the end of the 8th) | RETURN_WINDOW_DAYS, services/eligibility.py |
| Not eligible when | outside the window, the product is not returnable, or the item already has a return that isn't cancelled | services/eligibility.py |
| Grade A | 100% refund, item restocked | GRADE_REFUND_PERCENT, GRADE_ROUTE |
| Grade B | sent to refurbishing. If the repair passes re-inspection, the item is restocked and the refund is 70%. If it fails, the item becomes grade C | services/returns.py |
| Grade C | 0% refund, item scrapped | |
| Damaged / wrong-item exception | 100% refund whatever the grade, if QC confirms the claim (visible damage for "Damaged", item doesn't match the order for "Wrong item"). The item is still routed by its grade | FULL_REFUND_REASONS, services/refund.py |
| Pickup fee | ₹50, deducted only for "Changed my mind" | PICKUP_FEE |
| Refund formula | final = max(0, base × grade% − pickup fee), with every part stored | services/refund.py |
| Pickup attempts | 2. The first "customer absent" rebooks the pickup for the next day in the same slot; the second cancels the return and records why | MAX_PICKUP_ATTEMPTS |
| Frequent returner | more than 3 return requests in 30 days. Shown to the admin; the customer is never blocked | FREQUENT_RETURN_LIMIT, services/flags.py |
| Suspected fraud | QC unticks "item matches order" on a return whose reason isn't "Wrong item": the return is rejected and flagged_fraud is set | services/returns.py |
| Refund atomicity | the refund row, the inventory_log row and the move to "Refunded" are committed in one transaction. refunds.return_id is unique, so a second refund is impossible | services/refund.py |
| Status changes | only through in , which checks the move against the transition table, writes and updates |
Run python seed.py (or reset.bat) first so the codes below match.
What the seed contains. One customer, Chirag, with 12 delivered orders. 7 items are returnable; the others show Window closed or Not returnable, which is handy for explaining the rules. Chirag also has 3 finished returns (RL-2026-0001 to 0003, closed or refunded) in My returns, so the admin charts and the warehouse inventory aren't empty. The Agent, Warehouse, QC and Refurbisher queues start empty: everything that appears there comes from returns you make as the customer, and each return shows up on a screen only when it is that role's turn.
/. Scroll through the 3D loop, the five-step "How a return flows" section, the three stamps and the numbers.The top-bar menu still switches to anyone at any time, if you'd rather jump around.
Other things to try:
/customer/return/RL-2026-9999. That code doesn't exist, so you get the 404 page. (Another customer's return gives the same 404; the tests check this.)Decisions I made where the spec was open:
returnloop/ folder is the repository root itself.config.STAFF. pickups.agent_id, qc_reports.inspector_id and refurbish_jobs.technician_id hold those ids.CUSTOMERS in seed.py and STAFF in config.py.app.py app factory, error pages, template filters
config.py settings and every business-rule constant
models.py the 11 tables
seed.py demo data, pushed through the real services
services/ all business logic (state machine, eligibility, refund, flags, workflow, handoff)
blueprints/ thin route handlers, one per role, plus the API
templates/ Jinja templates (base, macros, handoff card, landing, one folder per role)
static/css/ main.css (design system) and motion.css (animations, reduced motion)
static/js/ main.js, cursor, tilt, transitions, scenes/ (3D), fx/ (stamp, burst, counters), lib/webgl.js
tests/ pytest suite
docs/ ER diagram and UML mapping
/ppt (the PPT link in the top bar) is an 18-slide deck about the project from a software engineering point of view: project planning & management (vision, scope, incremental process, risks), functional and non-functional requirements, use case diagram, class diagram, DFD level 0 and level 1, activity diagram, two sequence diagrams (QC grade and refund; handing a return to the next desk), state diagram, layered architecture, and the path of one click from the UI down to the database. Use the arrow keys, click or swipe to move; Present (or F) goes full screen; Save as PDF prints one slide per page. A ready copy is in docs/ReturnLoop-presentation.pdf. The diagrams are drawn by Mermaid (loaded from jsdelivr) except the use case and activity diagrams, which are hand-drawn SVG.
/docs (the Docs link in the top bar, between PPT and Team) is the project's software requirements & design document, in the site's paper-and-ink style with no animation: introduction and scope, functional and non-functional requirements, the use case, activity, swimlane, class, CRC, DFD (level 0 and 1), state and sequence diagrams, then UI design: a workplace for every desk, wireframes and prototypes. It is versioned, with a revision history under the contents. Download PDF gives a ready A4 copy (static/docs/ReturnLoop-Documentation.pdf); Print prints the page itself on A4.
The diagrams are plain SVG in the page, so it loads no diagram library. The requirements and the use case, activity and state diagrams are shared with the presentation (templates/_spec.html, templates/diagrams/), so the two never disagree. The class, DFD and sequence diagrams are the presentation's Mermaid drawings saved as static SVG. The prototype screenshots live in static/docs/proto/.
After changing the app, the docs or the deck, refresh everything the documentation shows with one command. It runs its own copy of the app on a throwaway database (your returnloop.db is never touched), re-saves the Mermaid diagrams, retakes every prototype screenshot and rebuilds both PDFs:
pip install playwright
python tools/refresh_docs.py
To rebuild only the PDFs from an app that's already running, use python tools/make_pdfs.py --base http://127.0.0.1:5000. The QR code on the cover opens config.PUBLIC_URL; if the live address changes, run python tools/make_qr.py (needs pip install segno) and then refresh_docs.py.
When you publish a new version, add a row to revisions at the top of templates/docs.html; the cover and footer pick up the latest one.
/team (the Team link in the top bar, for every role) introduces Chirag Seervi, Anshuman Singh, Aryan Singh and Aadi Srivastava. Up to 9,000 particles (3,600 on phones, fewer on low-power machines) start as a knotted loop. As you scroll they burst apart and re-form into each member's first name, and end as interlocked rings, one per member. Your cursor (or finger) parts and swirls the particles around it, and clicking (or tapping) the page or a member's stamp shakes them loose. The morphing runs in a vertex shader on the GPU. Each member has a "crew manifest" card with a departure-board name scramble. Names and roles live in config.TEAM; edit them there. The page and the particle scene adapt to however many members are listed.
prefers-reduced-motion turns off particles, parallax, tilt, page transitions, shakes and the stamp animation. The 3D scenes then draw single still frames.lib/webgl.js. It checks WebGL support, caps the pixel ratio (1.75 desktop, 1.25 mobile), pauses when the canvas is off-screen or the tab is hidden, halves the particles if the frame rate stays under 40 fps for 2 seconds, and disposes everything on page exit.change_status()services/state_machine.pystatus_historyupdated_atstatic/uploads/ with random names.products.image_url holds a placeholder key such as placeholder:audio. Each category has an inline SVG line drawing.position: sticky with ScrollTrigger scrubbing, which behaves well on mobile. Lenis would only add risk there.services/returns.py (one function per workflow action), services/stats.py (dashboard and landing numbers), services/uploads.py (photo checks) and services/handoff.py (who is next, for the handoff card), so route handlers stay thin.