Synaplan
기업을 위한 오픈소스 AI 플랫폼
자동 3D 프린트 팜을 위한 전 과정 관리: 견적·발주·출력·배송, FastAPI·PostgreSQL·React·Bambu Lab 사용
End-to-end management for an automated 3D print farm: quote, dispatch, print, ship. FastAPI · PostgreSQL · React · Bambu Lab
비즈니스Python · TypeScriptGitHub @iritur온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A customer-facing configurator with transparent pricing, automatic printer assignment
and dispatch, and farm-floor operations — for an automated 3D print farm, Bambu Lab
first.
Stack: Python / FastAPI / PostgreSQL on the farm LAN · two React SPAs — a storefront
on internet hosting and a farm console on the LAN
(ADR-0016).
run_console.bat adds the farm console on :5174, reusing anything already up.
run_design.bat serves the static design kit on :4180.README 전문 보기 ↗A customer-facing configurator with transparent pricing, automatic printer assignment and dispatch, and farm-floor operations — for an automated 3D print farm, Bambu Lab first.
Stack: Python / FastAPI / PostgreSQL on the farm LAN · two React SPAs — a storefront on internet hosting and a farm console on the LAN (ADR-0016).
run_web.bat # database, API, workers, storefront on :5173
run_console.bat adds the farm console on :5174, reusing anything already up.
run_design.bat serves the static design kit on :4180.
[!TIP] First-time setup — virtualenv, npm install, migrations — is in docs/DEVELOPMENT.md. Standing the stack up on a real host for the first time is docs/RUNBOOK-FIRST-BOOT.md.
flowchart TB
WEB["storefront SPA<br/>catalogue · configurator · checkout · account"]
subgraph lan["Farm LAN"]
direction TB
CON["console SPA<br/>orders · prep · fleet · materials · journal"]
API["API<br/>one process, one domain model"]
WK["workers<br/>six sweep loops"]
PG[("PostgreSQL")]
RD[("Redis")]
PRN["printers<br/>bambu · manual · mock"]
end
WEB -->|HTTPS| API
CON -->|same-origin /api| API
API -.->|WebSocket| CON
API --> PG
WK --> PG
API <-->|event relay| RD
WK <-->|event relay| RD
WK -->|MQTT over TLS · FTPS| PRN
The API and the workers are separate containers with an in-process bus each, so
everything a sweep raises reaches a watching console through the Redis relay
(core/relay.py). Without it those events die in the worker and the boards go quiet —
which is why the release gate proves the relay rather than trusting it. What crosses
that WebSocket is an invalidation, never state
(ADR-0015): the console is
told what went stale and asks for it, so a dropped frame costs a refetch rather than
leaving two screens quietly disagreeing.
| Rule | Held up by | |
|---|---|---|
| 1 | One backend, one database, one domain model. No mirrored entities, no sync layer. | an import-linter contract |
| 2 | One pricing engine — a pure deterministic function. Transparent breakdowns and per-option price deltas fall out of it for free. | ADR-0002 |
| 3 | Drivers never simulate silently. A disconnected printer reports Offline and raises an alert. It never invents data. | a driver interface with no fallback path |
| 4 | A feature is done only when a test proves it. Status docs say works / scaffolded / stubbed. | a CI gate |
Each is enforced structurally rather than by care. See docs/adr/ for why each one is worth that.
[!IMPORTANT] Rule 3 generalises past drivers: a null reading is "not measured", not
0. An hour with no telemetry is not an idle hour, an unknown id must 404 rather than answer an empty grid, and a denominator must be what was observed — never the roster. Otherwise the worse the coverage, the healthier the farm looks, and the error is silent and flattering.
Two of them exist because reality demanded them: prep, where a human slices before
anything can be dispatched (ADR-0006), and
price_review, where the sliced truth exceeded the quote beyond tolerance and the order
is held for a decision rather than silently costing the farm money or silently
overcharging the customer (ADR-0013).
stateDiagram-v2
direction LR
[*] --> draft
draft --> awaiting_payment
awaiting_payment --> paid
paid --> prep: needs slicing
paid --> queued: prepared plate cached
prep --> price_review: over tolerance
prep --> queued
price_review --> queued
queued --> printing
printing --> queued: remake
printing --> post_production
post_production --> quality_check
quality_check --> post_production: finish again
quality_check --> queued: reprint
quality_check --> packing
packing --> shipped
shipped --> completed
completed --> [*]
cancelled is reachable only from draft and awaiting_payment; refunded from
paid through post_production. Anything outside the table is a bug rather than a
business decision, and is refused loudly rather than half-applied —
contexts/ordering/policies.py.
Working on this with an AI agent? CLAUDE.md carries the rules that hold everywhere, with the area-specific ones beside the code they govern — backend/CLAUDE.md and frontend/CLAUDE.md, so a session only loads what it needs. HANDOFF.md carries the current state: what just changed, what is deliberately unfinished, and what needs a person rather than an agent.
Open work is in issues, grouped by milestone and described in docs/WORKFLOW.md. The documents below say what the system is; the tracker says what is missing, and only the tracker says it.
| Document | What it covers |
|---|---|
| docs/WORKFLOW.md | How the issue tracker is used — labels, milestones, and what closes an issue |
| printorian_scenario.txt | The product scenario — source of truth for requirements |
| docs/ANALYSIS.md | What the scenario requires, decomposed into capabilities with the difficulty named |
| docs/ARCHITECTURE.md | Locked decisions, module map, pricing engine, scheduler, drivers, governance |
| docs/ROADMAP.md | Phase plan with exit criteria and risks |
| docs/adr/ | 21 locked decisions, each with the problem that motivated it |
| docs/GLOSSARY.md | One agreed name per concept, RU / EN |
| docs/DEVELOPMENT.md | Setup, daily commands, the CI gates |
| docs/DATABASE-REVIEW.md | Schema by context, indexing, partitioning, and the accepted trade-offs |
| docs/SECURITY-REVIEW.md | A read of the money path and the unauthenticated entry points — what was fixed, what is waiting on a person |
backend/
printorian/core/ config, Money, units, ids, clock, errors, events, db
cpu (blocking work, off the loop) · relay (events across
processes) · ratelimit · heartbeat · secrets · storage
printorian/contexts/ account · catalog · fleet · identity · inventory · journal
ordering · packaging · payments · postproduction · pricing
production · scheduling · settings
printorian/drivers/ printer adapters — bambu, manual, mock
printorian/workers/ scheduler · telemetry · sla · postproduction · packaging ·
maintenance — each beats at the end of every pass
printorian/api/ thin HTTP layer; authorization enforced here
tools/ governance gates, OpenAPI export, Bambu spike
frontend/
apps/web/ storefront — catalogue, configurator, checkout, journal
apps/console/ farm console — orders, prep, library, journal, fleet,
materials, users, settings
packages/ui/ Harvester design system, RU/EN catalogues, DataTable
packages/api-client/ generated from OpenAPI — never hand-edited
packages/events/ the WebSocket event stream both apps subscribe to
deploy/ production compose and the Caddyfile the release gate runs
design/ the static design kit the UI is built against
Built and working end to end: pricing engine and quote/preview API · STL analysis and the model catalogue with staff curation · inventory with AMS-slot locations · the storefront configurator, checkout with delivery and payment, order tracking with the nine-stage pipeline and queue position, and the customer account — profile, loyalty ladder, addresses, uploads, receipts and sessions · the farm console · the journal with an RSS feed · fleet, production, scheduling and the virtual farm harness · the settings screen, with write-only encrypted secrets and an audited «было · стало» per save · one-image containers with a release gate (INFRASTRUCTURE Stage 1).
[!WARNING] Two things are not proven, and both need hardware or an account this repository cannot supply.
- The Bambu LAN spike ran against a real X2D and its findings are the specification Phase 3 builds from — telemetry and control proven, the FTPS write still pending storage in the test machine (docs/BAMBU-LAN-PROTOCOL.md).
- Payments run against the
mockandmanualproviders. The YooKassa adapter exists but has never been exercised against the real gateway in test mode, which is what Phase 2's exit criterion asks for.
[!NOTE] HANDOFF.md is the live status — test counts, what landed last, and what is next, each verified against the code rather than read off a plan. Prefer it to any summary here: this section is the shape, that one is the state.
Three jobs, and the third is the one that matters.
backend — six governance gates before a single test runs, so a structural
regression fails fast and unambiguously: ruff check, ruff format --check,
mypy --strict, lint-imports, context isolation, file length. Then tests on a real
PostgreSQL (ADR-0021), migrations applied
from scratch, and alembic check — the models and the migrations cannot drift.
frontend — the API client is generated from the schema the backend job exported, never committed (ADR-0005). That is what makes a breaking backend change fail the build at the commit that caused it, rather than in somebody's editor a week later.
image — the two jobs above test the source tree. Nothing there proves the thing
that actually ships works: a missing system library, a wrong entrypoint, a migration
that only runs with a dev dependency present, a base image that moved underneath us.
So this job builds the images and then runs them, against the same
deploy/compose.prod.yml the farm uses — migrations forwards, backwards and forwards
again; readiness reporting its dependencies; the console's same-origin proxy; every
worker loop proven to be sweeping rather than merely running; and a live event raised
in one container proven to reach the other. Only then does it scan, SBOM, push and sign
(cosign keyless, via the job's OIDC identity — no key to store, rotate or lose).
core/cpu.py runs that work in a bounded thread
pool, and carries the measurements that make it a bug rather than a preference.POST /pricing/quote takes an
optional actor and parses a mesh, so it is rate-limited; sign-in has a lockout;
request bodies are refused by size before anything buffers them.python -m printorian.workers --check is the container's healthcheck
— a process check that cannot tell working from wedged is worse than none.VIEW_FINANCIALS is kept separate from
every production permission, so a response carrying seconds cannot quietly start
carrying rubles or kilowatt-hours.Next: docs/ROADMAP.md for the phase plan · docs/INFRASTRUCTURE.md for deployment Stage 2 onwards
| docs/DESIGN-KIT.md | Which of the twenty-one kit screens exist, and what the unbuilt ones would need |
| docs/INFRASTRUCTURE.md | Containers, release gate, deployment stages |
| docs/RUNBOOK-FIRST-BOOT.md | Standing the stack up on a real host, and the pre-flight that fails early |
| docs/RUNBOOK-BACKUP-RESTORE.md | WAL archiving, base backups, the restore drill |
| docs/RUNBOOK-PAYMENTS.md | YooKassa and T-Pay: method selection, demo-store vs live-store testing, test cards |
| docs/RUNBOOK-FIRST-PRINT.md | Proving the driver against a real printer — the largest unproven assumption in the system |
| docs/BAMBU-LAN-PROTOCOL.md | Spike findings from a real printer — the spec the Phase 3 driver is built from |
| docs/PROPOSITIONS-ECOSYSTEM.md | Dated argument for what to adopt from the Klipper ecosystem — reasoning only, to be triaged into issues |