Telas Paraná
Telas Paraná: perimeter fencing and protection, Londrina/PR. 40 years, three generations.
the_problem
A 40-year-old fencing company whose only inbound channel was the telephone and word of mouth. No contact capture, no marketing attribution, no record of who asked for a quote. Every lead that did not call at that exact moment was lost.
what_it_does
- One-page institutional site built for conversion: hero, figures, products, services, segments, completed works, testimonials and contact.
- Every call to action composes a contextual message and opens WhatsApp already filled in, the business’s real conversion path.
- Lead capture with name, WhatsApp, e-mail, interest and LGPD consent, stored in a dedicated schema with UTM tracking.
- Full customer authentication: traditional signup plus Google social login through a server-side BFF, a protected account area, signup completion for incomplete Google accounts, and avatar upload.
- Live Google reviews through the Places API, filtered to four stars and above, with a static fallback.
- A 25-photo WebP gallery in three categories, a self-built institutional video player that pauses when it leaves the viewport, and dark/light theming with no flash.
stack
frontend
Next.js (App Router) · TypeScript · Tailwind CSS v4 · Vitest
backend
C# / .NET 10 · ASP.NET Core · EF Core 10 + Npgsql · PostgreSQL 16 · xUnit + Moq
infra
Google Cloud · Terraform · Cloud Run · Cloud SQL · GitHub Actions
measured
- Commits
- 368git history, 2026-03-24 to 2026-06-28
- Shipped version
- v2.4.6README changelog
- Environments provisioned by Terraform
- 3envs/ holds DEV, HML, PROD
how_it_was_built
Evolved through numbered versions with a changelog kept in the README, v1.0.0 to v2.4.6. The pattern visible in the history: each version ships functionality, and the next version is almost always security hardening of what just shipped. v2.1.0 delivered auth; v2.1.1 fixed JWT signature verification, an open redirect, and avatar MIME handling. v2.4.0 delivered avatars; v2.4.1 replaced PBKDF2 with Argon2id at OWASP parameters: 19 MiB, two iterations, parallelism one.
v2.4.2 was a full remediation following a cybersecurity and LGPD audit: an anti-pwn-request guard in the deployment pipeline, rate limiting by real client IP behind Cloud Run via forwarded headers, atomic refresh-token rotation with reuse detection that revokes the entire family, timing-based user-enumeration mitigation on login, CPF masked in responses, personal data removed from JWT claims, nonce-based CSP enforced, and non-root containers on base images pinned by digest.
Security is a track of its own, with numbered issues traced through to a validated production apply. v2.4.4 closed the public exposure of the users API (invoker restricted to the frontend service account, service-to-service authentication by Google ID token) and migrated avatars from a public bucket to a private one served through an authenticated proxy.
Infrastructure is Terraform end to end, with modules and per-environment configuration for DEV, HML and PROD: three applications on Cloud Run, Postgres on Cloud SQL, six secrets in Secret Manager, images in Artifact Registry, and three least-privilege service accounts. Continuous delivery runs on GitHub Actions with Workload Identity Federation, so no service-account key is ever committed.
known_limitations
- Allowed-hosts validation is deferred, and the README says why: pinning the wrong list takes the Cloud Run deployment down, and the gain is marginal behind the existing setup.
- The HS256 signing secret is shared between the users API and the BFF. Migrating to RS256 is recorded as low priority rather than as an oversight.
- E-mail verification on traditional signup is still pending. Google login already arrives with a verified address, so the gap only affects one of the two signup paths.
roadmap
- v2.5: lead CRM panel
- v2.6: contact validation by token
- v2.7: AI/RAG chatbot qualifying leads against the catalogue
- v2.8: payments and marketplace
- Migration to GKE as traffic requires it
tracked coding time
6 hrs 43 mins Source: WakaTime · tracked 2026-03-17 to current