1
Fork 0
blog-flutter/README.md
Leonardo Devai 1b31c9b8ee Review and modernize all 42 projects to the updated standard
Pinned 2026 toolchains (Go 1.26, Rust 1.98/edition 2024, Python 3.14 + uv, Node 24,
Zig 0.16, NixOS 26.05), postgres 18 / mongo 8, lockfiles built from, non-root
runtimes, .dockerignore, per-project LICENSE, READMEs with the git.devai.io clone
line, checkout@v7 CI. Security fixes in the legacy Rust APIs (any-password login,
self-assigned admin, hard-coded JWT secret), JWT alg/exp/sub enforcement across the
blog series, safe markdown links in the frontends, and many smaller bugs — every
project was built, run and exercised end to end.

Adds scripts/publish.sh + a CI publish job that splits every folder into its own
repo at git.devai.io/templates/<folder>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01128fhuZbgivaSJvtMf4s1G
2026-09-27 21:10:38 +02:00

3.6 KiB

blog-flutter

The blog client as a Flutter app — Material 3, a post list, a post screen with rendered markdown, login, and an editor with a publish switch. Plain setState plus one ChangeNotifier for auth — no state-management package, no code generation. It works against any backend of the devai.io blog engine series.

Run

Get it: git clone https://git.devai.io/templates/blog-flutter.git

Only lib/, pubspec.yaml, pubspec.lock and analysis_options.yaml ship here — no platform shells. Generate the ones you want once, then run (Flutter 3.47):

flutter create --empty --platforms=android,ios,web .
flutter run --dart-define=API_URL=http://localhost:8080

--empty keeps flutter create from adding a sample test that refers to its own demo app. Start a backend sibling first (e.g. docker compose up --build in blog-go-postgres), then create a user, since there is no sign-up screen:

curl -X POST localhost:8080/auth/register -H 'Content-Type: application/json' \
  -d '{"email":"me@example.com","password":"secret123"}'

How it works

The API base URL is a compile-time constant, String.fromEnvironment('API_URL'), defaulting to http://localhost:8080; pass --dart-define=API_URL=... to flutter run or flutter build. On the Android emulator use http://10.0.2.2:8080 to reach a backend on your machine. Mobile and desktop builds call the API directly; a web build is subject to CORS, which the series backends do not send, so serve it behind a proxy on the API's origin instead.

ApiClient (a ChangeNotifier) keeps the JWT from POST /auth/login in memory and sends Authorization: Bearer <token>; the app bar swaps between Log in and Write / Log out as it changes. The token is not persisted — add shared_preferences to ApiClient if sessions should survive a restart.

Markdown is turned into Flutter widgets (Text.rich spans), never HTML; links are styled but not tappable.

The API never returns unpublished posts, so the editor keeps a freshly saved draft open; switch on Published and save again to make it public.

API calls used:

POST   /auth/login          {email, password} -> {token}
GET    /posts               -> [{id, title, slug, excerpt, published_at}]
GET    /posts/{slug}        -> full post
POST   /posts        (auth) {title, body} -> post (unpublished)
PUT    /posts/{id}   (auth) {title?, body?, published?} -> post
DELETE /posts/{id}   (auth) -> 204

Layout

lib/main.dart                  app shell, Material 3 light and dark themes
lib/api.dart                   ApiClient: auth state + typed API calls
lib/markdown.dart              dependency-free markdown → widgets
lib/screens/posts_screen.dart  published posts, pull to refresh
lib/screens/post_screen.dart   full post; edit/delete when signed in
lib/screens/login_screen.dart  email + password → JWT
lib/screens/editor_screen.dart create/edit with publish switch

Deploy

A device app ships through the app stores (flutter build appbundle, flutter build ipa), not to a server, so there is no Dockerfile or compose file. Push to your own GitHub repo and the shipped workflow (.github/workflows/ci.yml) clones Flutter 3.47.4 from the official repository and runs flutter pub get --enforce-lockfile and flutter analyze.


Part of devai.io — the blog frontend series, one API and four clients: blog-react, blog-angular, blog-dart, blog-flutter.