# DTF System - Project Context for AI Agents ## Purpose of this document Read this document before changing code, documentation, architecture, or scope. It is the current English source of truth for the project. It supersedes older decisions in `README.md`, `docs/historico/ESPECIFICACAO.md`, `schema.sql`, and the existing prototype code whenever they conflict. Update this file whenever the team makes a material product, process, or architecture decision. ## Project goal Build a DTF ordering and production-flow system for Dropstar/Altus. The current process is slow and manual: customers send artwork through WhatsApp, staff forward files, designers discover problems late, and production status is not visible outside the factory. The business has substantially more machine capacity than it currently uses. The goal is to let customers place DTF orders online, pay, send artwork, and follow production without making WhatsApp, shared folders, or manual handoffs the bottleneck. The customer-facing value is speed and clarity. The operations value is a traceable queue and fewer lost or manually handled orders. ## Current MVP scope The MVP must be delivered in **at most three weeks**. The target is a working online system, not factory-machine automation. ### Included - Dedicated DTF site/subdomain. - Existing Site DTF commercial rules and product experience. - Direct, resumable multipart file upload to Cloudflare R2. - Mercado Pago payment integration with signed and idempotent webhooks. - Freight quotation and charging at checkout. - Idempotent Tiny/Olist order integration and order traceability. - Online Kanban for production status and secure file download. - WhatsApp status notifications. - Private object storage, 30-day file retention, backups, and basic security. - Operator guidance for the factory team. ### Explicitly outside the three-week delivery - Automatic pre-flight validation. It will be validated after delivery using real customer files and real printed output, then refined as support work. - Direct FlexiPRINT integration. - Factory-side agent, hot folder, internal file server automation, VPN, and heartbeat monitoring. - Production-room dashboard, printer/machine telemetry, and advanced reports. - Automated shipping-label purchase, shipping-label printing, and dispatch automation. The MVP freight scope is quote selection and charging only. - Personalized cart behaviour based on past orders, day, or time. After delivery, the team provides support and evaluates requested changes. Do not turn post-delivery support into a new committed delivery phase without an explicit decision. ## Agreed production model ```text Customer browser -> Site DTF / API on VPS -> direct multipart upload to private Cloudflare R2 -> Mercado Pago payment + freight selected at checkout -> Tiny/Olist order record -> online Kanban -> factory operator downloads final file and imports it manually into FlexiPRINT ``` WhatsApp is a notification channel, not the artwork-upload channel. It is used for payment confirmation, correction requests, production status, and order completion. The operator works through the browser. The factory does not need an installed agent or an internal server for the MVP. If the factory internet connection fails, only the factory team temporarily loses access to the Kanban and secure downloads. The public portal, payments, uploads, R2 objects, queue, and cloud services remain online. Factory work resumes when local access returns. ## Infrastructure and deployment - **VPS:** runs the website, API, worker, PostgreSQL, ClamAV, Kanban, and third-party integrations. - **Cloudflare R2:** private S3-compatible object storage for original uploads and final files. It does not run the application, database, worker, or antivirus. - **Upload path:** the browser uploads directly to R2 using short-lived, server-issued presigned multipart URLs. Large files must never be proxied through the VPS. - **Deployment:** one Portainer-owned `dtf-cloud` Docker Swarm stack. One Gitea Actions workflow tests/scans, publishes `latest` plus commit-SHA application images, and calls the Portainer webhook. Activation remains blocked pending the production work listed below. - **Kanban access:** configure `OPERATOR_EMAIL` and `OPERATOR_PASSWORD` as stack environment variables. If the email is absent, only Kanban login is blocked; the rest of the stack remains available. - **Recommended VPS baseline:** 4 vCPU, 16 GB RAM, and 200 GB NVMe. Existing VPS capacity may be used if it safely meets or exceeds this baseline. - **Backups:** PostgreSQL backups go to R2. Application secrets are never committed to Git. ## File retention The business does not want an unlimited artwork library. | Artifact | Retention | |---|---:| | Incomplete multipart upload | 1 day | | Rejected or infected upload | 3 days | | Customer original after approval | Up to 7 days | | Final print artwork | Maximum 30 days from the first upload | | Order history and metrics | Kept in the database without keeping the image | The 30-day retention decision overrides older references to 90 days or 12-month artwork reordering. ## R2 planning cost reference R2 cost is driven primarily by the average number of gigabytes stored during a month; read/write operations are expected to be a much smaller cost at the project's scale. There is no egress charge in the current planning model. The client-facing roadmap uses the following planning examples, based on standard R2 storage pricing, the included storage allowance, and an exchange rate reference of USD 1 = BRL 5.13: | Average storage | Approx. R2/month | Approx. BRL/month | |---|---:|---:| | 100 GB | USD 1.35 | BRL 7 | | 500 GB | USD 7.35 | BRL 38 | | 1 TB | USD 14.85 | BRL 76 | | 3 TB | USD 44.85 | BRL 230 | These are planning estimates only. Confirm Cloudflare pricing, exchange rates, taxes, and payment-provider fees before presenting a commercial quote. ## Commercial rules The existing rules in `web/index.html` are approved as the current source of truth. Do **not** redesign, simplify, or change prices, discounts, minimums, rounding, or product modes without explicit approval. The current site contains four product modes, quality-based price tiers, artwork-ready discounts, separate assembly charges for loose artwork, a one-metre minimum, and ten-centimetre billing rounding. The browser may display the calculation, but production payment creation must recalculate and validate all price, quantity, freight, and discount values on the server. Client-provided totals are never authoritative. Normal JPG/PNG uploads are individual artwork by default, including when uploaded from the by-metre panel. They use the existing loose-artwork editor, printed width, quantity, and live packing canvas; packed height determines metres. Customers uploading an already assembled film-width image must explicitly select the ready-sheet option before uploading. PDF and manual-format ready sheets keep their existing workflow. These models retain their separate approved price tiers; image dimensions alone must never classify a normal artwork as a finished sheet. ## Freight The original visual freight flow in `web/index.html` was a stub with only pickup functional. The localhost bridge now supports pickup and backend fake freight quotes; there is still no real carrier quotation or production checkout. The customer already uses Correios and other shipping platforms. Before freight can be completed, obtain: - The platform(s) that should be used as the source of truth. - API credentials or delegated access for the selected platform. - Origin postal code/address. - Available services and carriers to offer. - Packaging weight and dimensions by DTF length/package. - Freight business policy: exact pass-through, subsidy, free-shipping rules, pickup, or other exceptions. At checkout, the backend must quote freight from the selected source, store the chosen service and quoted amount, include the amount in the Mercado Pago payment, and persist it in the order. Do not create a payment before the freight amount is final. ## Integrations ### Mercado Pago Required before production payment integration, not for the local mock milestone: - Production credentials. - Webhook configuration/access. Webhook processing must verify authenticity and be idempotent. A duplicate or late delivery must not create a duplicate payment, order, message, or queue card. ### Tiny/Olist Tiny/Olist is already available. The implementation must create/update orders idempotently and use the order number for traceability. Confirm the actual API endpoints, marker/tag behaviour, and rate limits before production use. ### WhatsApp WhatsApp is already available, but the technical provider still needs to be confirmed (official Meta Cloud API, Z-API, or another provider). Implement only the required customer events: 1. Payment approved. 2. Artwork correction needed, with a secure link back to the site. 3. Order entered production. 4. Order ready for collection or shipping. Messages initiated by the business may require approved templates depending on the provider and conversation state. Use an outbox/job mechanism with retries, delivery status handling, and idempotency. Do not send artwork through WhatsApp. ## Factory responsibilities after delivery The client/factory team is responsible for: - Opening the Kanban, downloading final files, and importing them manually into the current FlexiPRINT setup. - Performing real print tests and reporting mismatches in the final file or printed result. - Maintaining PCs, printers, FlexiPRINT licences, printing profiles, internal folders, and the local factory network. - Informing the development team about changes to prices, freight, operational rules, or external platforms that need system changes. The development team delivers the online system, provides usage guidance, and supports subsequent corrections or scoped enhancements. ## Three-week roadmap | Week | Delivery | Result | |---|---|---| | 1 | Infrastructure and upload | VPS, domain, database, R2, multipart upload, antivirus, and service foundation. | | 2 | Payment, freight, and order | Mercado Pago, freight quotation, idempotent Tiny/Olist order creation, final file generation, and main Kanban states. | | 3 | Kanban and handover | Online Kanban, secure download, WhatsApp status messages, 30-day retention, and operational handover. | ## Known implementation status ### Active localhost milestone (2026-09-15) The current implementation target is localhost before any production connection. Use `docker-compose.yml`, `.env.example`, and `LOCAL_SETUP.md`. The runtime is in `app/`; historical `portal/`, `kanban/`, `agente/`, and `schema.sql` are preserved as references and are not imported or started by Compose. - One local `dtf-cloud` Compose project runs seven long-lived services: Site and Kanban web gateways, FastAPI Portal/API, PostgreSQL, MinIO, ClamAV, and a PostgreSQL outbox/scanning worker. Separate database and storage initialization jobs provision restricted runtime identities, for nine Compose services total. - MinIO implements the S3 storage boundary with direct multipart browser uploads, resumable parts, private objects, and short-lived signed operator downloads. - Payment, freight, Tiny/Olist, and WhatsApp use fake adapters only. No production credentials or integrations are configured. The API and worker have no external network route; only local web/storage gateways publish loopback ports. - The original Site commercial calculation and appearance remain the source of truth. Its existing browser artwork analysis is retained as prototype advice; no new automatic pre-flight, server artwork analysis, or print-file generation is implemented or invoked. - Since client length and grade could be tampered with and automatic pre-flight is deferred, a local operator manually confirms those commercial inputs before checkout. This is a development trust-boundary decision, not a new production promise. The backend calculates all tiers, discounts, assembly-inclusive rates, one-metre minimum, ten-centimetre rounding, freight, and final totals. Immutable approved quotes expire after 24 hours. A customer confirms the server total on the Site to create one idempotent local paid order. - Paid orders use `rec`, `tra`, `fil`, `imp`, `cor`, `fin`, with allowed transitions, operator authentication, concurrency checks, and durable movement history. Local mock integration receipts are visible in the Kanban. - The customer portal at `/portal.html` supports local registration/login, stronger scrypt password hashing with legacy-hash upgrade, revocable HttpOnly sessions, owned order history/status, secure active file downloads, and correction uploads. Registration/login can claim only the current guest session's records, never orders found by email or CNPJ. Email verification and password recovery are not implemented. - Unfinished carts (including File blobs) recover from IndexedDB for 24 hours in the same browser, scoped to the guest/account identity. Recovered items can be removed/replaced or joined by new items; in-place reconstruction of the artwork editor and cross-device cart synchronization are not implemented. Browser storage capacity limits apply. Payment clears the saved cart. Logout revokes the server session and clears local checkout metadata and saved File blobs across open Site tabs. - Operators manually upload and approve a complete final-file set, with one or more files per order item. Queue entry requires active final files for every item. Corrections invalidate the old set; customers submit corrections through their portal, and operators reapprove final files. No artwork transformation, automatic pre-flight, or machine control is performed. - Every completed upload is quarantined pending a local ClamAV scan. Only `clean` files can be quoted, commercially approved, paid, downloaded, attached as final files, or admitted to the print queue. Rejected/error files remain blocked and expire within three days. The isolated scanner uses signatures bundled in its pinned image and has no external network route. The multipart transport could carry 5 GiB, but API and customer admission stop at the effective 128 MiB scan/release limit by default. Larger files require a new scan/release design. This malware gate is not print pre-flight or artwork validation. - A retention worker removes expired object bytes but keeps order/file metadata: incomplete uploads after a one-hour reservation lease, originals within seven days of manual final artwork approval, and attached final/correction files within 30 days of the order's first upload. Storage lifecycle is also a 30-day backstop. - Structured security events are written to logs and PostgreSQL. The local `security_status` command summarizes authentication, rate-limit, scan, and scanner/signature alerts without exposing secrets. Security regression tests, exact-runtime Python dependency auditing, and Trivy image reports live under `app/` and `output/security/`; open findings are documented in `SECURITY_REPORT.md` and are not a production-readiness claim. - All direct and transitive Python packages are pinned with artifact hashes in `infra/requirements.lock`; the API image build requires those hashes. The lock is regenerated in a disposable Python 3.12 container by `infra/lock_dependencies.sh`. A fresh exact-runtime audit found no known Python advisories on 2026-09-15; this does not cover OS/container findings. - `compose.staging.yaml` is a separate, network-disabled readiness gate only. It validates non-secret staging decisions and rejects placeholders, local endpoints, fake providers, embedded secret settings, and unsafe secret sources. It does not deploy the application, contain credentials, or contact any real provider. - A separate production delivery package now exists under `deploy/`, with non-root API/web image definitions, a single Portainer Docker Swarm stack, external secret/volume contracts, health-monitored rolling updates, commit-SHA rollback images, and one protected Gitea workflow under `.gitea/workflows/`. The package never contains provider credentials and has not been deployed. Its fail-closed preflight intentionally rejects the current source until production adapters, Docker-secret file loading, approved inputs, restore rehearsal, image scans, and human security approval are complete. - `python3 -m ops.backup create-and-verify` creates a private, Git-ignored bundle containing a PostgreSQL dump plus every complete, unexpired object already marked `clean`. SHA-256 manifests protect both parts. Verification restores the database under a UUID name and the object bytes under a UUID MinIO prefix, hashes the restored bytes, then removes only those temporary targets. Active data is never overwritten; pending, rejected, errored, expired, and purged objects are excluded. Run this local snapshot while uploads and retention are idle. Scheduling, offsite copies, and production restore operations remain unfinished. - Real providers, production authentication hardening, email verification/recovery, automatic final-file generation, production backup operations, and production activation remain incomplete. Deployment plumbing exists but cannot pass its release gate yet. No factory automation or pre-flight is added. See `docs/historico/IMPLEMENTATION_REPORT.md` for verification, `PRODUCTION_INPUTS.md` for the decisions and evidence required before staging or production connection, and `PORTAINER.md` for the production delivery contract. The client roadmap promises are unchanged, so its PDF source is not regenerated for this local implementation checkpoint. ### Existing assets - `web/`: the Site (`index.html`), the Kanban and customer portal pages, and the scripts behind them. `web/site-*.js` holds the Site's behaviour. - `docs/historico/`: the original specification, endpoint sketch, task plan and status report. Background only — they describe a model this system does not implement. The prototypes they describe (`portal/`, `kanban/`, `agente/`, the root `schema.sql` and `.env.exemplo`) were removed on 2026-09-21 once nothing referenced them; recover from Git history if ever needed. - `tools/generate_dtf_report.py`: generator for the client-facing roadmap PDF. - `docs/roadmap-cliente.pdf`: the generated roadmap, as last sent. - `docs/reuniao-2026-09-09-anotacoes.pdf`: meeting notes that established the business direction. Treat it as context; the latest decisions in this document define the active scope. ### Important gaps and stale assumptions - The original Site had no backend payment, freight quote, order persistence, authentication, purchase history, or real cart persistence. Local order persistence, reviewed quotes, mock freight and fake payment now work through `web/checkout.js`. The local customer portal now provides accounts and order history; cart recovery is browser-local. Production account verification, recovery, and cross-device cart editing are still absent. - Without the local bridge, the original freight fallback remains a stub. Real freight quotation remains unimplemented in all runtimes. - The existing the removed prototypes duplicated WhatsApp senders and send direct text messages. They are not production-ready notification modules. - Older documentation and code describe a Tiny webhook creating an upload link, a factory agent, local Kanban, FlexiPRINT automation, 90-day retention, and 12-month artwork reuse. Those are not the current MVP model. ## Documentation synchronization `context.md` is the compact operating context for agents. The current client-facing narrative, diagrams, and formatting live in `docs/roadmap-cliente.pdf`, generated from `tools/generate_dtf_report.py`. When a decision changes, update both the relevant implementation context here and the roadmap source when it changes what the client-facing plan promises. ## Change-control rules for agents - Preserve the current Site DTF commercial rules unless explicitly asked to change them. - Do not add factory-side automation, a local agent, hot folders, FlexiPRINT control, machine dashboards, or a new post-MVP delivery commitment by inference. - Do not claim that R2 hosts or executes application services. - Keep all customer-facing and internal documentation in English only when this file is the requested artifact; otherwise follow the user's requested language. - When a requirement is unclear, distinguish between the MVP, a future enhancement, and an existing prototype assumption before changing code.