Family Allowance Certificate Upload and Validation System (Salario Familiar)
Province-wide digitization of a paper-based procedure: average processing time down from 4 months to 5 weeks, with a concentrated annual cycle of 20,000 to 30,000 case files and close to 50,000 files, on a legacy stack and without being able to install a single external library.
The Entre Ríos Provincial Education Council (Consejo General de Educación) is the governing body of the education system in the province of Entre Ríos, Argentina. The system is province-wide: it's used by all school staff — teachers, principals, administrative and support staff — not just the Council's own employees.
- PHP 7
- SQL Server
- JavaScript
- jQuery
- AJAX
- Bootstrap
- Upload
- Validation 1
- Validation 2
- Payroll
- Approved
Rejected: back to upload

Press
The agency's official article (in Spanish) credits me as “programador y creador del sistema”.
Se presentó la nueva modalidad de carga de documentación de asignaciones familiaresConsejo General de Educación de Entre Ríos · 04/04/2024
- Processing time
- 4 months → 5 weeks
- Requests per cycle
- 20,000–30,000
- Files processed
- ≈50,000
Average per request, before and after
A single annual cycle of 3 to 4 months
2 files and 2 validation stages per request
The problem
The family allowance procedure was done on paper. Each school kept its own paper forms, and the documents traveled to the Payroll department to be validated by hand.
The volume isn't continuous: it's concentrated in a single three-to-four-month cycle each year, with 20,000 to 30,000 requests. Each request carries two files and goes through two validation stages, so the cycle moves around 50,000 files in a short window.
On paper there was no way to answer two basic questions: where is my request, and who validated what. Without traceability, every inquiry was a manual search.
Constraints
- Non-negotiable legacy stack: PHP 7 and SQL Server. The agency wasn't going to migrate for this project.
- Technical constraint set by the agency: no external libraries could be installed. Anything that didn't ship with PHP had to be written.
- Mandatory integration with SAGE, the province's school management system already in use.
- The end users are all school staff in the province, the vast majority with no technical background and uneven connectivity.
- The peak is seasonal and can't be postponed: if the system fails during the cycle, the procedure doesn't wait until next year.
Decisions
Write the file-upload security layer from scratch, in plain PHP
File uploads are the most dangerous attack surface of a public system: if it accepts anything, the server ends up running whatever it's sent. With no libraries available, I implemented real type validation, filename sanitization and access control on downloads, all with the language's own primitives.
Trade-off: In-house security code is in-house code to maintain and audit, without the years of public scrutiny an established library has behind it. I accepted it because the alternative wasn't using a library, it was not validating at all.
Auditing and traceability inside the data model, not as an attached log
In a procedure that affects someone's paycheck, the question “who validated this and when” isn't a diagnostic: it's part of the case file. Modeling it in the database, rather than in a separate log file, turns the answer into a query instead of an investigation.
Trade-off: More writes per request and a heavier schema. In exchange, the traceability can't be lost or rotated away by accident.
Two validation stages per request
Splitting validation makes it possible to stop an incomplete case file before it reaches payroll, which is where an error costs real money and rework.
Trade-off: One more step for the user and twice the files to process. The cost is paid during the cycle; the error, in someone's salary.
Document in two formats: a written manual and tutorial videos
I wrote the manuals as PDFs, but for a province-wide audience with no technical background a document isn't enough: some people will never open it. I also directed the tutorial videos, which show the real screen step by step and were shared with the entire education community. It wasn't choosing one or the other: it was covering both the people who read and the people who don't.
Trade-off: Two materials to maintain instead of one. If the interface changes, both have to be redone, and the video is the expensive one. For a system with a single cycle per year, the trade is worth it.
Architecture
PHP 7 backend on SQL Server, with the database modeled around the case file and its validation states. The frontend is JavaScript with jQuery and AJAX so that uploading and tracking don't require reloading the page on slow connections. The file layer is separate from the rest: it receives, validates, sanitizes and only then persists, and every download goes through access control instead of being served straight from the filesystem. Tracking queries and bulk loading are optimized for the cycle's peak, which is when the system is really put to the test.
Outcome
- Cut the average processing time from 4 months to 5 weeks.
- Eliminated paper forms at every school in the province.
- Presented at an official event in the Education Council's auditorium in April 2024.
- The agency's official press release credits me as the system's programmer and creator. It's the most verifiable item in my profile, because I didn't write it.
What I'd do differently today
- I'd move validation out of the request. During the cycle's peak, doing all the work synchronously turns every slowdown into a wait for the user; a simple queue would have absorbed the peak without touching the experience.
- I'd take the files off the application's filesystem. Separate storage with short-lived signed URLs reduces the attack surface and means growth no longer depends on the server's disk.
- I'd write automated tests for the upload layer. It's the riskiest component and the one I touched by hand the most: exactly where a test suite pays for itself.
- I raised the no-external-libraries constraint and documented it in writing at the time; it was never lifted. What I'd change today isn't having pushed back, but how: bring it as a concrete risk with an estimated cost instead of a technical argument. In a public agency a constraint moves when someone can sign off on the risk, not when they understand the reasoning.