Repo to the FastAPI of the OpenTaberna Project. See Wiki for more information.
Tooling
- Python 3.14
- uv package manager 0.4.0
- Docker
- Ruff 0.14.5
For code development use uv package manager. After installation go into the root directory of this repository and run:
uv syncTo start the API locally:
source .venv/bin/activate
python3 src/app/main.pyTo test the Setup:
Take a look at the docker-compose.dev.yml file. It provides a dev docker setup for local development. Run:
docker compose up -f docker-compose.dev.yml -dThis FastAPI can be build and tested via GitHub workflows. There are two available workflows:
- test.yml -> to test the API
- test-build-deploy.yml -> runs pytest for minor checks and builds the docker image.
This Pipeline is can be triggered either by merging a PR into main or run it manually in the Repository Action section.
The workflow tests for:
- System Integration
- Pytest
- Linter and Formatter
- Trivy checks dependencys
- Bandit to audit the code
All results are uploaded as Artifacts.
This workflow runs small pytests before it builds the docker image for the API. After a successful build the image gets pushed into the organizations docker registry. The last Job deploys the whole docker-compose.yml in the root directory to a Portainer instance.
The workflow can be triggerd by a tag on any commit:
git tag vX.X.X && git push origin vX.X.XCaution
The workflow only tells if a deployment started on portainer. It can not detect if the API container or any other container fails on start as long as the container gets marked as "running".
flowchart TD
A[Customer views product] --> B[Add to cart]
B --> C[Start checkout]
C --> D[Create Order: DRAFT]
D --> E["Reserve inventory (StockReservation)"]
E -->|insufficient stock| E1[Reject / show out of stock]
E -->|ok| F["Create Payment Session/Intent (PSP)"]
F --> G[Customer completes payment on PSP]
G --> H[PSP sends Webhook: payment_succeeded / payment_failed]
H --> I{"Webhook verified + idempotent?"}
I -->|duplicate| I1["Return 200 OK (no-op)"]
I -->|new| J[DB txn: Payment=SUCCEEDED]
J --> K[Order status -> PAID]
K --> L[Commit inventory: decrement on_hand + release reservation]
L --> M[Enqueue fulfillment job: CREATE_LABEL]
M --> N["Worker calls Carrier API (e.g. DHL)"]
N --> O{"Label created?"}
O -->|no| O1[Retry/backoff + alert admin]
O -->|yes| P[Shipment: tracking + label stored]
P --> Q[Order status -> READY_TO_SHIP]
Q --> R["Admin pick & pack with packing slip"]
R --> S[Hand over to carrier / pickup scan]
S --> T[Order status -> SHIPPED]
T --> U[Send tracking email to customer]
H -->|payment_failed| V[Payment=FAILED]
V --> W[Order status -> CANCELLED]
W --> X[Release reservation]
- Core domain + DB schema
- Product/SKU, Inventory, Order, OrderItem, Customer, Address
- Order state machine
- DRAFT → PENDING_PAYMENT → PAID → READY_TO_SHIP → SHIPPED
- PENDING_PAYMENT → CANCELLED (timeout / failed)
- Idempotency & constraints
- Unique constraints for “one shipment label per order”
- Event inbox table (dedupe webhook events)
- Cart + Checkout draft API
- Create draft order and line items with price snapshots
- Inventory reservations
- Reserve on checkout start; expiry + cleanup job
- Payment provider integration (PSP)
- Create payment session/intent; store provider reference
- Webhook endpoint (authoritative payment confirmation)
- Signature verification
- Idempotent processing
- Transactional transition to PAID + commit inventory
- Admin order list + detail
- Filter by status: PAID / READY_TO_SHIP / SHIPPED
- Pick/pack documents
- Packing slip + pick list (PDF optional, HTML fine initially)
- Manual shipment marking
- Admin enters tracking number manually
- Customer notification email
(At this point you have a working webshop that can get paid, manage stock correctly, and ship manually.)
- Background job system
- Worker + queue; retry/backoff; dead-letter + alerts
- Carrier abstraction layer
- CarrierAdapter.create_label(order) interface
- DHL adapter
- Create label, store PDF/ZPL, tracking number
- Admin label printing + shipment workflow
- “Create label” / “Recreate label” rules
- Print label + packing slip from admin
-
Outbox pattern for reliable job enqueueing
-
Observability
- Structured logs, correlation IDs, metrics
- Fraud/edge-case handling
- Payment reversals/refunds → inventory & order adjustments
-
Returns + refunds (basic RMA)
-
Partial fulfillment / split shipments (optional, later)
- Webhook-driven payment confirmation
- Reservation-based inventory
- Admin pick/pack + manual tracking
- Then add DHL labels