Agencies and freelancers
Client portal for an agency or freelancer

What you get
- A private space per client
- Project status at a glance
- Files to download
- Approve or request changes in one click
- An activity log per client
The prompt
Change the names, prices and details to yours. Your AI needs LazyFrog connected first: two minutes.
Use LazyFrog to build a client portal for my design studio: each client signs in to their own private space with their project status, files to download and designs to approve, and never sees another client's. For the look: quiet luxury for a design studio, off-black on pure white with one terracotta accent, a wide-spaced geometric sans, lots of empty space, a split-screen sign-in with the studio's work filling the left half, and each client space headed by its project's cover image.
The live demo
What Codex built from that prompt on 14 November 2026, in about 6 minutes, then published as an example. Try it: what you add is put back every night.
| Maison client | maison@example.com | demo12345 |
|---|---|---|
| Forma client | forma@example.com | demo12345 |
The full spec
The same app with every detail named: the pages, fields and tables. Use it when you want exactly this app; the short prompt leaves those choices to your AI.
Use LazyFrog to build a client portal for my design studio. Each client has their own space and their own sign-in (email and password at /login), and a client never sees anything of another client's: every query is scoped to the signed-in client, and an id from another client's space answers 404. Clients go in a table called clients (name, slug, email, project_status as a short line such as "Second design draft"), files in files (client_id, filename, path, uploaded_at; kept privately in the project's file store and downloaded only by that client), approvals in approvals (client_id, title, description, status as pending, approved or changes_requested, comment, decided_at) and everything that happens in activity (client_id, what, at), where what says what happened and to what, such as "Requested changes on Homepage: a bigger logo". A client's home page shows the project status, their files, their pending approvals with an Approve button and a Request changes button that asks for a comment, and their activity. My team works under /admin, protected with LazyFrog's protected pages (I'll choose the password in the portal): add clients (which makes their account and an invitation link where they choose their password, emailed through my own email provider when one is connected and shown to me to send myself either way), set the project status, upload files and ask for approvals. Add a JSON API: POST /api/login with {"email", "password"} answers {"token"}, which the other /api routes take as Authorization: Bearer; GET /api/approvals, GET /api/files and GET /api/activity list the client's own; POST /api/approvals/<id>/approve, and POST /api/approvals/<id>/request-changes with {"comment"}; for my team, POST /admin/api/approvals with {"client" (the slug), "title", "description"} answers {"id"}, and POST /admin/api/files (multipart: client and the file in the field file) uploads one. Start with two example clients, a bakery (slug example-bakery) and a florist (slug example-florist), each with a status, two files, an approval and some activity. So I can try both spaces, make demo sign-ins bakery@example.com and florist@example.com in the preview only (when LF_ENV is preview; never on the live site), with the password the app reads from the secret DEMO_PASSWORD, which I add myself in the portal (Project › Secrets): don't set the preview's value, show it or write it anywhere; make or update those accounts from it whenever the app starts, and none while it isn't set. The live site has no demo accounts; so that publishing isn't refused for a secret set only on the preview, also set DEMO_PASSWORD for production yourself (secrets set with env production) to a long random value the live site never uses.
The full spec was built and checked on LazyFrog on 31 October 2026. It took about 9 minutes.