Files
dtf-system/CONTEXT.md
Cauê Faleiros 66ddb17f02
All checks were successful
Build and deploy / Validate source (push) Successful in 10s
Build and deploy / Integration suite on a real stack (push) Successful in 1m47s
Build and deploy / Secret scan and release gate (push) Successful in 7s
Build and deploy / Publish images and notify Portainer (push) Successful in 1m38s
chore: untrack deliverables committed by mistake, and home the stray files
The previous commit used git add -A and swept in four binaries that were
deliberately untracked: the week-1 client report as .docx and .pdf, a duplicate
of it under output/documents, and imagem-teste.jpg, an input dropped in to test
with. None of them are the repository's to version. They are untracked here,
left on disk, and covered by .gitignore so the mistake cannot repeat.

Three files had no sensible home. The meeting notes sat at the repository root
under a 78-character name with spaces and accents, the roadmap generator lived
in tmp/ — a directory otherwise ignored as scratch — and its output in output/,
which is otherwise generated evidence. They are now docs/reuniao-2026-09-09-
anotacoes.pdf, tools/generate_dtf_report.py and docs/roadmap-cliente.pdf, with
CONTEXT.md and ROADMAP.md updated to match and a docs/README.md saying what each
document is for.

.gitignore no longer needs four rules to keep one generator out of an ignored
directory; tmp/ is scratch again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 16:47:36 -03:00

20 KiB

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

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 dtf-site.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 dtf-site.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 local/; 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 transport accepts files up to 5 GiB, but the local scan/release limit is 128 MiB; larger files remain blocked. 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 one day, 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 local/ 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 local/requirements.lock; the API image build requires those hashes. The lock is regenerated in a disposable Python 3.12 container by local/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 local.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

  • dtf-site.html: the Site. Commercial rules, artwork analysis, cart and delivery UI; its behaviour lives in local/static/site-*.js.
  • 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 local/static/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 portal/whats.py and kanban/whats.py are duplicated 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.