You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Silberengel e62e8604a4 correct updates from relays 5 days ago
assets speed up app 6 days ago
bin Authenticate user with a NostrSigner. Prep for long form articles. 1 year ago
config correct updates from relays 5 days ago
docker/cron correct updates from relays 5 days ago
docs Footer links 9 months ago
frankenphp correct updates from relays 5 days ago
migrations Downsizing: Clean up db migration and provide no-magazine fallback 9 months ago
public Static pages, service worker, manifest 11 months ago
publication/Newsroom Downsizing: remove nzines 9 months ago
scripts correct updates from relays 5 days ago
src correct updates from relays 5 days ago
templates speed up app 6 days ago
tests Security 11 months ago
translations Downsizing: remove nzines 9 months ago
.dockerignore setup remote build 6 days ago
.editorconfig Symfony from dunglas/symfony-docker 1 year ago
.env.dist correct updates from relays 5 days ago
.env.test Authenticate user with a NostrSigner. Prep for long form articles. 1 year ago
.gitattributes Symfony from dunglas/symfony-docker 1 year ago
.gitignore Reorganize configs 12 months ago
Dockerfile speed up app 6 days ago
LICENSE Initial commit 1 year ago
Makefile correct updates from relays 5 days ago
README.md correct updates from relays 5 days ago
compose.hub.yaml setup remote build 6 days ago
compose.override.yaml correct updates from relays 5 days ago
compose.prod.yaml Downsizing: cleanup 9 months ago
compose.yaml correct updates from relays 5 days ago
composer.json correct updates from relays 5 days ago
composer.lock correct updates from relays 5 days ago
importmap.php speed up app 6 days ago
package.json Quill editor basics 1 year ago
phpunit.xml.dist Authenticate user with a NostrSigner. Prep for long form articles. 1 year ago
symfony.lock Downsizing: cleanup 9 months ago

README.md

Unfold: Imwald

Imwald

A Symfony + FrankenPHP site that reads Nostr long-form articles (kind 30023) and related data from relays, stores articles in MySQL, and serves pages with Twig. Comments and profile metadata are cache-backed (not the full source of truth in the DB).


Requirements

Requirement Version / notes
PHP ≥ 8.3.13 (see composer.json)
Docker Optional; recommended for local dev and production images
Database MySQL 8.0 (configurable)

Local development (Docker)

  1. Env: copy .env.dist to .env and adjust if needed (especially APP_SECRET outside dev).

  2. Start stack

    docker compose up -d
    
  3. App URL (default): http://127.0.0.1:9080
    Port comes from HTTP_PORT in .env and compose.override.yaml (loopback only).

  4. First-time DB: migrations run on php container start when migrations/ contains PHP files (see frankenphp/docker-entrypoint.sh).

Service Role
php FrankenPHP + Caddy, Symfony app, console
database MySQL; dev exposes 127.0.0.1:3307 → 3306 for local clients
cron Runs full app:prewarm every 10 minutes; repo bind-mounted at /var/www/html (see docker/cron/)

To migrate, import articles from Nostr for a time window, then prewarm magazine indices, author metadata, and comment caches:

make prewarm
Step (script order) Command / effect
1 docker compose up -d --wait — starts php, database, and cron (the cron image runs a full app:prewarm on a 10 min schedule)
2 doctrine:migrations:migrate
3 articles:get -- '-2 month' 'now' — sync long-form into MySQL for that window
4 app:prewarm — magazine 30040, kind-0 profiles, comment cache (default --comments-max=20, newest by createdAt)

make prewarm brings the stack (including cron) up so scheduled prewarm is active. Optional extra arguments for the cron-scheduled app:prewarm go in .env as PREWARM_FLAGS (same as you might pass to php bin/console app:prewarm …); Compose passes them into the cron container. Example: PREWARM_FLAGS="--metadata-limit=50 --no-magazine". Restart the cron service after changing PREWARM_FLAGS so the container reloads the env. Hub / compose.hub.yaml has no cron service; use a host timer or exec if you need the same there.


Console commands (overview)

Command Purpose
articles:get <from> <to> Pull long-form articles from Nostr for the time range, persist to DB
app:prewarm Magazine relay refresh + metadata cache + comment cache warm
doctrine:migrations:migrate Apply SQL migrations
user:elevate (If used) user elevation helper

php bin/console list and … -h for full options.

app:prewarm (notable options)

Option Default Meaning
--no-magazine off Skip magazine 30040 index
--no-metadata off Skip Nostr kind-0 / profile cache
--no-comments off Skip comment thread cache
--metadata-limit 0 (all authors) Cap distinct author pubkeys
--metadata-batch 50 Pubkeys per batched Nostr REQ
--comments-max 20 Newest N articles (by createdAt DESC); 0 = all (still bounded by budget)
--comments-budget 120 Max wall seconds for the comments phase
--magazine-budget 30 Max wall seconds for magazine refresh

Prewarm clears the PHP CLI execution time limit for that run; relay work can be slow.

PREWARM_ON_START (optional)

Variable Set where Effect
PREWARM_ON_START=1 Compose environment on the php service (not only Symfony .env inside the container) After DB is up and migrations run, executes app:prewarm once on start. Does not run articles:get.

For a full Nostr backfill + one-shot prewarm, use make prewarm (or a host cron / systemd timer) instead of relying on PREWARM_ON_START alone.


Configuration

What File
Site title, npub, d_tag, relays (default_relay, article_relays, profile_relays), theme config/unfold.yaml (imported as Symfony parameters)
DATABASE_URL, APP_SECRET, HTTP_PORT, MYSQL_*, optional PREWARM_FLAGS (for the Docker cron service) .env / .env.local (see .env.dist)
Service wiring (e.g. cache, NostrClient args) config/services.yaml

Relays (short): default_relay and article_relays drive article sync and many queries; profile_relays are used first for kind-0 / profile fetches, then the merged default + article set (see NostrClient).


Production / Hub image

Topic Notes
compose.hub.yaml Runs a pulled image (default silberengel/unfold:latest), no local PHP app build. Override with UNFOLD_DOCKER_IMAGE.
HTTP publish HTTP_PUBLISH in .env (default 9080 → container 80). Set TRUSTED_PROXIES behind a reverse proxy.
Secrets Set APP_SECRET and DB credentials in real env; do not commit production secrets.

File header in compose.hub.yaml lists pull, migrate, and optional build/push one-liners.


License

MIT — see LICENSE.


Configurable under parameters.external_links in config/unfold.yaml (e.g. Unfold on GitHub, Decent Newsroom). Adjust for your deployment.