MVP Specification
Last updated: 2026-04-02
1. Product summary
Build a self-contained Phoenix application for publishing static artifacts under stable URLs.
Supported artifact types in MVP:
- HTML presentation decks
- plain HTML reports
- markdown documents rendered to HTML
The product should optimize for fast, pleasant publishing UX for Martin and Otto.
2. MVP goals
Must achieve
- publish or update an artifact at a stable slug
-
serve it under
https://share.martin-dobberstein.de/<slug> - optionally protect each artifact with its own Basic Auth credentials
- generate memorable 6-word passphrases by default
- support relative attachments (png, svg, etc.)
- maintain current index and archive index
- store everything in PostgreSQL
- expose an API for Otto-driven publishing
- provide simple admin UI with login for Martin
Explicit non-goals
- collaborative editing
- WYSIWYG authoring
- version history
- rollback
- draft/publish states
- per-user artifact permissions
- audit logs
- advanced analytics
- comments
- SVG extraction from embedded HTML
3. Primary personas
Martin (human operator)
Needs:
- see what is published
- see whether a publication is public/protected
- reveal/copy credentials
- archive/unarchive items
- occasionally create or edit items manually
Otto (API operator)
Needs:
- create/update publication from generated artifacts
- upload entrypoint and attachments in one flow
- request generated password
- receive resulting URL and password in response
4. URL and routing behavior
Public routes
-
/— current publication index -
/archive— archived publication index -
/:slug— publication entry page -
/:slug/assets/:filename— attachment serving
Stability guarantees
- publication URLs do not change after archive
- archive flag only affects index placement, not route shape
5. Publication model
Each publication contains:
- slug
- title
- description (optional)
- notes (optional)
- tags (optional, can be deferred in implementation if necessary)
- publication_month
- archived_at (nullable)
-
auth mode (
publicorbasic_auth) - username
- generated/manual passphrase
- view_count
-
entry_type (
htmlormarkdown) - entry_body
- source_path/origin metadata (optional)
- timestamps
Attachments
Each publication may have 0..n attachments:
- filename
- content_type
- binary data
- size_bytes
6. Auth behavior
Publication access
Each publication is either:
- public
- protected by HTTP Basic Auth
Protected default behavior
When a protected publication is created without explicit credentials:
- generate username/password automatically
-
default admin convention can be simple username such as
share - password should be a 6-word memorable hyphen-separated passphrase
Credential storage
To satisfy both UX and security requirements:
- store encrypted plaintext credentials for admin reveal
- store a password hash for verification
7. Content rendering behavior
HTML entrypoint
- returned as HTML response
- application rewrites nothing by default beyond any minimal needed asset URL conventions
-
relative references should work via
./assets/<filename>
Markdown entrypoint
- rendered server-side to HTML
-
markdown may reference relative attachments via
./assets/<filename> - output should use a consistent document wrapper/template for readability
8. API surface (MVP)
API should be sufficient for Otto to publish artifacts without UI.
Required operations
- Create or overwrite publication
- Upload/replace entrypoint body
- Upload/replace attachments
- Set auth mode
- Generate password automatically or accept manual password
- Archive/unarchive publication
- List publications
- Fetch publication metadata including revealable credentials (admin-authenticated)
Recommended endpoint shape
-
POST /api/publications -
PUT /api/publications/:slug -
GET /api/publications -
GET /api/publications/:slug -
POST /api/publications/:slug/archive -
POST /api/publications/:slug/unarchive
Actual endpoint naming can be adjusted during implementation.
9. Admin UI (MVP)
Authentication
-
generated via
mix phx.gen.auth -
initial admin user:
-
username/email/login identifier:
mart - password: generated 6-word passphrase
-
username/email/login identifier:
Required pages
- login page
- publication list
- publication detail/edit page
- create publication page
- archive list view
Required actions
- create publication
- edit title/slug/entrypoint/auth settings
- reveal password
- regenerate password
- upload attachments
- archive/unarchive
10. Index pages
/
Shows non-archived publications with at least:
- title
- slug/url
- type
- public/protected indicator
- publication month
- short description if present
/archive
Shows archived publications grouped by publication month.
Individual item links should still point to the same /:slug route.
11. View counter
MVP metric:
- increment simple total hit count when publication entry page is viewed successfully
No need for:
- uniqueness
- IP/user tracking
- dashboards
12. Constraints
- all storage in existing PostgreSQL
- artifact sizes expected under 10 MB
- low traffic expected
- no external object storage required
- no extra fancy infrastructure should be introduced in MVP
13. Acceptance criteria
MVP is successful if Otto can:
- call the API with title + slug + HTML/Markdown body + attachments
- request protected mode with generated password
- receive URL + credentials
- immediately access the artifact via stable URL
- later update the same slug without redeploying the application
- archive it without breaking the URL
And Martin can:
- log into admin UI
- see current and archived publications
- reveal or regenerate per-publication credentials
- manually edit/archive/unarchive when needed