Initial commit: postcard v1

Phone photo -> composited postcard (canvas templates, stamp corner,
EXIF-aware date/location, self-hosted handwriting font) with a small
server for share links, day-context caption drafting off goonk's
day-summary API, and Nominatim reverse geocoding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-08-06 19:49:03 +02:00
co-authored by Claude Sonnet 5
commit cf0f5fca2c
24 changed files with 2839 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
import express from 'express'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { config } from './config.js'
import { apiRouter, imageRouter } from './routes.js'
import { sweepExpiredPostcards, startCleanupJob } from './cleanup.js'
const app = express()
// Deployed behind a reverse proxy in production — needed for accurate
// req.ip in the rate limiter.
app.set('trust proxy', true)
// Mounted before the static frontend and before any body parser: the
// upload route reads the raw request stream itself and must not have it
// consumed by express.json()/express.raw() first.
app.use('/api', apiRouter)
app.use('/', imageRouter)
const staticRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
app.use(express.static(staticRoot))
sweepExpiredPostcards()
startCleanupJob()
app.listen(config.port, () => {
console.log(`postcard server listening on :${config.port}`)
})