<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Palks Studio</title>
    <description>The latest articles on Forem by Palks Studio (@palks_studio).</description>
    <link>https://forem.com/palks_studio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3772766%2Ffab897d4-6d2e-4fe9-9350-3e9fa72aec4e.png</url>
      <title>Forem: Palks Studio</title>
      <link>https://forem.com/palks_studio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/palks_studio"/>
    <language>en</language>
    <item>
      <title>How I integrated Factur-X EN16931 into a PHP billing system — without a database or SaaS dependency</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Mon, 11 May 2026 10:17:35 +0000</pubDate>
      <link>https://forem.com/palks_studio/-how-i-integrated-factur-x-en16931-into-a-php-billing-system-without-a-database-or-saas-25ab</link>
      <guid>https://forem.com/palks_studio/-how-i-integrated-factur-x-en16931-into-a-php-billing-system-without-a-database-or-saas-25ab</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bffajxx80sck12uae6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bffajxx80sck12uae6f.png" alt="A Factur-X EN16931 compliant invoice — PDF/A-3 with embedded XML, generated on-premise without SaaS or ERP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Without a database, without a SaaS platform, without an ERP
&lt;/h2&gt;

&lt;p&gt;When the French e-invoicing reform (RFE) started becoming a real deadline, I needed to make my billing system compliant.&lt;br&gt;&lt;br&gt;
Not by switching to a SaaS platform.&lt;br&gt;&lt;br&gt;
Not by plugging into an ERP. But by integrating the Factur-X standard directly into an existing PHP stack, deployed on a standard Apache server.&lt;/p&gt;

&lt;p&gt;This article is about how I did it, what the standard actually requires, and what the real technical challenges were.&lt;/p&gt;


&lt;h2&gt;
  
  
  What is Factur-X, really?
&lt;/h2&gt;

&lt;p&gt;Factur-X is a franco-german standard for structured electronic invoicing. It is built on two layers:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A PDF/A-3 file — not just a regular PDF, but a long-term archiving format defined by ISO 19005-3
&lt;/li&gt;
&lt;li&gt;An embedded XML file compliant with the EN16931 European standard, profile Comfort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PDF is human-readable. The XML is machine-readable. Both are mandatory. One without the other is not Factur-X.&lt;br&gt;&lt;br&gt;
The standard is already required for public procurement in France and is progressively being adopted across the EU under the european VAT directive. It is not a french-only concern.&lt;/p&gt;


&lt;h2&gt;
  
  
  The VAT legal mentions — the part most developers miss
&lt;/h2&gt;

&lt;p&gt;Generating a valid Factur-X file is not enough. The invoice itself must carry the correct VAT legal mention depending on the client's location. Getting this wrong is not a formatting issue — it is a fiscal compliance issue.&lt;/p&gt;

&lt;p&gt;There are three cases when the issuer is based in France:  &lt;/p&gt;
&lt;h3&gt;
  
  
  French client
&lt;/h3&gt;

&lt;p&gt;The issuer is a micro-enterprise or not subject to VAT. The mandatory mention is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TVA non applicable, art. 293B du CGI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No VAT is applied. No VAT column appears on the invoice. This mention must be present.&lt;/p&gt;

&lt;h3&gt;
  
  
  EU client (B2B with VAT number)
&lt;/h3&gt;

&lt;p&gt;The transaction falls under the reverse charge mechanism. The client self-declares the VAT in their own country. The mandatory mention is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Autoliquidation — TVA due par le preneur, art. 283-2 du CGI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VAT is forced to 0% on all lines. The mention replaces any VAT footer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-EU client&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The service is exported outside the EU. VAT exemption applies under export rules. The mandatory mention is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exonération de TVA — art. 262 I du CGI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, VAT is 0%. The mention is legally required on the document.&lt;/p&gt;

&lt;p&gt;These three mentions are not optional notes. They are the legal justification for why VAT is absent or transferred. An invoice without the correct mention — or with the wrong one — can be challenged during a tax audit.&lt;/p&gt;

&lt;p&gt;In my implementation, the correct mention is determined automatically based on the client's country ISO code and VAT number. The developer does not choose it manually. The system does.&lt;/p&gt;




&lt;h2&gt;
  
  
  The technical chain — how Factur-X is actually generated
&lt;/h2&gt;

&lt;p&gt;The generation happens in two distinct phases, handled by two separate components. This separation is intentional — each phase has a different responsibility and a different technical constraint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1 — Building the XML
&lt;/h3&gt;

&lt;p&gt;The first component is a PHP script responsible for constructing the EN16931-compliant XML file.&lt;/p&gt;

&lt;p&gt;It reads the invoice data — issuer details, client details, line items, VAT amounts, totals, payment terms — and maps each field to the correct EN16931 element. The profile used is Comfort, which covers the full set of fields required for B2B invoicing including VAT breakdown by rate.&lt;/p&gt;

&lt;p&gt;A few things that matter here:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amounts must follow strict decimal formatting — no rounding shortcuts
&lt;/li&gt;
&lt;li&gt;VAT must be aggregated by rate, not by line
&lt;/li&gt;
&lt;li&gt;The seller and buyer identifiers (SIREN, SIRET, VAT number) must appear in specific XML nodes depending on the client zone
&lt;/li&gt;
&lt;li&gt;The legal VAT mention determined in the previous step is embedded directly into the XML as a structured element, not just as visible text on the PDF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is a raw XML file, stored temporarily before the next phase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2 — Injecting the XML and converting to PDF/A-3
&lt;/h3&gt;

&lt;p&gt;The second component is a Python script using the factur-x library developed by Akretion — the same team behind the Factur-X standard itself.&lt;/p&gt;

&lt;p&gt;This script does two things:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes the invoice PDF (generated by the PHP billing engine using mPDF) and the XML file produced in phase 1
&lt;/li&gt;
&lt;li&gt;It embeds the XML inside the PDF and converts the result to PDF/A-3b — the archiving format required by the standard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why Python for this phase and not PHP? Because the factur-x library handles the PDF/A-3 conversion and XML embedding with precision that is difficult to replicate in PHP without heavy dependencies. The library also validates the XML structure against the EN16931 schema before injection — which acts as a built-in compliance check.&lt;/p&gt;

&lt;p&gt;The final output is a single file: a PDF/A-3 with the XML embedded, fully compliant with Factur-X EN16931 Comfort profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  The temporary file cycle
&lt;/h3&gt;

&lt;p&gt;Between the two phases, temporary files are created and cleaned up automatically. The XML is written to a dedicated temporary directory, used during injection, then deleted once the final PDF is produced. Nothing persists beyond what is needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The result — what this architecture delivers
&lt;/h2&gt;

&lt;p&gt;The output of this chain is a single invoice file that is both human-readable and machine-readable, compliant with Factur-X EN16931, ready for transmission to a Partner Dematerialization Platform (PDP) or direct exchange with a client.&lt;/p&gt;

&lt;p&gt;A few things worth noting about what this approach delivers:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No SaaS dependency&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The entire generation chain runs on the server where the billing system is deployed. No external API call is made during invoice generation. No data leaves the infrastructure. The invoice is produced, signed, archived and delivered entirely on-premise.&lt;/p&gt;

&lt;p&gt;This matters for clients who cannot or do not want their financial data processed by a third-party cloud service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No ERP required&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The system does not sit on top of an ERP. It does not require an existing accounting software to function. The Factur-X output is produced directly from the billing data entered in the interface — client details, service lines, VAT zone, payment terms.&lt;/p&gt;

&lt;p&gt;This makes it deployable for small and mid-size businesses that need compliance without the overhead of a full ERP migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliance is structural, not cosmetic&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The VAT legal mentions are not added as text fields that a user can forget or mistype. They are determined by the system based on the client's country and VAT number, embedded in both the visible PDF and the structured XML. The correct mention always appears. The correct VAT rate is always applied.&lt;/p&gt;

&lt;p&gt;This is the difference between a system that looks compliant and one that actually is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating Factur-X into an existing billing stack is not trivial, but it is achievable without rebuilding everything. The key is understanding what the standard actually requires — not just the file format, but the fiscal logic behind it.&lt;/p&gt;

&lt;p&gt;The chain described here — PHP for XML construction, Python for PDF/A-3 conversion and injection — is stable, testable, and entirely self-hosted. It produces invoices that are compliant today and will remain compliant as the european e-invoicing mandate expands.&lt;/p&gt;

&lt;p&gt;If you are working on a similar integration or have questions about the EN16931 structure, feel free to reach out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it
&lt;/h3&gt;

&lt;p&gt;A live demo is available — you can generate a real Factur-X EN16931 compliant invoice directly from your browser, no account required.&lt;br&gt;
&lt;a href="https://palks-studio.com/en/facturx-invoice-generation" rel="noopener noreferrer"&gt;Try the Factur-X demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>backend</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Dependency as an Engineering Trade-Off</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Sun, 10 May 2026 14:49:48 +0000</pubDate>
      <link>https://forem.com/palks_studio/dependency-as-an-engineering-trade-off-322p</link>
      <guid>https://forem.com/palks_studio/dependency-as-an-engineering-trade-off-322p</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7t8zsgvdkykzro1n823g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7t8zsgvdkykzro1n823g.png" alt="Tangled dependencies versus controlled backend architecture and long-term system stability" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stability, control and long-term maintainability in backend systems
&lt;/h2&gt;

&lt;p&gt;Dependencies are everywhere in modern software development.&lt;br&gt;&lt;br&gt;
Frameworks, libraries, external services, and specialized tools help accelerate development and avoid reinventing existing solutions.&lt;/p&gt;

&lt;p&gt;In many situations, this is a reasonable choice.&lt;br&gt;&lt;br&gt;
A dependency can reduce development time, provide proven functionality, and simplify complex implementations.&lt;/p&gt;

&lt;p&gt;However, every dependency also introduces a trade-off that is often invisible at first: part of the system’s behavior is no longer fully controlled by the people building it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solving problems today, creating complexity tomorrow
&lt;/h2&gt;

&lt;p&gt;Adding a dependency usually solves an immediate problem.&lt;br&gt;&lt;br&gt;
A feature is implemented faster, with less effort, and the system moves forward quickly.&lt;/p&gt;

&lt;p&gt;Over time, however, dependencies evolve:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;breaking changes between versions
&lt;/li&gt;
&lt;li&gt;behavioral changes
&lt;/li&gt;
&lt;li&gt;reduced maintenance or abandonment
&lt;/li&gt;
&lt;li&gt;new technical constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system may continue to function, but its stability increasingly depends on external factors.&lt;/p&gt;

&lt;p&gt;Complexity rarely appears immediately.&lt;br&gt;&lt;br&gt;
It accumulates gradually as the system evolves.&lt;/p&gt;




&lt;h2&gt;
  
  
  When behavior escapes the system
&lt;/h2&gt;

&lt;p&gt;The more layers a system relies on, the harder it becomes to explain why it behaves in a certain way.&lt;/p&gt;

&lt;p&gt;An issue may originate from:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application code
&lt;/li&gt;
&lt;li&gt;an intermediate library
&lt;/li&gt;
&lt;li&gt;a version change
&lt;/li&gt;
&lt;li&gt;or an external service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A backend system may suddenly behave differently after what appears to be a minor update:&lt;br&gt;&lt;br&gt;
a dependency changes an internal behavior, an external API modifies a response format, or a framework update introduces a new constraint.&lt;/p&gt;

&lt;p&gt;Nothing in the business logic was intentionally changed, yet the system itself no longer behaves the same way.&lt;/p&gt;

&lt;p&gt;This diffusion of responsibility increases uncertainty.&lt;br&gt;&lt;br&gt;
Understanding a problem often requires understanding multiple systems at once.&lt;/p&gt;

&lt;p&gt;At that point, the difficulty is no longer purely technical.&lt;br&gt;&lt;br&gt;
It becomes structural.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reducing dependencies means reducing uncertainty
&lt;/h2&gt;

&lt;p&gt;Reducing dependencies does not mean rejecting existing tools.&lt;br&gt;&lt;br&gt;
It means deciding what should truly belong to the system.&lt;/p&gt;

&lt;p&gt;Some functionalities are central enough to justify a simple, controlled implementation. Others can remain external without significant impact.&lt;/p&gt;

&lt;p&gt;The goal is not to minimize dependencies at all costs, but to limit those that directly influence core logic or critical system behavior.&lt;/p&gt;

&lt;p&gt;The fewer external elements a system depends on, the more predictable its behavior becomes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stability as a consequence of control
&lt;/h2&gt;

&lt;p&gt;The systems that are easiest to maintain are not necessarily those using the fewest tools.&lt;br&gt;&lt;br&gt;
They are often the ones where dependencies are clearly identified and limited to areas where they provide real value.&lt;/p&gt;

&lt;p&gt;When the essential parts of a system remain under control, external changes become less risky.&lt;/p&gt;

&lt;p&gt;Stability does not come from avoiding change, but from understanding what actually changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Balance rather than rejection
&lt;/h2&gt;

&lt;p&gt;Dependencies are an integral part of modern development.&lt;br&gt;&lt;br&gt;
They allow teams to build faster and benefit from shared knowledge.&lt;/p&gt;

&lt;p&gt;But every dependency shifts part of the control outside the system itself.&lt;/p&gt;

&lt;p&gt;Understanding this trade-off leads to better decisions: accepting dependencies when they genuinely simplify the problem, and reducing them when they introduce more uncertainty than value.&lt;/p&gt;

&lt;p&gt;Over time, these often invisible decisions determine whether a system remains understandable or gradually becomes difficult to evolve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>security</category>
      <category>server</category>
    </item>
    <item>
      <title>AI Agents Writing All Your Code: Comfort or Loss of Control?</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Fri, 24 Apr 2026 15:10:07 +0000</pubDate>
      <link>https://forem.com/palks_studio/ai-agents-writing-all-your-code-comfort-or-loss-of-control-5heb</link>
      <guid>https://forem.com/palks_studio/ai-agents-writing-all-your-code-comfort-or-loss-of-control-5heb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faw6b8evycxyrsuq5ltqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faw6b8evycxyrsuq5ltqh.png" alt="AI agent controlling code and developer systems" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The new reflex: delegate everything
&lt;/h2&gt;

&lt;p&gt;Over the past few months, we’ve seen the rise of AI agents capable of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating full codebases
&lt;/li&gt;
&lt;li&gt;modifying existing projects
&lt;/li&gt;
&lt;li&gt;automating complex tasks
&lt;/li&gt;
&lt;li&gt;making technical decisions
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reflex is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I’ll just let the AI handle it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it works.&lt;br&gt;&lt;br&gt;
At least, on the surface.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem: we no longer know what we’re running
&lt;/h2&gt;

&lt;p&gt;When an agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;writes code
&lt;/li&gt;
&lt;li&gt;modifies files
&lt;/li&gt;
&lt;li&gt;restructures a project
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;who actually understands what’s going on?&lt;/p&gt;

&lt;p&gt;In many cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the code is accepted without review
&lt;/li&gt;
&lt;li&gt;the logic is not fully understood
&lt;/li&gt;
&lt;li&gt;entire parts become opaque
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We gain speed.&lt;br&gt;&lt;br&gt;
But we lose something fundamental:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;understanding.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A system that works… until it breaks
&lt;/h2&gt;

&lt;p&gt;It’s the same pattern we’ve seen before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it works
&lt;/li&gt;
&lt;li&gt;we stack layers
&lt;/li&gt;
&lt;li&gt;we trust it
&lt;/li&gt;
&lt;li&gt;then one day… it breaks
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no one knows where to look
&lt;/li&gt;
&lt;li&gt;no one understands the full logic
&lt;/li&gt;
&lt;li&gt;the system becomes hard to fix
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The question no one is asking
&lt;/h2&gt;

&lt;p&gt;Today, the focus is on performance, productivity, speed.&lt;/p&gt;

&lt;p&gt;But very few people ask the real question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;what happens when we no longer control what we execute?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because tomorrow, the issue might not be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a bug
&lt;/li&gt;
&lt;li&gt;a mistake
&lt;/li&gt;
&lt;li&gt;a bad implementation
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But something deeper:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;total dependence on a system we don’t understand&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What if we start hearing about compromised agents?
&lt;/h2&gt;

&lt;p&gt;Today, it may sound exaggerated.&lt;/p&gt;

&lt;p&gt;But we’ve already seen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compromised dependencies
&lt;/li&gt;
&lt;li&gt;libraries injecting malicious code
&lt;/li&gt;
&lt;li&gt;popular tools becoming attack vectors
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the question is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;if an agent controls part of your code… what happens if it’s compromised?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And more importantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;who is able to detect it?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The real issue isn’t AI
&lt;/h2&gt;

&lt;p&gt;AI isn’t the problem.&lt;/p&gt;

&lt;p&gt;It’s a powerful tool.&lt;br&gt;&lt;br&gt;
Useful.&lt;br&gt;&lt;br&gt;
Sometimes impressive.&lt;/p&gt;

&lt;p&gt;The problem is how we use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Assistant vs pilot
&lt;/h2&gt;

&lt;p&gt;There’s a huge difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using AI as an assistant
&lt;/li&gt;
&lt;li&gt;letting AI take control
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In one case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you gain speed
&lt;/li&gt;
&lt;li&gt;you keep control
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you accelerate
&lt;/li&gt;
&lt;li&gt;but you lose understanding
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Taking back control
&lt;/h2&gt;

&lt;p&gt;Using AI agents isn’t a bad thing.&lt;/p&gt;

&lt;p&gt;But a few simple principles make all the difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;understand what is generated
&lt;/li&gt;
&lt;li&gt;limit automated layers
&lt;/li&gt;
&lt;li&gt;avoid delegating critical parts
&lt;/li&gt;
&lt;li&gt;keep logic simple and readable
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Technology is moving fast. Very fast.&lt;/p&gt;

&lt;p&gt;And AI agents will take more and more space.&lt;/p&gt;

&lt;p&gt;But as automation increases,&lt;br&gt;&lt;br&gt;
control can decrease.&lt;/p&gt;

&lt;p&gt;And in technical systems,&lt;br&gt;&lt;br&gt;
speed is not what makes them reliable.&lt;/p&gt;

&lt;p&gt;Understanding is.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ia</category>
      <category>programming</category>
      <category>security</category>
      <category>development</category>
    </item>
    <item>
      <title>Stop letting your editor decide how your code should look</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Tue, 21 Apr 2026 16:37:41 +0000</pubDate>
      <link>https://forem.com/palks_studio/stop-letting-your-editor-decide-how-your-code-should-look-165</link>
      <guid>https://forem.com/palks_studio/stop-letting-your-editor-decide-how-your-code-should-look-165</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksc3014jj4yzg8abv77f.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksc3014jj4yzg8abv77f.webp" alt="VS Code environment pack before and after configuration comparison" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Most developers don’t control their environment
&lt;/h2&gt;

&lt;p&gt;Most developers don’t configure their environment.&lt;/p&gt;

&lt;p&gt;They install extensions.&lt;/p&gt;

&lt;p&gt;They stack tools.&lt;/p&gt;

&lt;p&gt;They let everything run automatically.&lt;/p&gt;

&lt;p&gt;And over time, they lose control.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem is not formatting
&lt;/h2&gt;

&lt;p&gt;It’s &lt;strong&gt;uncontrolled automation&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;format on save&lt;/li&gt;
&lt;li&gt;hidden transformations&lt;/li&gt;
&lt;li&gt;conflicting extensions&lt;/li&gt;
&lt;li&gt;inconsistent results between machines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What starts as “productivity” becomes:&lt;/p&gt;

&lt;p&gt;→ unpredictable diffs&lt;br&gt;&lt;br&gt;
→ broken formatting&lt;br&gt;&lt;br&gt;
→ code that changes without you asking  &lt;/p&gt;




&lt;h2&gt;
  
  
  The real issue: loss of control
&lt;/h2&gt;

&lt;p&gt;When your editor modifies your code automatically, you are no longer in control of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when changes happen
&lt;/li&gt;
&lt;li&gt;what changes are applied
&lt;/li&gt;
&lt;li&gt;how your code is structured
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s not tooling.&lt;/p&gt;

&lt;p&gt;That’s delegation.&lt;/p&gt;




&lt;h2&gt;
  
  
  I built a different approach
&lt;/h2&gt;

&lt;p&gt;Instead of automating everything blindly, I built a VS Code environment based on one idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nothing happens unless you decide it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No format on save.&lt;br&gt;&lt;br&gt;
No hidden actions.&lt;br&gt;&lt;br&gt;
No external dependencies.&lt;/p&gt;

&lt;p&gt;Only explicit, controlled operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this environment does differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No automatic formatting
&lt;/li&gt;
&lt;li&gt;No “magic” behavior
&lt;/li&gt;
&lt;li&gt;No dependency on extensions
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manual
&lt;/li&gt;
&lt;li&gt;predictable
&lt;/li&gt;
&lt;li&gt;reproducible
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Controlled formatting, not automation
&lt;/h2&gt;

&lt;p&gt;Formatting and cleanup are still there.&lt;/p&gt;

&lt;p&gt;But they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;triggered manually via tasks
&lt;/li&gt;
&lt;li&gt;applied only when needed
&lt;/li&gt;
&lt;li&gt;executed locally with Python scripts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to clean
&lt;/li&gt;
&lt;li&gt;what to modify
&lt;/li&gt;
&lt;li&gt;how far it goes
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Local scripts, full control
&lt;/h2&gt;

&lt;p&gt;Instead of relying on extensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clean.py&lt;/code&gt; → removes useless spaces, fixes structure
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;convert.py&lt;/code&gt; → normalizes line endings
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;space.py&lt;/code&gt; → detects issues without modifying
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;backup.py&lt;/code&gt; → creates timestamped local backups
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs locally.&lt;/p&gt;

&lt;p&gt;No network. No hidden logic. No surprises. :contentReference[oaicite:0]{index=0}&lt;/p&gt;




&lt;h2&gt;
  
  
  Three execution modes
&lt;/h2&gt;

&lt;p&gt;You can run actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on the whole project
&lt;/li&gt;
&lt;li&gt;on the active file
&lt;/li&gt;
&lt;li&gt;on a custom selection
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids accidental global changes.&lt;/p&gt;

&lt;p&gt;And keeps your code stable. :contentReference[oaicite:1]{index=1}&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Because code is not just written.&lt;/p&gt;

&lt;p&gt;It is maintained.&lt;/p&gt;

&lt;p&gt;And maintenance requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consistency
&lt;/li&gt;
&lt;li&gt;predictability
&lt;/li&gt;
&lt;li&gt;control
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blind automation breaks all three.&lt;/p&gt;




&lt;h2&gt;
  
  
  This is not about tools
&lt;/h2&gt;

&lt;p&gt;It’s about responsibility.&lt;/p&gt;

&lt;p&gt;If your environment modifies your code without you noticing:&lt;/p&gt;

&lt;p&gt;You are no longer responsible for your code.&lt;/p&gt;

&lt;p&gt;Your tools are.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;developers tired of fighting their editor
&lt;/li&gt;
&lt;li&gt;teams needing consistent formatting
&lt;/li&gt;
&lt;li&gt;anyone who wants a stable, predictable workflow
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Faster doesn’t mean better.&lt;/p&gt;

&lt;p&gt;Automated doesn’t mean controlled.&lt;/p&gt;

&lt;p&gt;And in the long run:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the code you control will always outlive the tools you depend on.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you're interested in how it works under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a technical breakdown of the system architecture.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  VS Code – Environment Pack
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;configured working environment&lt;/strong&gt; for Visual Studio Code.&lt;/p&gt;

&lt;p&gt;This pack provides a clear and consistent framework for formatting, cleanup, and normalization&lt;br&gt;&lt;br&gt;
of common file types (&lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.html&lt;/code&gt;, &lt;code&gt;.css&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;),&lt;br&gt;&lt;br&gt;
using VS Code settings and locally executed Python scripts.&lt;/p&gt;

&lt;p&gt;The goal is not blind automation,&lt;br&gt;&lt;br&gt;
but a &lt;strong&gt;controlled set of tools&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
that lets you keep full control over code structure, readability, and consistency,&lt;br&gt;&lt;br&gt;
regardless of the operating system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this environment exists
&lt;/h2&gt;

&lt;p&gt;Most editors automatically reformat code when saving files.&lt;br&gt;&lt;br&gt;
While convenient, this can introduce unexpected changes,&lt;br&gt;&lt;br&gt;
inconsistent formatting, or conflicts between extensions.&lt;/p&gt;

&lt;p&gt;This pack takes the opposite approach:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no automatic formatting
&lt;/li&gt;
&lt;li&gt;no hidden actions
&lt;/li&gt;
&lt;li&gt;manual tools executed only when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to keep code stable, readable and predictable,&lt;br&gt;&lt;br&gt;
while giving full control to the developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pack Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vscode_environment_pack_v1.1/
│
├── .vscode/
│   ├── settings.json           → Complete editor configuration (indentation, encoding, readability)
│   ├── keybindings.json        → Custom keyboard shortcuts (navigation, editing)
│   ├── tasks.json              → VS Code tasks for manual tool execution
│   ├── launch.json             → Script execution within the environment
│   └── extensions.json         → Local extension management
│
├── scripts/
│   ├── cleaning.py             → File cleaning and normalization
│   ├── conversion.py           → Format and encoding handling
│   ├── analysis.py             → File analysis (read-only)
│   └── backup.py               → Local file backup system
│ 
├── LICENSE.md                  → Terms of use and legal framework
│ 
└── docs/
    ├── TECHNICAL_README.md     → Technical documentation and internal structure
    ├── README_COMMERCIAL.md    → Project overview and public presentation
    ├── INSTALL.md              → Installation and usage guide
    │
    └── examples/
        ├── before.py           → Dirty / unstructured example files
        ├── after.py            → Clean, formatted versions generated by the pack
        ├── convert_lf.mp4      → CRLF files automatically converted to LF
        ├── indent_clean.mp4    → Broken indentation/margins fixed instantly
        ├── indent_python.mp4   → Badly indented Python file auto-corrected
        ├── backup.mp4          → Demonstrates automatic file backup on each save (Ctrl + S)
        │                         and how to restore a deleted file from the backup folder
        └── space_clean.mp4     → Broken file analyzed and margins detected (read-only)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you want to explore the technical implementation, you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/vs-code-environment-pack" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/vs-code-environment-pack&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>python</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Static websites don’t limit features. They redefine where complexity lives</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Fri, 17 Apr 2026 15:10:23 +0000</pubDate>
      <link>https://forem.com/palks_studio/static-websites-dont-limit-features-they-redefine-where-complexity-lives-37kh</link>
      <guid>https://forem.com/palks_studio/static-websites-dont-limit-features-they-redefine-where-complexity-lives-37kh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyqlfwn97q66a95jpxhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyqlfwn97q66a95jpxhu.png" alt="Palks Studio homepage — static" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Websites Are Not Limited Websites
&lt;/h2&gt;

&lt;p&gt;Static websites are often associated with simple projects: landing pages, fixed content, or minimal websites without advanced functionality.&lt;/p&gt;

&lt;p&gt;This perception largely comes from earlier stages of the web, where “static” meant limited interaction and little or no logic.&lt;/p&gt;

&lt;p&gt;Today, that association no longer reflects reality.&lt;/p&gt;

&lt;p&gt;A static website does not define what a project can do, but how it is structured.&lt;/p&gt;




&lt;h2&gt;
  
  
  Static does not mean minimal
&lt;/h2&gt;

&lt;p&gt;A static website can integrate many modern features:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;secure download systems
&lt;/li&gt;
&lt;li&gt;payments handled through external services
&lt;/li&gt;
&lt;li&gt;interactive interfaces
&lt;/li&gt;
&lt;li&gt;local chatbots
&lt;/li&gt;
&lt;li&gt;client-side animations and dynamic behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference is not in visible capabilities, but in where complexity is placed.&lt;/p&gt;

&lt;p&gt;Instead of concentrating logic in a permanent server or database, functionality is isolated into specific components only where it is needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Moving complexity instead of spreading it
&lt;/h2&gt;

&lt;p&gt;In many projects, a full backend is introduced by default, even when actual needs remain limited.&lt;/p&gt;

&lt;p&gt;This often increases complexity:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;continuous server maintenance
&lt;/li&gt;
&lt;li&gt;additional dependencies
&lt;/li&gt;
&lt;li&gt;larger error surface
&lt;/li&gt;
&lt;li&gt;constant updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A static approach keeps the website itself simple while delegating only necessary parts to specialized services or scripts.&lt;/p&gt;

&lt;p&gt;Complexity is not removed.&lt;br&gt;&lt;br&gt;
It is moved to controlled areas.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance and structural clarity
&lt;/h2&gt;

&lt;p&gt;Static websites also provide structural advantages.&lt;/p&gt;

&lt;p&gt;Content is directly accessible, structure remains readable, and behavior stays predictable. The absence of server-side generation on each request reduces potential failure points and simplifies hosting.&lt;/p&gt;

&lt;p&gt;This structural simplicity makes long-term maintenance and project handover easier.&lt;/p&gt;

&lt;p&gt;The project remains understandable without requiring complex infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Most real-world needs
&lt;/h2&gt;

&lt;p&gt;In practice, many web projects do not require a fully dynamic system.&lt;/p&gt;

&lt;p&gt;Presentation websites, documentation, digital products, educational content, or information platforms can operate efficiently on a well-designed static foundation.&lt;/p&gt;

&lt;p&gt;Advanced functionality can be added selectively without turning the entire project into a complex application.&lt;/p&gt;




&lt;h2&gt;
  
  
  An engineering choice
&lt;/h2&gt;

&lt;p&gt;Choosing a static architecture is not about limiting a project.&lt;br&gt;&lt;br&gt;
It is often about defining a clear scope, reducing maintenance, and achieving more predictable behavior.&lt;/p&gt;

&lt;p&gt;Static websites do not replace dynamic applications where they are necessary.&lt;br&gt;&lt;br&gt;
But in many cases, they provide a more stable result with less complexity.&lt;/p&gt;

&lt;p&gt;This is not a step backward.&lt;br&gt;&lt;br&gt;
It is a structural decision.&lt;/p&gt;

&lt;p&gt;At Palks Studio, websites are built as static, dependency-free systems. Bases are available here: &lt;a href="https://palks-studio.com/en/static-site" rel="noopener noreferrer"&gt;https://palks-studio.com/en/static-site&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you're interested in how it works under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a technical breakdown of the system architecture.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Palks Studio — Static site + digital storefront
&lt;/h2&gt;

&lt;p&gt;This repository contains the public website of Palks Studio, which combines:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a clean, tracking-free static HTML website
&lt;/li&gt;
&lt;li&gt;a lightweight server-side digital storefront
&lt;/li&gt;
&lt;li&gt;an autonomous PDF invoicing system
&lt;/li&gt;
&lt;li&gt;and secure token-based delivery of downloadable files
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system operates without a CMS, without a database, and without unnecessary SaaS dependencies,&lt;br&gt;&lt;br&gt;
relying solely on flat files (JSON/CSV) and minimalist PHP scripts.  &lt;/p&gt;

&lt;p&gt;The repository includes:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the public website (pages, styles, images, content)
&lt;/li&gt;
&lt;li&gt;payment and digital delivery components
&lt;/li&gt;
&lt;li&gt;as well as publicly accessible documentation
with the aim of clarity, readability, and transparency
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This repository is not a turnkey product, a framework, or a software library.&lt;br&gt;&lt;br&gt;
It serves as a reference artifact to understand the approach,&lt;br&gt;&lt;br&gt;
tools, and technical choices carried by Palks Studio.  &lt;/p&gt;




&lt;h2&gt;
  
  
  About Palks Studio
&lt;/h2&gt;

&lt;p&gt;Palks Studio designs technical tools, documentation structures,&lt;br&gt;&lt;br&gt;
and working environments intended to be:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;readable
&lt;/li&gt;
&lt;li&gt;understandable
&lt;/li&gt;
&lt;li&gt;autonomous
&lt;/li&gt;
&lt;li&gt;maintainable over time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The emphasis is placed on:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;functional simplicity
&lt;/li&gt;
&lt;li&gt;control of dependencies
&lt;/li&gt;
&lt;li&gt;transparency of technical choices
&lt;/li&gt;
&lt;li&gt;durability rather than trends
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/palks-studio-website/
│
├── fr/                                       → Pages du site (FR)
├── en/                                       → Pages du site (EN)
│
├── assets/
│   ├── css/
│   │   └── style.css                         → Global stylesheet (FR) / Feuille de styles globale (EN)
│   └── img/                                  → Images et visuels (FR) / Images and visuals (EN)
│
├── robots.txt                                → Règles pour moteurs de recherche (FR) / Search engine directives (EN)
├── sitemap.xml                               → Plan du site pour indexation (FR) / Sitemap for indexing (EN)
│
├── LICENCE.md                                → Conditions d’utilisation et cadre légal (FR)
├── LICENSE.md                                → Terms of use and legal Framework (EN)
│
├── core/                                     → Backend génération PDF (FR) / PDF generation backend (EN)
├── endpoint/                                 → Moteur de traitement du formulaire CSV (FR) / CSV upload form processing engine (EN)
│
├── storage/
│   └── protected/                            → Stockage sécurisé interne (FR) / Secure internal storage (EN)
│
├── config/
│   └── download/                             → Configuration interne des téléchargements (FR) / Internal download configuration (EN)
│
├── library/
│   ├── contracts/                            → Génération et templates de contrats (FR) / Contract generation and templates (EN)
│   ├── batch/                                → Interface d’import et traitement CSV (FR) / CSV import and processing interface (EN)
│   ├── payments/                             → Pages de gestion des paiements (FR) / Payment handling pages (EN)
│   ├── counters/                             → Gestion de la numérotation (FR) / Numbering management (EN)
│   ├── core/                                 → Fonctions internes (génération, email, PDF) (FR) / Internal functions (generation, email, PDF) (EN)
│   └── templates/                            → Modèles de documents (FR) / Document templates (EN)
│
├── docs/
│   ├── VUE_D_ENSEMBLE.md                     → Vue d’ensemble du système (FR)
│   ├── OVERVIEW.md                           → System Overview (EN)
│   ├── PROJECT-OVERVIEW_FR.md                → Vue d’ensemble du projet (FR)
│   ├── PROJECT-OVERVIEW.md                   → Project Overview (EN)
│   ├── README_FR.md                          → Présentation générale (FR)
│   └── README.md                             → General Overview (EN)
│
├── store/                                    → Fichiers produits numériques (FR) / Digital product files (EN)
│
└── endpoint/
    ├── endpoint_a.php                        → Initialisation d’une session de paiement (FR) / Checkout session initialization (EN)
    ├── endpoint_b.php                        → Traitement des événements de paiement (FR) / Payment event handler (EN)
    ├── endpoint_c.php                        → Traitement post-paiement (FR) / Post-payment fulfillment handler (EN)
    └── endpoint_d.php                        → Point d’accès sécurisé aux fichiers (FR) / Secure file access endpoint (EN)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to explore the technical implementation, you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/palks-studio-website" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/palks-studio-website&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>backend</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Not All Complexity Is Bad — But Most of It Is</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Sat, 11 Apr 2026 17:12:47 +0000</pubDate>
      <link>https://forem.com/palks_studio/not-all-complexity-is-bad-but-most-of-it-is-48h</link>
      <guid>https://forem.com/palks_studio/not-all-complexity-is-bad-but-most-of-it-is-48h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq3bjnhr9n0o16bciz4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq3bjnhr9n0o16bciz4n.png" alt="System complexity diagram" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why complexity isn’t always the problem
&lt;/h2&gt;

&lt;p&gt;Complexity is often seen as something to eliminate.&lt;/p&gt;

&lt;p&gt;But not all complexity is bad.&lt;/p&gt;

&lt;p&gt;Some of it is necessary.&lt;/p&gt;

&lt;p&gt;Some of it shouldn’t exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  The confusion
&lt;/h2&gt;

&lt;p&gt;Most systems don’t fail because they are complex.&lt;/p&gt;

&lt;p&gt;They fail because the wrong complexity accumulates.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real issue
&lt;/h2&gt;

&lt;p&gt;Over time, systems mix two things:&lt;/p&gt;

&lt;p&gt;what is required&lt;br&gt;
what just happened to be added&lt;/p&gt;

&lt;p&gt;And the difference disappears.&lt;/p&gt;




&lt;h2&gt;
  
  
  What actually matters
&lt;/h2&gt;

&lt;p&gt;Good systems don’t avoid complexity.&lt;/p&gt;

&lt;p&gt;They make it visible and intentional.&lt;/p&gt;




&lt;h2&gt;
  
  
  A better way to think about it
&lt;/h2&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;p&gt;“how do we simplify?”&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;p&gt;“which complexity belongs here?”&lt;/p&gt;

&lt;p&gt;Full article → &lt;a href="https://palks-studio.com/en/useful-vs-accidental-complexity" rel="noopener noreferrer"&gt;https://palks-studio.com/en/useful-vs-accidental-complexity&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>software</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Factur-X EN16931: your invoice is probably not compliant (and you don't know it)</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Fri, 03 Apr 2026 17:03:31 +0000</pubDate>
      <link>https://forem.com/palks_studio/factur-x-en16931-your-invoice-is-probably-not-compliant-and-you-dont-know-it-5kj</link>
      <guid>https://forem.com/palks_studio/factur-x-en16931-your-invoice-is-probably-not-compliant-and-you-dont-know-it-5kj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzegrwknfnnok7u1vruzr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzegrwknfnnok7u1vruzr.png" alt="Factur-X EN16931 compliant invoice — XSD, Schematron and PDF/A-3 validated" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most invoicing solutions claim Factur-X compliance.&lt;br&gt;
Few actually pass all three validation levels.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three levels
&lt;/h2&gt;

&lt;p&gt;Factur-X conformity requires passing all of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XSD validation — XML structure is syntactically correct&lt;/li&gt;
&lt;li&gt;Schematron validation — EN16931 business rules are respected&lt;/li&gt;
&lt;li&gt;PDF/A-3 validation — the PDF document is archivable with the XML correctly embedded&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where most solutions fail
&lt;/h2&gt;

&lt;p&gt;PDF/A-3 is the real problem.&lt;/p&gt;

&lt;p&gt;Common PHP PDF libraries — Dompdf, TCPDF — produce DeviceRGB without ICC OutputIntent.&lt;br&gt;
The XML can be perfectly structured. The invoice is still rejected.&lt;/p&gt;




&lt;h2&gt;
  
  
  The combination that works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;mPDF generates clean PDF/A-1b output&lt;/li&gt;
&lt;li&gt;factur-x (Python) injects the EN16931 XML and converts to PDF/A-3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: XSD ✅ Schematron ✅ PDF/A-3 ✅&lt;/p&gt;




&lt;p&gt;Full note → &lt;a href="https://palks-studio.com/en/electronic-invoicing-compliance" rel="noopener noreferrer"&gt;https://palks-studio.com/en/electronic-invoicing-compliance&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>payments</category>
      <category>php</category>
      <category>software</category>
    </item>
    <item>
      <title>Why real-time can unnecessarily complicate simple systems</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Wed, 25 Mar 2026 15:55:42 +0000</pubDate>
      <link>https://forem.com/palks_studio/why-real-time-can-unnecessarily-complicate-simple-systems-5579</link>
      <guid>https://forem.com/palks_studio/why-real-time-can-unnecessarily-complicate-simple-systems-5579</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymcj5rqdpip0gltezksv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymcj5rqdpip0gltezksv.png" alt="Real-time vs simplicity" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Real-time architectures are everywhere.&lt;/p&gt;

&lt;p&gt;But not every system needs to be instant.&lt;/p&gt;

&lt;p&gt;In many cases, real-time introduces more complexity than value.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Most systems today assume everything must update instantly.&lt;/p&gt;

&lt;p&gt;But many business processes don’t need that.&lt;/p&gt;




&lt;h2&gt;
  
  
  The hidden cost
&lt;/h2&gt;

&lt;p&gt;Real-time systems create multiple intermediate states.&lt;/p&gt;

&lt;p&gt;Over time, this makes systems harder to understand and maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  A simpler approach
&lt;/h2&gt;

&lt;p&gt;Some systems benefit from clear, step-based processing instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data preparation
&lt;/li&gt;
&lt;li&gt;validation
&lt;/li&gt;
&lt;li&gt;processing
&lt;/li&gt;
&lt;li&gt;output
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Full article → &lt;a href="https://palks-studio.com/en/real-time-unnecessary-complexity" rel="noopener noreferrer"&gt;https://palks-studio.com/en/real-time-unnecessary-complexity&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>architecture</category>
      <category>automation</category>
      <category>software</category>
    </item>
    <item>
      <title>Stop stacking tools. Build systems that run on their own.</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Sun, 22 Mar 2026 17:14:05 +0000</pubDate>
      <link>https://forem.com/palks_studio/stop-stacking-tools-build-systems-that-run-on-their-own-2j6n</link>
      <guid>https://forem.com/palks_studio/stop-stacking-tools-build-systems-that-run-on-their-own-2j6n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrq5sijr4mflgcojnwc1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrq5sijr4mflgcojnwc1.png" alt="Autonomous billing and automation system running on a self-hosted infrastructure without SaaS dependencies" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Entrepreneurs, freelancers, agencies,&lt;/p&gt;

&lt;p&gt;A complete autonomous system running on your own hosting, without SaaS, subscriptions or external dependencies.&lt;/p&gt;

&lt;p&gt;Are you still stacking tools to run your business?&lt;/p&gt;

&lt;p&gt;Zapier.&lt;br&gt;
Make.&lt;br&gt;
Plugins.&lt;br&gt;
Subscriptions.&lt;br&gt;
Updates.&lt;br&gt;
Dependencies.&lt;/p&gt;

&lt;p&gt;It works…&lt;/p&gt;

&lt;p&gt;until it breaks.&lt;/p&gt;




&lt;p&gt;At Palks Studio, we do the opposite.&lt;/p&gt;

&lt;p&gt;We remove dependencies.&lt;/p&gt;

&lt;p&gt;We deploy systems directly on your infrastructure.&lt;/p&gt;




&lt;p&gt;No SaaS.&lt;br&gt;
No subscriptions.&lt;br&gt;
No surprises.&lt;br&gt;
No updates breaking everything.&lt;/p&gt;




&lt;p&gt;Internal scripts.&lt;/p&gt;

&lt;p&gt;Autonomous tools.&lt;/p&gt;

&lt;p&gt;Systems that run on your own hosting.&lt;/p&gt;




&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;quotes → signature → invoicing → payment → revenue tracking&lt;br&gt;
&lt;a href="https://palks-studio.com/en/invoicing-without-saas" rel="noopener noreferrer"&gt;https://palks-studio.com/en/invoicing-without-saas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;CSV → batch processing → structured outputs → automated delivery&lt;br&gt;
&lt;a href="https://palks-studio.com/en/batch-invoicing-facturx" rel="noopener noreferrer"&gt;https://palks-studio.com/en/batch-invoicing-facturx&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Invoicing.&lt;br&gt;
Automation.&lt;br&gt;
Internal tools.&lt;/p&gt;

&lt;p&gt;One goal:&lt;/p&gt;

&lt;p&gt;make it work.&lt;br&gt;
simply.&lt;br&gt;
over time.&lt;/p&gt;




&lt;p&gt;Less tools.&lt;br&gt;
Less complexity.&lt;br&gt;
More control.&lt;/p&gt;




&lt;p&gt;If your system depends on 5 external services,&lt;/p&gt;

&lt;p&gt;it’s not a system.&lt;/p&gt;

&lt;p&gt;It’s a fragile chain.&lt;/p&gt;




&lt;p&gt;There’s another way to build.&lt;/p&gt;

&lt;p&gt;Simpler.&lt;br&gt;
More stable.&lt;br&gt;
Fully controlled.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/palks-studio-website" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/palks-studio-website&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>backend</category>
      <category>architecture</category>
      <category>business</category>
    </item>
    <item>
      <title>If your business depends on 5 tools, you don’t have a system</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Mon, 16 Mar 2026 14:11:23 +0000</pubDate>
      <link>https://forem.com/palks_studio/a-self-hosted-financial-system-for-freelancers-4b27</link>
      <guid>https://forem.com/palks_studio/a-self-hosted-financial-system-for-freelancers-4b27</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqzp7v4v0je7a5k3iysq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqzp7v4v0je7a5k3iysq.png" alt="Clean self-hosted invoice system with PDF preview and paid validation process" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Still managing quotes, invoices and payments across multiple tools?
&lt;/h2&gt;

&lt;p&gt;I built a complete financial system that runs on your own domain.&lt;/p&gt;

&lt;p&gt;Not a SaaS.&lt;br&gt;
No subscription.&lt;br&gt;
No critical dependencies.&lt;/p&gt;

&lt;p&gt;The system runs on your own hosting.&lt;/p&gt;

&lt;p&gt;Quotes → online signature → invoicing → payment confirmation → revenue journal.&lt;/p&gt;

&lt;p&gt;Everything is semi-automated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quote / contract
&lt;/h2&gt;

&lt;p&gt;Simple interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your fixed company details&lt;/li&gt;
&lt;li&gt;client information&lt;/li&gt;
&lt;li&gt;service lines&lt;/li&gt;
&lt;li&gt;currency / VAT&lt;/li&gt;
&lt;li&gt;your fixed banking details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PDF is generated directly in the browser and sent to the client by email.&lt;/p&gt;

&lt;p&gt;No data is sent to the server before validation.&lt;/p&gt;

&lt;p&gt;Once the quote is sent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a secure link is sent to the client&lt;/li&gt;
&lt;li&gt;the client can view and sign the quote online&lt;/li&gt;
&lt;li&gt;the quote is archived&lt;/li&gt;
&lt;li&gt;you receive a confirmation email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The quote then becomes a signed contract.&lt;/p&gt;




&lt;h2&gt;
  
  
  Invoicing
&lt;/h2&gt;

&lt;p&gt;The system includes a smart client lookup.&lt;/p&gt;

&lt;p&gt;You only need to enter a single piece of information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email&lt;/li&gt;
&lt;li&gt;SIRET / SIREN&lt;/li&gt;
&lt;li&gt;client name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and the system automatically retrieves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the client’s details&lt;/li&gt;
&lt;li&gt;their existing quotes (a list is suggested in the quote field)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most recent quote is automatically suggested.&lt;/p&gt;

&lt;p&gt;You simply select the correct quote from the list.&lt;/p&gt;

&lt;p&gt;The system retrieves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;service lines&lt;/li&gt;
&lt;li&gt;amounts&lt;/li&gt;
&lt;li&gt;client information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If no quote exists, the invoice can be generated directly with a free service description.&lt;/p&gt;

&lt;p&gt;Once validated, the system immediately generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the invoice&lt;/li&gt;
&lt;li&gt;the stamped invoice (pre-generated)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The invoice is sent to the client and archived.&lt;/p&gt;

&lt;p&gt;The stamped version is stored while waiting for payment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Payment confirmation
&lt;/h2&gt;

&lt;p&gt;The interface lists all pending invoices.&lt;/p&gt;

&lt;p&gt;One click is enough to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mark the invoice as paid&lt;/li&gt;
&lt;li&gt;send the stamped invoice&lt;/li&gt;
&lt;li&gt;add the entry to the revenue journal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system also allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;monthly invoice export (ZIP)&lt;/li&gt;
&lt;li&gt;monthly revenue export (CSV)&lt;/li&gt;
&lt;li&gt;annual revenue journal export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All data is stored in simple files.&lt;/p&gt;

&lt;p&gt;No database.&lt;/p&gt;




&lt;p&gt;This system is designed to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;autonomous&lt;/li&gt;
&lt;li&gt;installable on any PHP hosting&lt;/li&gt;
&lt;li&gt;bilingual FR / EN&lt;/li&gt;
&lt;li&gt;fully documented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data stays with the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com/en/invoicing-without-saas" rel="noopener noreferrer"&gt;https://palks-studio.com/en/invoicing-without-saas&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This is the type of systems I design at Palks Studio:&lt;/p&gt;

&lt;p&gt;simple tools that automate complete business processes.&lt;/p&gt;

&lt;p&gt;If you want to install this system on your own infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;a href="mailto:contact@palks-studio.com"&gt;contact@palks-studio.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you're interested in how it works under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a technical breakdown of the system architecture.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Billing System is a suite of three interconnected billing tools accessible from a unified interface. It covers the full lifecycle of a service engagement: from quote generation to invoice settlement, including electronic signature and structured archiving.&lt;/p&gt;

&lt;p&gt;The system is designed to be deployed directly on the client's server, on a standard Apache hosting environment with PHP 8.x and Composer. It requires no database, no third-party service, and no subscription.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Client-side quote PDF generation (jsPDF)
&lt;/li&gt;
&lt;li&gt;Server-side invoice PDF generation (Dompdf)
&lt;/li&gt;
&lt;li&gt;Automatic pre-generation of the paid invoice at billing time
&lt;/li&gt;
&lt;li&gt;Electronic quote signing by the client (touch/mouse canvas)
&lt;/li&gt;
&lt;li&gt;Client auto-fill from archives (SIREN, SIRET, VAT, email, name)
&lt;/li&gt;
&lt;li&gt;Structured archiving by client and period
&lt;/li&gt;
&lt;li&gt;Secure sequential numbering (file lock)
&lt;/li&gt;
&lt;li&gt;Monthly export of invoices (ZIP)
&lt;/li&gt;
&lt;li&gt;Monthly export of revenue records (CSV)
&lt;/li&gt;
&lt;li&gt;Yearly export of the revenue journal (CSV)
&lt;/li&gt;
&lt;li&gt;Automatic email notifications at each stage (quote, invoice, settlement)
&lt;/li&gt;
&lt;li&gt;Cross-module navigation bar
&lt;/li&gt;
&lt;li&gt;Bilingual FR/EN interface with real-time language switch
&lt;/li&gt;
&lt;li&gt;Dark mode / light mode with persistence
&lt;/li&gt;
&lt;li&gt;No database
&lt;/li&gt;
&lt;li&gt;No SaaS dependency
&lt;/li&gt;
&lt;li&gt;Basic security: secure sessions, tokens, brute-force protection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;billing-system/
│
├── public/
│   │  └── assets/
│   │      ├── logo*              → Company logo if provided
│   │      ├── signature.png      → User signature used on quotes and invoices (PNG format)
│   │      └── favicon*           → Optional favicon displayed in the browser tab
│   │
│   ├── Endpoint a                → Quote generation endpoint
│   ├── Endpoint b                → Invoice generation endpoint
│   ├── Endpoint c                → Direct invoice generation endpoint
│   ├── Endpoint d                → Paid invoice generation endpoint
│   │
│   ├── Interface a               → Quote generation interface
│   ├── Interface b               → Direct invoice generation interface
│   ├── Interface c               → Payment tracking interface
│   ├── sign.php                  → Signature interface
│   ├── export a                  → Archived invoices ZIP export
│   ├── export b                  → Revenue journal CSV export
│   │
│   ├── search.php                → Client search and auto-fill
│   ├── serve.php                 → Secure PDF access via token
│   └── save.php                  → Quote save and archiving
│
├── vendor/                       → Libraries used by the document generation engine
├── templates/                    → HTML templates used for document rendering
│
├── app.php                       → Central configuration for issuer and bank details
├── mailer.php                    → Internal email sending script with attachments
├── core.php                      → Main engine: generation logic, calculations and archiving
├── LICENSE.md                    → Project license
│
├── contracts/                    → Signed and unsigned quote archiving
├── counters/                     → Numbering counters (quotes and invoices)
├── logs/                         → System logs (optional)
├── data/                         → Operational data
│
└── docs/
    ├── USER_GUIDE.md             → User guide
    ├── OVERVIEW.md               → Project overview and general system description
    └── README.md                 → Installation and usage documentation (client version)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you want to explore the technical implementation, you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/billing-system" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/billing-system&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>freelance</category>
      <category>automation</category>
      <category>business</category>
      <category>backend</category>
    </item>
    <item>
      <title>You don’t need a backend to generate quotes</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Sun, 08 Mar 2026 19:29:21 +0000</pubDate>
      <link>https://forem.com/palks_studio/building-a-free-quote-generator-with-no-backend-pdf-generated-in-the-browser-4f5m</link>
      <guid>https://forem.com/palks_studio/building-a-free-quote-generator-with-no-backend-pdf-generated-in-the-browser-4f5m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxn8z8dvfbfx8cddjulf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxn8z8dvfbfx8cddjulf.png" alt="Example of a generated quote (PDF output)" width="800" height="1131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a quote should be simple.
&lt;/h2&gt;

&lt;p&gt;Yet most tools require:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;account creation
&lt;/li&gt;
&lt;li&gt;email registration
&lt;/li&gt;
&lt;li&gt;server-side storage
&lt;/li&gt;
&lt;li&gt;sometimes even a subscription.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to try a different approach.&lt;/p&gt;

&lt;p&gt;A quote generator that runs entirely in the browser.&lt;/p&gt;

&lt;p&gt;No backend.&lt;br&gt;&lt;br&gt;
No API.&lt;br&gt;&lt;br&gt;
No database.&lt;/p&gt;

&lt;p&gt;You can test it here:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com/fr/generateur-devis" rel="noopener noreferrer"&gt;https://palks-studio.com/fr/generateur-devis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool generates a professional PDF quote directly in the browser without sending any data to a server.&lt;/p&gt;


&lt;h2&gt;
  
  
  Everything runs in the browser
&lt;/h2&gt;

&lt;p&gt;Everything happens client-side.&lt;/p&gt;

&lt;p&gt;User fills the form&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
JavaScript processes the data&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
PDF is generated locally&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
Browser downloads the file&lt;/p&gt;

&lt;p&gt;No network request is required.&lt;/p&gt;

&lt;p&gt;The only external dependency is the jsPDF library.&lt;/p&gt;


&lt;h2&gt;
  
  
  Generating PDFs directly in JavaScript
&lt;/h2&gt;

&lt;p&gt;The generator relies on jsPDF to build the document directly in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once loaded, creating a PDF is straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsPDF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jspdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;jsPDF&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, everything can be drawn directly into the document.&lt;/p&gt;




&lt;h2&gt;
  
  
  The form mirrors the final document
&lt;/h2&gt;

&lt;p&gt;The form mirrors a real quote structure.&lt;/p&gt;

&lt;p&gt;It contains:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;issuer information
&lt;/li&gt;
&lt;li&gt;client information
&lt;/li&gt;
&lt;li&gt;quote metadata
&lt;/li&gt;
&lt;li&gt;service lines
&lt;/li&gt;
&lt;li&gt;totals
&lt;/li&gt;
&lt;li&gt;payment details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your company&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"issuer_name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"issuer_email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"issuer_phone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each section of the form maps directly to a block inside the generated PDF.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quotes need flexible line items
&lt;/h2&gt;

&lt;p&gt;Quotes require flexible service lines.&lt;/p&gt;

&lt;p&gt;Users can dynamically add or remove rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;line-row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;input name="lines[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;][desc]"&amp;gt;
    &amp;lt;input name="lines[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;][qty]" type="number"&amp;gt;
    &amp;lt;input name="lines[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;][price]" type="number"&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each line contains:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;description
&lt;/li&gt;
&lt;li&gt;quantity
&lt;/li&gt;
&lt;li&gt;unit price
&lt;/li&gt;
&lt;li&gt;VAT rate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Totals update instantly when values change.&lt;/p&gt;




&lt;h2&gt;
  
  
  All calculations happen instantly
&lt;/h2&gt;

&lt;p&gt;All calculations are transparent and client-side.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateTotals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;vatTotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.line-row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name*="[qty]"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name*="[price]"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vat&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name*="[tva]"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lineHT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qty&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;lineHT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;vatTotal&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;lineHT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;vat&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;vatTotal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI immediately displays:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subtotal
&lt;/li&gt;
&lt;li&gt;VAT
&lt;/li&gt;
&lt;li&gt;Total amount&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;before the PDF is generated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Turning form data into a document
&lt;/h2&gt;

&lt;p&gt;When the user confirms, the script builds the document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jsPDF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jspdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;jsPDF&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the script draws the document:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;header
&lt;/li&gt;
&lt;li&gt;issuer block
&lt;/li&gt;
&lt;li&gt;client block
&lt;/li&gt;
&lt;li&gt;service table
&lt;/li&gt;
&lt;li&gt;totals
&lt;/li&gt;
&lt;li&gt;notes
&lt;/li&gt;
&lt;li&gt;footer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;QUOTE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quoteNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every field comes directly from the form inputs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keeping the layout stable
&lt;/h2&gt;

&lt;p&gt;PDF layout can break when text becomes longer than expected.&lt;/p&gt;

&lt;p&gt;To prevent layout issues, the generator wraps text dynamically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitTextToSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each block calculates its own height before being drawn.&lt;/p&gt;

&lt;p&gt;This prevents overlapping elements and keeps the layout stable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a backend is unnecessary here
&lt;/h2&gt;

&lt;p&gt;For this type of tool, a backend is often unnecessary.&lt;/p&gt;

&lt;p&gt;Running everything in the browser provides several advantages.&lt;/p&gt;

&lt;p&gt;Privacy.&lt;/p&gt;

&lt;p&gt;No data is transmitted to any server.&lt;/p&gt;

&lt;p&gt;Simplicity.&lt;/p&gt;

&lt;p&gt;No authentication, no database, no API.&lt;/p&gt;

&lt;p&gt;Lightweight hosting.&lt;/p&gt;

&lt;p&gt;The entire generator is essentially a single HTML page.&lt;/p&gt;

&lt;p&gt;It can run on:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;static hosting
&lt;/li&gt;
&lt;li&gt;GitHub Pages
&lt;/li&gt;
&lt;li&gt;any simple web server&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What this approach does not solve
&lt;/h2&gt;

&lt;p&gt;This approach also has some limitations.&lt;/p&gt;

&lt;p&gt;There is no:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quote history
&lt;/li&gt;
&lt;li&gt;client management
&lt;/li&gt;
&lt;li&gt;automated emailing
&lt;/li&gt;
&lt;li&gt;electronic signature workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for generating quick quotes, it works extremely well.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this tool is designed for
&lt;/h2&gt;

&lt;p&gt;The goal was not to build a SaaS product.&lt;/p&gt;

&lt;p&gt;The goal was to build a tool that is:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple
&lt;/li&gt;
&lt;li&gt;frictionless
&lt;/li&gt;
&lt;li&gt;immediately usable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No login.&lt;/p&gt;

&lt;p&gt;No tracking.&lt;/p&gt;

&lt;p&gt;No data collection.&lt;/p&gt;

&lt;p&gt;Just a form and a downloadable PDF.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;You can test it here:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com/en/quote-generator" rel="noopener noreferrer"&gt;https://palks-studio.com/en/quote-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works on:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;desktop
&lt;/li&gt;
&lt;li&gt;mobile
&lt;/li&gt;
&lt;li&gt;any modern browser&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Sometimes simpler is better
&lt;/h2&gt;

&lt;p&gt;Modern web tools often become unnecessarily complex.&lt;/p&gt;

&lt;p&gt;For some use cases, a simple client-side application is more than enough.&lt;/p&gt;

&lt;p&gt;A single HTML file with JavaScript can already provide:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a structured form
&lt;/li&gt;
&lt;li&gt;dynamic calculations
&lt;/li&gt;
&lt;li&gt;professional PDF generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes simplicity is the best solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/free-quote-generator" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/free-quote-generator&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Generating Factur-X is easy. Making it valid is not.</title>
      <dc:creator>Palks Studio</dc:creator>
      <pubDate>Wed, 04 Mar 2026 21:46:31 +0000</pubDate>
      <link>https://forem.com/palks_studio/building-a-factur-x-en16931-engine-from-scratch-what-actually-took-time-2bg2</link>
      <guid>https://forem.com/palks_studio/building-a-factur-x-en16931-engine-from-scratch-what-actually-took-time-2bg2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmc4g8rqlxzue9ci0ae9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmc4g8rqlxzue9ci0ae9.png" alt="Factur-X EN16931 pipeline — structured invoicing engine" width="800" height="1131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I started working on B2B e-invoicing, I thought the technical part would be straightforward. Generate a PDF, embed an XML, follow a standard. On paper, it seemed linear.&lt;/p&gt;

&lt;p&gt;In practice, it's something else entirely.&lt;/p&gt;

&lt;p&gt;Here's what actually took time — not the concepts, but the details that break everything in production.&lt;/p&gt;

&lt;p&gt;The Comfort profile is not declared — it is earned&lt;/p&gt;

&lt;p&gt;EN16931 defines several profiles. The Comfort profile, the one that guarantees real interoperability with accounting systems, requires strict identifier completeness.&lt;/p&gt;

&lt;p&gt;SIREN alone is not enough. SIRET alone is not enough. The combination of SIREN + SIRET + VAT number determines the profile declared in the XML. If one identifier is missing, the profile changes. And an incorrect profile means a technically invalid invoice — even if it looks perfectly fine visually.&lt;/p&gt;

&lt;p&gt;I implemented conditional validation logic before generation. No silent correction, no approximation. Either the data is complete, or the invoice does not go out.&lt;/p&gt;

&lt;p&gt;Multi-period invoicing is a state problem, not a calculation problem&lt;/p&gt;

&lt;p&gt;Invoicing across multiple months in a single document seems simple. It is not.&lt;/p&gt;

&lt;p&gt;The real issue: a period included in an issued invoice is permanently closed. It cannot be re-invoiced, partially modified, or cancelled. This is not a software constraint — it is a legal and accounting one.&lt;/p&gt;

&lt;p&gt;I had to model an explicit state system per period and per client, using immutable archiving flags. No database — only locked, deterministic and traceable files.&lt;/p&gt;

&lt;p&gt;Deduplication without a database&lt;/p&gt;

&lt;p&gt;The classic question: how do you prevent issuing the same invoice twice if the process is restarted?&lt;/p&gt;

&lt;p&gt;My answer: file-based locks. Each execution cycle checks for the existence of a lock file before generating anything. No race condition, no distributed transaction, no external dependency. One execution = one deterministic cycle. If the file exists, skip. Otherwise, generate and lock.&lt;/p&gt;

&lt;p&gt;Simple, traceable, reliable.&lt;/p&gt;

&lt;p&gt;The pipeline runs on cron — no background process, no service to keep alive&lt;/p&gt;

&lt;p&gt;No persistent process running in the background, no service to maintain active, no SaaS dependency. The engine triggers, processes, archives and stops. Each execution is independent and reproducible.&lt;/p&gt;

&lt;p&gt;This architectural choice has a direct consequence: if something goes wrong, there is nothing to restart, nothing to debug live. Logs are exhaustive, states are explicit, generated files are evidence.&lt;/p&gt;

&lt;p&gt;What I take from this&lt;/p&gt;

&lt;p&gt;Factur-X is not a PDF generation problem. It is a structured pipeline problem — controlled states and normalized data before production.&lt;br&gt;
Tools that "generate Factur-X" are plentiful. Systems that guarantee end-to-end compliance, full traceability and zero implicit correction are far less common.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palks-studio.com/en/batch-invoicing-facturx" rel="noopener noreferrer"&gt;https://palks-studio.com/en/batch-invoicing-facturx&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you're interested in how it works under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a technical breakdown of the system architecture.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview Project
&lt;/h2&gt;

&lt;p&gt;This repository presents a financial automation system designed to handle:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invoice generation (single &amp;amp; batch)
&lt;/li&gt;
&lt;li&gt;revenue tracking
&lt;/li&gt;
&lt;li&gt;payment reconciliation
&lt;/li&gt;
&lt;li&gt;client balances
&lt;/li&gt;
&lt;li&gt;accounting-ready exports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system is deterministic, auditable, and explicit by design.&lt;/p&gt;

&lt;p&gt;It operates:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;without a database
&lt;/li&gt;
&lt;li&gt;without a CMS
&lt;/li&gt;
&lt;li&gt;without a SaaS dependency
&lt;/li&gt;
&lt;li&gt;without any exposed web interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All executions run server-side, via CLI scripts and cron, with a strict separation of responsibilities.&lt;/p&gt;

&lt;p&gt;This project is not a product, not a SaaS, and not a plug-and-play tool.&lt;br&gt;&lt;br&gt;
It documents a production-grade approach to financial automation.&lt;/p&gt;

&lt;p&gt;Over time, the engine has been progressively extended&lt;br&gt;&lt;br&gt;
to cover real-world business cases,&lt;br&gt;&lt;br&gt;
without compromising its original design principles.&lt;/p&gt;

&lt;p&gt;The billing system now supports:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multi-line invoices
&lt;/li&gt;
&lt;li&gt;multiple VAT rates per invoice
&lt;/li&gt;
&lt;li&gt;complex or extended service periods
&lt;/li&gt;
&lt;li&gt;multi-month billing scenarios
&lt;/li&gt;
&lt;li&gt;complex combinations while remaining EN16931 Comfort compliant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This functional expansion did not alter&lt;br&gt;&lt;br&gt;
the deterministic, auditable, and traceable nature of the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Electronic invoicing (Factur-X)
&lt;/h3&gt;

&lt;p&gt;The system natively integrates Factur-X electronic invoicing (hybrid PDF with embedded XML),&lt;br&gt;&lt;br&gt;
in compliance with the European EN 16931 standard (Comfort profile):  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generation of a semantically EN 16931-compliant Factur-X XML
&lt;/li&gt;
&lt;li&gt;XML validation (XSD and Schematron)
&lt;/li&gt;
&lt;li&gt;injection of the XML into the PDF
&lt;/li&gt;
&lt;li&gt;production of a single final document: the Factur-X hybrid PDF
&lt;/li&gt;
&lt;li&gt;direct integration into the &lt;code&gt;run.php&lt;/code&gt; and &lt;code&gt;run_batch.php&lt;/code&gt; pipelines
&lt;/li&gt;
&lt;li&gt;no parallel formats
&lt;/li&gt;
&lt;li&gt;no persistent XML storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system targets business compliance and e-invoicing interoperability (France / EU).&lt;br&gt;&lt;br&gt;
PDF/A compliance (document archiving) is not a functional objective of the project and is deliberately out of scope.&lt;/p&gt;

&lt;p&gt;Factur-X is handled as a native component of the engine,&lt;br&gt;&lt;br&gt;
not as an external or optional module.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;automation_finance/
│
├── engine/                           → Core automation engine (billing, generation, processing)
├── data/                             → Internal data storage (clients, invoices, tracking)
├── tools/                            → Internal utilities and maintenance scripts
├── exports/                          → Data export and reporting
├── downloads/                        → Generated document delivery
├── clients/                          → Client configuration
├── contracts/                        → Legal and contractual documents
│
├── LICENCE.md                        → Conditions d’utilisation et cadre légal (FR)
├── LICENSE.md                        → Terms of use and legal Framework
│
├── LICENCE.md                        → Conditions d’utilisation et cadre légal (FR)
├── LICENSE.md                        → Terms of use and legal Framework
│
└── docs/
    ├── README_FR.md                  → Documentation générale du système (FR)
    ├── README.md                     → General system documentation
    │
    ├── SERVICE_MEMO_FR.md            → Note interne de positionnement du service (FR)
    ├── SERVICE_MEMO.md               → Internal Service Positioning Memo
    │
    ├── README_DEPLOY_FR.md           → Guide d’installation et d’exploitation (FR)
    ├── README_DEPLOY_EN.md           → Installation and Production Guide
    │
    ├── VUE_DENSEMBLE_AUTOMATION.md   → Vue d’ensemble du système d’automatisation de facturation (FR)
    └── SYSTEM_OVERVIEW_AUTOMATION.md → Billing Automation System Overview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you want to explore the technical implementation, you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Palks-Studio/automation-finance" rel="noopener noreferrer"&gt;https://github.com/Palks-Studio/automation-finance&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://palks-studio.com" rel="noopener noreferrer"&gt;https://palks-studio.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>payments</category>
      <category>php</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
