feat: replace DiceBear avatar proxy with local Multiavatar SVG generation and remove avatar_style from signup
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
# DevPlace — The Developer Social Network
|
||||
|
||||
Server-rendered social network for developers. FastAPI backend serving Jinja2 templates with ES6 interactivity. Avatar generation via DiceBear proxy. SQLite storage via `dataset`.
|
||||
Server-rendered social network for developers. FastAPI backend serving Jinja2 templates with ES6 interactivity. Avatar generation via Multiavatar (local, no network). SQLite via `dataset` with WAL mode and concurrency tuning.
|
||||
|
||||
[](.gitea/workflows/test.yaml)
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
make install # pip install -e .
|
||||
make dev # uvicorn --reload on port 10500
|
||||
make test # 95 Playwright integration tests, headless
|
||||
make test # 129 Playwright integration + unit tests, headless, fail-fast
|
||||
make test-headed # same tests in visible browser
|
||||
make demo # absurd full-journey demo (headed)
|
||||
make demo # full-journey GUI demo (headed)
|
||||
```
|
||||
|
||||
Open `http://localhost:10500`.
|
||||
@@ -18,13 +20,14 @@ Open `http://localhost:10500`.
|
||||
|
||||
| Layer | Technology |
|
||||
|-------|-----------|
|
||||
| Backend | Python 3.13+, FastAPI, Uvicorn |
|
||||
| Backend | Python 3.13+, FastAPI, Uvicorn (single worker) |
|
||||
| Templates | Jinja2 (server-side rendered) |
|
||||
| Frontend | Pure ES6 JavaScript, one class per file |
|
||||
| Database | SQLite via `dataset` (auto-sync schema, `uid` PKs) |
|
||||
| Database | SQLite via `dataset` (auto-sync schema, `uid` PKs, WAL mode, 30s busy timeout) |
|
||||
| Auth | Session cookies, SHA256+SALT via passlib |
|
||||
| Avatars | DiceBear 9.x via local proxy (`/avatar/{style}/{seed}`) |
|
||||
| Avatars | Multiavatar (local SVG generation, no external API, <5ms) |
|
||||
| Validation | `hawk` (Python/JS/CSS/HTML) |
|
||||
| Load testing | Locust (locustfile.py) |
|
||||
|
||||
## Project structure
|
||||
|
||||
@@ -34,9 +37,9 @@ devplacepy/
|
||||
config.py # Settings from env vars + .env
|
||||
database.py # dataset connection, index creation
|
||||
templating.py # Shared Jinja2 environment + globals
|
||||
avatar.py # DiceBear styles, URL generation
|
||||
avatar.py # Multiavatar generation, URL builder
|
||||
utils.py # Password hashing, session mgmt, time_ago
|
||||
models.py # Pydantic schemas (validated but unused in routes)
|
||||
models.py # Pydantic schemas
|
||||
routers/ # One file per domain (auth, feed, posts, ...)
|
||||
templates/ # Jinja2 HTML templates
|
||||
static/css/ # Page-specific CSS files
|
||||
@@ -47,7 +50,7 @@ devplacepy/
|
||||
|
||||
| Prefix | Purpose |
|
||||
|--------|---------|
|
||||
| `/auth` | Signup, login, logout |
|
||||
| `/auth` | Signup, login, logout, forgot/reset password |
|
||||
| `/feed` | Post feed with topic/tab filtering |
|
||||
| `/posts` | Post detail, creation |
|
||||
| `/comments` | Comment creation, deletion |
|
||||
@@ -55,12 +58,9 @@ devplacepy/
|
||||
| `/profile` | Profile view, editing |
|
||||
| `/messages` | Direct messaging |
|
||||
| `/notifications` | Notification list, mark read |
|
||||
| `/votes` | Upvote/downvote on posts and comments |
|
||||
| `/avatar` | DiceBear avatar proxy with caching |
|
||||
|
||||
## API
|
||||
|
||||
No REST API — everything is form-based POST + redirect. All state lives in the session cookie. Endpoints return HTML or redirect.
|
||||
| `/votes` | Upvote/downvote on posts, comments, projects |
|
||||
| `/follow` | Follow/unfollow users |
|
||||
| `/avatar` | Multiavatar proxy with in-memory cache |
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -69,22 +69,60 @@ No REST API — everything is form-based POST + redirect. All state lives in the
|
||||
| `DEVPLACE_DATABASE_URL` | `sqlite:///devplace.db` | Database connection string |
|
||||
| `SECRET_KEY` | hardcoded fallback | Session signing key |
|
||||
|
||||
## Database
|
||||
|
||||
SQLite via `dataset` with production-oriented pragmas set on every connection:
|
||||
|
||||
```sql
|
||||
PRAGMA journal_mode=WAL; -- concurrent readers + writers
|
||||
PRAGMA synchronous=NORMAL; -- safe with WAL, faster than FULL
|
||||
PRAGMA busy_timeout=30000; -- wait 30s instead of failing on lock
|
||||
PRAGMA cache_size=-8000; -- 8MB page cache
|
||||
PRAGMA temp_store=MEMORY; -- temp tables in memory
|
||||
PRAGMA mmap_size=268435456; -- 256MB memory map for reads
|
||||
```
|
||||
|
||||
All indexes are created via `CREATE INDEX IF NOT EXISTS` wrapped in try/except — safe to run on every startup regardless of table state.
|
||||
|
||||
## Testing
|
||||
|
||||
- **95 integration tests** across 9 files using Playwright (NOT pytest-playwright plugin)
|
||||
- **129 tests** across 13 files: 95 Playwright integration tests + 34 unit tests
|
||||
- Playwright (NOT pytest-playwright plugin — conflicts, uninstall it)
|
||||
- Server starts as subprocess on port 10501 with isolated temp database
|
||||
- Test users `alice_test` / `bob_test` seeded via HTTP at session start
|
||||
- Tests stop at first failure (`-x` flag)
|
||||
- Failure screenshots auto-save to `/tmp/devplace_test_screenshots/`
|
||||
- Headed mode: `PLAYWRIGHT_HEADLESS=0 make test`
|
||||
|
||||
### Key test patterns
|
||||
|
||||
- Every `page.goto()` and `page.wait_for_url()` uses `wait_until="domcontentloaded"` — avatar images don't block test execution
|
||||
- Session-scoped browser context with per-test cookie clearing
|
||||
- `page.locator(...).wait_for(state="visible")` preferred over bare selectors
|
||||
|
||||
## Avatars
|
||||
|
||||
Uses [Multiavatar](https://github.com/multiavatar/multiavatar-python) — generates deterministic SVG avatars locally from a seed string (the username). No external API calls, no network dependency. Generation takes <5ms. Results are cached in-memory (cleared on server restart).
|
||||
|
||||
Avatar URL format: `/avatar/multiavatar/{username}?size={size}`
|
||||
|
||||
## CI/CD
|
||||
|
||||
Gitea Actions workflow at `.gitea/workflows/test.yaml`:
|
||||
- Runs on push/PR to main
|
||||
- Sets up Python 3.13, installs dependencies + Playwright
|
||||
- Validates all source files with `hawk`
|
||||
- Runs all 129 tests with fail-fast
|
||||
- Uploads failure screenshots as artifacts
|
||||
|
||||
## Feature workflow
|
||||
|
||||
1. Implement the feature (router + template + CSS + JS)
|
||||
2. `hawk .` — validate all source files
|
||||
3. `make test` — run all 95 tests headless
|
||||
4. If adding new functionality, write Playwright tests in `tests/test_*.py`
|
||||
5. For visual features, take a screenshot and verify with `falcon describe`
|
||||
6. Update `AGENTS.md` if any new conventions were introduced
|
||||
3. `make test` — run all 95 tests (fail-fast)
|
||||
4. Add Playwright tests in `tests/test_*.py` for new functionality
|
||||
5. For visual features: `falcon take --output /tmp/verify.png && falcon describe /tmp/verify.png`
|
||||
6. Update `AGENTS.md` and `README.md` if new conventions were introduced
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user