Production Case Study
This lesson explains what the Flaxon Labs organization website proves and how to build a similar application. It is a working reference architecture: public Jinax pages, authenticated Admin, schema-driven CMS, persistent PostgreSQL data, Redis coordination, Blob media, SMTP account mail, and Vercel deployment.
Flaxon can support a real organization site with editable projects, documentation, releases, posts, community forms, custom Admin pages, authentication, migrations, health checks, and production service configuration. The external database, Redis, storage, mail provider, backups, monitoring, and worker platform remain deployment responsibilities.
1. Create the application
mkdir flaxon-labs-app
cd flaxon-labs-app
py -m venv .venv
.venv\Scripts\Activate.ps1
pip install "flaxon[standard,security]==0.2.4" psycopg[binary] redis
flaxon init .
2. Bootstrap Flaxon, Jinax, Admin, and CMS
import os
from flaxon import Flaxon
from flaxon.jinax import Jinax
from flaxon.admin import AdminConfig, AdminDashboard
from flaxon.admin.cms import CMS, CMSField, ContentType
app = Flaxon("organization", debug=False)
app.use_templates(Jinax("templates"))
# Attach a configured PostgreSQL adapter before creating Admin/CMS.
database = app.database
admin = AdminDashboard(
app,
config=AdminConfig(site_title="Organization Admin"),
database=database,
redis_url=os.environ.get("REDIS_URL"),
)
cms = CMS(
app,
url_prefix="/admin/cms",
auth=admin.auth,
database=database,
redis_url=os.environ.get("REDIS_URL"),
)
cms.register(ContentType(
"project",
fields=[
CMSField("title", required=True),
CMSField("summary", required=True),
CMSField("body", type="richtext"),
CMSField("status", type="select", choices=["draft", "published"]),
],
list_display=["title", "status", "updated_at"],
list_filter=["status"],
search_fields=["title", "summary", "body"],
))
3. Add public pages
@app.get("/")
async def home(request):
await cms._load_database()
projects = [
item for item in cms.content_types["project"].items.values()
if item.get("status") == "published"
]
return await request.render("home.html", {"projects": projects})
@app.get("/api/health")
async def health(request):
return {"ok": True, "service": "organization"}
4. Production environment
FLAXON_ENV=production
FLAXON_SECRET_KEY=generate-a-random-value-at-least-32-characters
DATABASE_URL=postgresql://user:password@host/database?sslmode=require
REDIS_URL=rediss://default:password@host:6379
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_...
BLOB_PUBLIC_URL=https://...public.blob.vercel-storage.com
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=mailer@example.com
SMTP_PASSWORD=provider-app-password
SMTP_FROM=Organization <mailer@example.com>
SMTP_TLS=true
FLAXON_ADMIN_USERNAME=admin
FLAXON_ADMIN_PASSWORD=replace-with-a-strong-password
FLAXON_ADMIN_EMAIL=admin@example.com
Keep secrets in Vercel, a CI secret store, or the host environment. Never commit an .env file. Use a pooled PostgreSQL URL for serverless workloads and configure Redis for shared sessions, rate limits, locks, and cross-worker events.
5. Migrate and create the first Admin user
flaxon migrate --database $env:DATABASE_URL --migrations-dir migrations
python scripts/create_admin.py admin --email admin@example.com --password "use-a-unique-password"
flaxon run app:app --host 0.0.0.0 --port 8000
Open /admin/login for the Admin dashboard and /admin/cms/ for content editing. Add CSRF fields to every browser form and require permissions inside custom routes, even when the UI hides actions.
6. Deploy to Vercel
{
"builds": [{"src": "app.py", "use": "@vercel/python"}],
"routes": [{"src": "/(.*)", "dest": "app.py"}]
}
vercel link
vercel env add DATABASE_URL production
vercel env add REDIS_URL production
vercel env add FLAXON_SECRET_KEY production
vercel --prod
7. Verify the workflow
- Run migrations against the same database used by deployment.
- Log in, create a project, publish it, and confirm the public page reads the record.
- Upload media and confirm metadata is stored separately from the Blob object.
- Test reset and verification mail using a real SMTP provider.
- Run
python -m pytest --no-cov -qand browser smoke tests before release. - Check health, error logs, backups, rate limits, and worker jobs from the hosting platform.
Architecture decisions
Use Admin for authenticated operational data and CMS for editorial content. Keep public route handlers thin and read published content from the CMS store. Use durable database storage for users, settings, revisions, audit records, and forms. Use Redis when more than one process can serve requests. Run scheduled publishing, thumbnail work, and retries on a durable external worker rather than relying on a serverless request.
Next customization
Register a new ContentType for products, events, or releases; add a Jinax template under templates/; and add a permission-protected custom Admin route. This is the same extension pattern used by the Flaxon Labs reference site.