- Add production checklist section for Resend inbound on bilhej.se - Note that mail is read in the Resend dashboard unless a webhook is added later - Update GDPR letter footer example in REQUIREMENTS.md to kontakt@bilhej.se Co-authored-by: Cursor <cursoragent@cursor.com>
587 lines
27 KiB
Markdown
587 lines
27 KiB
Markdown
# BilHej / Bilhälsning.se — Requirements Document
|
||
|
||
> **Note:** This file is loaded by OpenCode via `AGENTS.md` as an external
|
||
> instruction source. It is referenced by `opencode.json` instructions.
|
||
|
||
> **Version:** 0.1.0 (Draft)
|
||
> **Date:** April 2026
|
||
> **Status:** Pre-development
|
||
|
||
---
|
||
|
||
## 1. Executive Summary
|
||
|
||
BilHej (Bilhälsning.se) is a web platform that allows Swedish residents to contact the owner of a vehicle by entering a registration number, composing a message, and having a physical letter printed and mailed. The platform acts as a trusted intermediary — the user never sees the recipient's name or address. Revenue comes from charging users per letter, with a hybrid subscription + pay-as-you-go model.
|
||
|
||
---
|
||
|
||
## 2. Project Vision
|
||
|
||
A driver sees a car parked on the street. They want to:
|
||
- Compliment the owner on their well-kept Volvo 240
|
||
- Express interest in buying the car
|
||
- Let the owner know their tire is flat or lights were left on
|
||
- Give feedback about driving behavior or a honking incident
|
||
|
||
They visit Bilhälsning.se on their phone, enter the plate, write a short message, pay 49 SEK — and a physical letter arrives in the owner's mailbox 1–3 days later. The sender remains anonymous unless they choose to include their contact details in the letter body.
|
||
|
||
---
|
||
|
||
## 3. Target Users
|
||
|
||
- **Sender:** Swedish resident, 18+, with email and a payment method
|
||
- **Recipient:** Swedish vehicle owner (never directly interacts with the platform)
|
||
|
||
---
|
||
|
||
## 4. Data Flow & Privacy Design
|
||
|
||
```
|
||
Sender BilHej Third Parties
|
||
────── ────── ─────────────
|
||
Enters plate ──────────→ Plate number stored
|
||
Composes letter ───────→ Letter content stored
|
||
Pays (Stripe/Swish) ───→ Payment recorded
|
||
│
|
||
├─→ Transportstyrelsen: owner address lookup
|
||
│ (address used to mail envelope, then DELETED)
|
||
│
|
||
├─→ PostNord/Strålfors: letter content + address
|
||
│ (print, envelope, mail, return tracking ID)
|
||
│
|
||
Receives confirmation ←── Tracking + order status
|
||
```
|
||
|
||
**Key principles:**
|
||
- The sender never sees the recipient's name or address
|
||
- The recipient's address is only used transiently — obtained, used for envelope addressing, then deleted
|
||
- The recipient's name is never stored by BilHej
|
||
- Letter content is stored only for order history and moderation purposes
|
||
- The letter itself serves as GDPR Art. 14 notification (informs recipient their address was accessed)
|
||
|
||
---
|
||
|
||
## 5. Functional Requirements
|
||
|
||
### F1 — User Account (Sender)
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Registration | Email + password |
|
||
| Login | Email + password |
|
||
| Account page | View order history, manage subscription |
|
||
| Auth method | JWT tokens (Spring Security + stateless sessions) |
|
||
|
||
**Rationale:** BankID is not required. The user never accesses personal data — BilHej
|
||
(the company) is the sole data controller querying Transportstyrelsen. Email+password
|
||
keeps the user experience simple and avoids BankID integration costs and GDPR
|
||
complexity on the user side.
|
||
|
||
### F2 — License Plate Input
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Input | Registration number (e.g., "ABC123") |
|
||
| Validation | Swedish plate format (3 letters + 3 digits, or 3 letters + 2 digits + 1 letter) |
|
||
| Lookup — public vehicle info | Transportstyrelsen's open vehicle data (make, model, year, color). This is publicly available and free/low-cost. |
|
||
| Lookup — owner address | Transportstyrelsen "Fråga om fordonsägare" or "Fordonsregisterkund" API. NOT shown to the sender. Used internally to address the envelope. |
|
||
|
||
**Phase 0 (hobby/manual):** The vehicle info lookup can optionally use a free/open dataset or the Transportstyrelsen SMS service for make/model. Owner address is obtained manually via the "Fråga om fordonsägare" form.
|
||
|
||
**Phase 1 (business/automated):** Direct API integration with Transportstyrelsen as a "Fordonsregisterkund" for automated owner address lookup.
|
||
|
||
### F3 — Letter Composer
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Template selection | Choose a pre-written template or "Fritt meddelande" |
|
||
| Text editor | Textarea with character limit (e.g., 1000 chars) |
|
||
| Preview | Rendered preview showing exactly what the recipient will see (A4 page) |
|
||
| Sender identity | Optional: include name/email/phone in letter body. Default: anonymous |
|
||
| Language | Swedish (expandable to English later) |
|
||
|
||
### F4 — Letter Templates
|
||
|
||
| # | Template name | Purpose | Legal risk |
|
||
|---|---------------|---------|------------|
|
||
| 1 | **Komplimang** | Compliment on the car | Low |
|
||
| 2 | **Jag vill köpa din bil** | Purchase interest inquiry | Low |
|
||
| 3 | **Tips / servicebehov** | Heads-up about flat tire, lights, etc. | Low |
|
||
| 4 | **Synpunkter på körbeteende** | Feedback about driving behavior | **Medium** |
|
||
| 5 | **Tuta / frustration** | Honking incident follow-up (worded diplomatically) | **Medium** |
|
||
| 6 | **Fritt meddelande** | Free text, sender's own words and responsibility | Low (user liability) |
|
||
|
||
Templates 4 and 5 should always include clear disclaimers and respectful wording.
|
||
If legal counsel advises against them, merge them into "Fritt meddelande" where
|
||
the user assumes full responsibility for content.
|
||
|
||
### F5 — Payment Wall
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Triggers | After letter is composed and sender clicks "Send" |
|
||
| Before payment | Sender sees: plate number, vehicle info (if available), letter preview |
|
||
| After payment | Letter is queued for processing and dispatch |
|
||
| Payment provider | Stripe (cards + Swish) |
|
||
| Price tiers | See Section 10 |
|
||
|
||
### F6 — Letter Sending & Tracking
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Phase 0 (manual) | Owner address obtained via Transportstyrelsen form → manual print + envelope + PostNord "Digitalt frimärke" (22 SEK, no tracking) or Varubrev (22 SEK, tracked) → manual status update |
|
||
| Phase 1 (automated) | PostNord "Skicka Direkt" API or Strålfors API → print + envelope + mail + automatic tracking |
|
||
| Tracking (automated) | PostNord returns shipment ID → poll for status (CREATED → IN_TRANSIT → DELIVERED) |
|
||
| Tracking (manual) | Varubrev shipment ID entered manually |
|
||
| User-facing status | "Skickat", "På väg", "Levererat" |
|
||
|
||
### F7 — Order History
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Access | Authenticated users only |
|
||
| Contents | Date, plate number, template used, status, tracking link (if available) |
|
||
| Letter content | Stored for sender's reference |
|
||
| No PII | Recipient address/name NEVER shown, NEVER stored after sending |
|
||
|
||
### F8 — Admin Panel
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Access | Internal only (admin credentials) |
|
||
| Template management | Create/edit/disable letter templates |
|
||
| Order overview | View all orders, statuses, revenue |
|
||
| Moderation queue | Review "Fritt meddelande" content if flagged |
|
||
| Blocklist | Manage opt-out list (recipients who don't want letters) |
|
||
| Revenue dashboard | Stripe integration for transaction overview |
|
||
|
||
---
|
||
|
||
## 6. Non-Functional Requirements
|
||
|
||
| ID | Requirement | Detail |
|
||
|----|-------------|--------|
|
||
| N1 | Responsive design | Mobile-first. Most users will be on a phone, standing next to a car. |
|
||
| N2 | Page load time | <2 seconds on 4G mobile |
|
||
| N3 | Security | HTTPS, password hashing (bcrypt), JWT expiration, input sanitization |
|
||
| N4 | Privacy | Address deleted after PostNord dispatch. No PII logs. |
|
||
| N5 | Availability | Phase 0: best-effort (home server). Phase 1: 99.5% uptime |
|
||
| N6 | Localization | Swedish UI (expandable to English) |
|
||
| N7 | Audit log | Every address lookup logged with plate, timestamp, purpose. Required by Transportstyrelsen for API users. |
|
||
|
||
---
|
||
|
||
## 7. Technical Architecture
|
||
|
||
### Stack
|
||
|
||
| Layer | Technology |
|
||
|-------|-----------|
|
||
| Frontend | Vue.js 3 (Composition API), Vite, Pinia state management, Vue Router |
|
||
| Backend API | Java 21, Spring Boot 4, Spring Security (JWT), Spring Data JPA |
|
||
| Database | PostgreSQL 16 |
|
||
| Deployment | Docker, Docker Compose |
|
||
| Hosting (Phase 0) | Home server via dynamic DNS or static IP, Let's Encrypt SSL |
|
||
| Hosting (Phase 1) | Swedish VPS provider (Binero, FS Data, Elastx) |
|
||
| Payment | Stripe (Checkout / Payment Intents) — supports Swish + cards |
|
||
| Mail API (Phase 1) | PostNord "Skicka Direkt" or Strålfors Document Delivery API |
|
||
|
||
### Architecture Diagram
|
||
|
||
```
|
||
┌──────────────────────────────────────────┐
|
||
│ Internet │
|
||
│ │
|
||
│ ┌──────────────┐ ┌───────────────┐ │
|
||
│ │ User Phone │ │ User Desktop │ │
|
||
│ └──────┬───────┘ └───────┬───────┘ │
|
||
└─────────┼─────────────────────┼──────────┘
|
||
│ HTTPS │
|
||
┌─────────▼─────────────────────▼──────────┐
|
||
│ Nginx (reverse proxy) │
|
||
│ Let's Encrypt SSL │
|
||
└──────────────────┬───────────────────────┘
|
||
│
|
||
┌──────────────────▼───────────────────────┐
|
||
│ Vue.js 3 SPA (Vite) │
|
||
│ Port: 3000 (dev) │
|
||
│ Served as static files │
|
||
└──────────────────┬───────────────────────┘
|
||
│ REST API calls
|
||
┌──────────────────▼───────────────────────┐
|
||
│ Spring Boot 4 (Java 21) │
|
||
│ Port: 8080 │
|
||
│ ┌────────────┐ ┌────────────────────┐ │
|
||
│ │ Spring │ │ Service Layer │ │
|
||
│ │ Security │ │ - LetterService │ │
|
||
│ │ (JWT) │ │ - LookupService │ │
|
||
│ │ │ │ - MailService │ │
|
||
│ │ │ │ - PaymentService │ │
|
||
│ └────────────┘ └────────┬───────────┘ │
|
||
│ │ │
|
||
│ ┌────────────▼───────────┐ │
|
||
│ │ PostgreSQL 16 │ │
|
||
│ │ Port: 5432 │ │
|
||
│ └────────────────────────┘ │
|
||
└──────────────────┬───────────────────────┘
|
||
│
|
||
┌──────────────┼──────────────┐
|
||
▼ ▼ ▼
|
||
┌────────┐ ┌──────────┐ ┌──────────┐
|
||
│ Trans- │ │ PostNord │ │ Stripe │
|
||
│ port- │ │ / │ │ (cards + │
|
||
│ styrel │ │ Strålfors│ │ Swish) │
|
||
│ sen │ │ API │ │ │
|
||
└────────┘ └──────────┘ └──────────┘
|
||
```
|
||
|
||
### Database Schema (Core Tables)
|
||
|
||
```
|
||
users
|
||
id UUID PK
|
||
email VARCHAR(255) UNIQUE NOT NULL
|
||
password_hash VARCHAR(255) NOT NULL
|
||
created_at TIMESTAMP
|
||
subscription ENUM('none', 'basic', 'pro')
|
||
|
||
orders
|
||
id UUID PK
|
||
user_id UUID FK → users
|
||
plate VARCHAR(10) NOT NULL
|
||
template VARCHAR(50)
|
||
letter_text TEXT NOT NULL
|
||
status ENUM('pending_payment','paid','lookup_started','sent','delivered','failed')
|
||
amount_paid DECIMAL(10,2)
|
||
tracking_id VARCHAR(100)
|
||
created_at TIMESTAMP
|
||
updated_at TIMESTAMP
|
||
|
||
templates
|
||
id UUID PK
|
||
name VARCHAR(100)
|
||
body_template TEXT
|
||
is_active BOOLEAN
|
||
|
||
blocklist
|
||
id UUID PK
|
||
plate VARCHAR(10) UNIQUE
|
||
reason VARCHAR(255)
|
||
created_at TIMESTAMP
|
||
|
||
audit_log
|
||
id UUID PK
|
||
plate VARCHAR(10)
|
||
action VARCHAR(50)
|
||
timestamp TIMESTAMP
|
||
ip_address VARCHAR(45)
|
||
```
|
||
|
||
---
|
||
|
||
## 8. API Integrations
|
||
|
||
### 8.1 Transportstyrelsen
|
||
|
||
| Aspect | Phase 0 (Hobby) | Phase 1 (Business) |
|
||
|--------|----------------|-------------------|
|
||
| Method | "Fråga om fordonsägare" form (manual) | "Fordonsregisterkund" API (automated) |
|
||
| What you get | Owner name + address | Owner name + address (programmatic) |
|
||
| Cost | ~10–15 SEK per request | ~3–5 SEK per query (estimated) |
|
||
| Turnaround | Days (manual processing) | Seconds (API) |
|
||
| Setup | None (open to individuals) | Formal application + agreement required |
|
||
| Name/address stored by BilHej | No (deleted after envelope is addressed) | No (deleted after envelope is addressed) |
|
||
|
||
**Open questions for Transportstyrelsen:**
|
||
- Can a small business / enskild firma get API access, or do they require a minimum volume?
|
||
- What is the actual per-query cost?
|
||
- What are the formal GDPR/data processing agreement requirements?
|
||
- How does the "Fordonsregisterkund" API handle address-update frequency (dagsaktuella uppgifter)?
|
||
|
||
**Email template for Transportstyrelsen:**
|
||
> Hej,
|
||
> Jag planerar att starta en tjänst där privatpersoner kan skicka brev till fordonsägare
|
||
> via registreringsnummer. Tjänsten fungerar så att avsändaren aldrig ser mottagarens
|
||
> adress — det är endast vi som mellanhand som hanterar adressen för att posta brevet,
|
||
> varefter adressen raderas.
|
||
> Jag undrar:
|
||
> 1. Kan vi som mindre företag få tillgång till ägaruppgifter via ert API
|
||
> (Fordonsregisterkund)?
|
||
> 2. Vad kostar det per uppslag?
|
||
> 3. Vilka krav ställer ni gällande GDPR och personuppgiftshantering?
|
||
> 4. Finns det någon minimivolym?
|
||
> Tack på förhand.
|
||
|
||
### 8.2 PostNord / Strålfors
|
||
|
||
| Service | Description | Cost (est.) | Tracking |
|
||
|---------|-------------|------------|----------|
|
||
| PostNord "Digitalt frimärke" | Buy postage digitally, print and mail yourself | 22 SEK (50g letter) | No |
|
||
| PostNord Varubrev 1:a klass | Tracked letter, postage only | ~22 SEK (50g) | Yes (basic) |
|
||
| PostNord "Skicka Direkt" API | Print + envelope + mail, fully automated | ~12–18 SEK total (estimated) | Yes |
|
||
| Strålfors Document Delivery API | Print + envelope + mail, enterprise grade | ~8–15 SEK total (estimated) | Yes (webhook) |
|
||
|
||
PostNord API access is free. You only pay for postage/services.
|
||
|
||
**Open questions for PostNord:**
|
||
- What is the actual price for "Skicka Direkt" (print + mail) for a single-page A4 letter?
|
||
- Is there a minimum volume?
|
||
- Can we get a business account as an enskild firma?
|
||
|
||
### 8.3 Stripe
|
||
|
||
| Detail | Description |
|
||
|--------|-------------|
|
||
| Products | Stripe Checkout, Payment Intents |
|
||
| Payment methods | Cards (Visa, Mastercard) + Swish |
|
||
| Fees | ~1.5% + 2 SEK per transaction |
|
||
| Subscription support | Stripe Billing for recurring subscriptions (Phase 1) |
|
||
|
||
---
|
||
|
||
## 9. User Flow
|
||
|
||
```
|
||
Sender visits Bilhälsning.se
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Enter plate │ "ABC 123"
|
||
│ number │
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Vehicle info │ "Volvo V70, 2009, Silver"
|
||
│ displayed │ (public data, free)
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Choose │ Template dropdown or free text
|
||
│ template │
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Compose/edit │ Text editor + preview
|
||
│ letter │
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Preview + │ "Så här ser brevet ut"
|
||
│ confirm │ Total: 49 SEK
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Log in / │ Email + password
|
||
│ Register │ (or skip: guest checkout)
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Pay via │ Stripe Checkout
|
||
│ Stripe/Swish │ (card or Swish)
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
│ Confirmation │ "Ditt brev är på väg!"
|
||
│ + tracking │ Estimated delivery: 2–4 days
|
||
└──────────────┘
|
||
```
|
||
|
||
**Behind the scenes (after payment):**
|
||
```
|
||
BilHej backend → Transportstyrelsen lookup (owner address)
|
||
→ PostNord/Strålfors API (print + mail)
|
||
→ Address deleted from BilHej
|
||
→ Order status updated
|
||
→ Tracking webhook/callback → status updated
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Business Model & Pricing
|
||
|
||
### Cost Analysis (per letter)
|
||
|
||
| Cost item | Phase 0 (manual) | Phase 1 (automated) |
|
||
|-----------|-----------------|--------------------|
|
||
| Transportstyrelsen address lookup | 10–15 SEK | 3–5 SEK |
|
||
| PostNord postage / print+mail | 22 SEK (postage only) | 12–18 SEK |
|
||
| Stripe processing (~1.5% + 2 SEK) | ~3 SEK | ~3 SEK |
|
||
| Envelope, paper, printer (manual) | ~5 SEK | 0 SEK (included) |
|
||
| **Total cost per letter** | **~40–45 SEK** | **~18–26 SEK** |
|
||
|
||
### Pricing Tiers
|
||
|
||
| Tier | Monthly price | Letters included | Extra letters | Est. margin (Phase 1) |
|
||
|------|--------------|-----------------|---------------|----------------------|
|
||
| Pay-as-you-go | — | 0 | 49 SEK | 23–31 SEK |
|
||
| Basic | 99 SEK/mån | 3 | 39 SEK | 13–21 SEK |
|
||
| Pro | 199 SEK/mån | 10 | 29 SEK | 3–11 SEK |
|
||
|
||
### Example Economics (Phase 1, Pro subscriber sending 15 letters/month)
|
||
|
||
```
|
||
Revenue: 199 (subscription) + 5 × 29 (extra letters) = 344 SEK
|
||
Costs: 15 × ~22 SEK = 330 SEK
|
||
Gross margin: 14 SEK
|
||
(Low margin on Pro — designed for high-volume users, profit on Basic/Pay-as-you-go)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. Legal & Compliance
|
||
|
||
### 11.1 GDPR Applicability
|
||
|
||
| Question | Answer |
|
||
|----------|--------|
|
||
| Does GDPR apply to a hobby project? | Technically yes if you process personal data of others. **However**, Art. 2(2)(c) exempts "purely personal or household activity." A paid public-facing website is **not** exempt. In practice, enforcement risk at small scale is low, but you should be aware. |
|
||
| Does GDPR apply to a registered company? | Yes, unequivocally. |
|
||
| Is a license plate personal data? | Yes (it directly identifies a vehicle owner). |
|
||
| Is an address personal data? | Yes. |
|
||
| What if we only process address transiently? | Data minimization is a GDPR principle (Art. 5(1)(c)). Transient processing with immediate deletion is a strong compliance posture. |
|
||
| Do we need to inform the recipient? | Yes, GDPR Art. 14 requires informing the data subject. The letter itself can serve this purpose — include a footer like: _"Detta brev skickades via BilHej.se. Din adress hämtades från Transportstyrelsens fordonsregister och har raderats efter utskick. För frågor: kontakt@bilhej.se"_ |
|
||
|
||
### 11.2 Transportstyrelsen Access
|
||
|
||
| For individuals | "Fråga om fordonsägare" form — open to anyone with a stated reason. ~10–15 SEK. |
|
||
| For businesses | "Fordonsregisterkund" API — requires formal application, stated purpose, data processing agreement. Price not public. |
|
||
|
||
### 11.3 Blocklist / Right to Object
|
||
|
||
Under GDPR Art. 21, data subjects have the right to object to processing. BilHej must provide:
|
||
- An email/contact form where a recipient can say "don't send me letters"
|
||
- A blocklist (per plate) that prevents future letters to that vehicle
|
||
- A clear note in the letter footer with opt-out instructions
|
||
|
||
### 11.4 Recommended Legal Steps
|
||
|
||
1. **Before launch (Phase 0):** Read Transportstyrelsen's terms for "Fråga om fordonsägare." Include GDPR Art. 14 notice in letter footer. Set up blocklist. Keep address deletion strict.
|
||
2. **Before Phase 1:** Consult a Swedish IT-jurist. Register company. Formal data processing agreement with Transportstyrelsen. Appoint DPO if needed. Draft privacy policy and terms of service.
|
||
|
||
### 11.5 Company vs Private Individual
|
||
|
||
If the website makes money, you are conducting economic activity. The Swedish Tax Agency (Skatteverket) will consider this a business regardless of formal registration. You can:
|
||
- Register as **enskild firma** (sole trader) — simplest, personal tax number, unlimited liability
|
||
- Register as **aktiebolag (AB)** — limited liability, requires 25,000 SEK share capital, more administration
|
||
- Not register at all (Phase 0) — only viable at very small scale. VAT (moms) becomes an issue above 80,000 SEK/year.
|
||
|
||
For Phase 0 with manual processing, staying unregistered is workable. If revenue approaches 80,000 SEK/year or if you want automated API access, incorporation will be necessary.
|
||
|
||
---
|
||
|
||
## 12. Development Phases
|
||
|
||
### Phase 0 — MVP (Hobby/Manual)
|
||
|
||
| Feature | Description |
|
||
|---------|-------------|
|
||
| Vue.js landing page | Plate input, letter composer, template selection |
|
||
| Email+password auth | User registration and login |
|
||
| Stripe integration | One-time payments only (no subscriptions) |
|
||
| Letter queue | Backend stores orders in DB, admin manually processes |
|
||
| Order history | Users see past orders and status |
|
||
| Admin panel | Mark orders as processed, enter tracking IDs manually |
|
||
| No API integrations (yet) | Address lookup done manually by you |
|
||
| Home server deployment | Docker Compose, dynamic DNS, Let's Encrypt |
|
||
|
||
**Timeline:** ~4–6 weeks (1 person, part-time)
|
||
**Cost:** ~0 SEK (excluding subscriptions/services)
|
||
|
||
### Phase 1 — Automated
|
||
|
||
| Feature | Description |
|
||
|---------|-------------|
|
||
| Transportstyrelsen API integration | Automated owner address lookup |
|
||
| PostNord/Strålfors API integration | Automated print + mail + tracking |
|
||
| Subscription management | Stripe Billing, recurring payments |
|
||
| Automatic tracking | Webhook callbacks from PostNord |
|
||
| Blocklist system | Opt-out management |
|
||
| Moderation queue | Review flagged free-text letters |
|
||
| Company registration + legal | Formal agreements, privacy policy, terms |
|
||
| Production hosting | Swedish VPS |
|
||
|
||
**Timeline:** ~6–10 weeks (1 person, full-time)
|
||
**Cost:** API fees, legal consultation (~10,000–30,000 SEK), VPS (~100 SEK/mån)
|
||
|
||
### Phase 2 — Growth
|
||
|
||
| Feature | Description |
|
||
|---------|-------------|
|
||
| Advanced templates | Rich text, optional images (car photo) |
|
||
| Analytics dashboard | Revenue, letter volume, user retention |
|
||
| Referral system | "Refer a friend, get a free letter" |
|
||
| English language support | UI and template localization |
|
||
| Mobile app (PWA) | Progressive Web App for app-like experience |
|
||
| Partner integrations | Dealerships, insurance companies, etc. |
|
||
|
||
---
|
||
|
||
## 13. Risks & Mitigations
|
||
|
||
| Risk | Severity | Mitigation |
|
||
|------|----------|------------|
|
||
| Transportstyrelsen denies API access | High | Phase 0 manual fallback works with form requests. SMS service as partial alternative. Investigate alternative data sources (fordonsfraga.se, biluppgifter.se). |
|
||
| High per-letter costs kill margins | Medium | Start with pay-as-you-go at 49 SEK (margin exists even at Phase 0 costs). Move to subscription+automation to reduce cost base. |
|
||
| Recipient complaints / negative PR | Medium | Polite, respectful templates. Clear opt-out in every letter. Blocklist system. Avoid "Tuta" template unless diplomatically worded. |
|
||
| GDPR complaint to IMY | Low (Phase 0) / Medium (Phase 1) | Address deletion, no name storage, Art. 14 notice in letter, blocklist. Legal review before Phase 1. |
|
||
| Home server downtime | Low | Phase 0 is best-effort. Not critical for low volume. |
|
||
| Stripe account closure (reputation risk) | Medium | Ensure terms of service compliance. Have backup payment method. |
|
||
| Competition | Low | No known competitor offers this exact service (physical letter via plate lookup). Car.info / biluppgifter.se show vehicle info but don't facilitate contact. |
|
||
|
||
---
|
||
|
||
## 14. Open Questions
|
||
|
||
| # | Question | Owner | Priority |
|
||
|---|----------|-------|----------|
|
||
| Q1 | What is Transportstyrelsen's actual per-query price for "Fordonsregisterkund" API? | To investigate | High |
|
||
| Q2 | Can we use "Fråga om fordonsägare" form for multiple requests as a commercial service? | To investigate | High |
|
||
| Q3 | What is PostNord "Skicka Direkt" API pricing for print-and-mail? | To investigate | High |
|
||
| Q4 | Does the SMS service give enough info to derive or supplement address data? | To investigate | Medium |
|
||
| Q5 | What are the exact legal requirements for API access — company registration? DPO? | To investigate | High |
|
||
| Q6 | Should we include the sender's name by default or default to anonymous? | Product decision | Low |
|
||
| Q7 | Should "Fritt meddelande" be moderated (reviewed before dispatch) or sent as-is? | Product decision | Medium |
|
||
| Q8 | Should we charge VAT (moms) from day one or only above 80,000 SEK? | Tax question | Medium |
|
||
|
||
---
|
||
|
||
## 15. Tech Stack Summary
|
||
|
||
```
|
||
Frontend: Vue.js 3, Vite, Pinia, Vue Router
|
||
Backend: Java 21, Spring Boot 4, Spring Security (JWT), JPA/Hibernate
|
||
Database: PostgreSQL 16
|
||
Deploy: Docker, Docker Compose, Nginx reverse proxy
|
||
Hosting: Home server (Phase 0) → Swedish VPS (Phase 1)
|
||
Payments: Stripe (cards + Swish)
|
||
Mail: Manual (Phase 0) → PostNord API / Strålfors API (Phase 1)
|
||
Vehicle: Manual form (Phase 0) → Transportstyrelsen API (Phase 1)
|
||
SSL: Let's Encrypt (Certbot)
|
||
CI/CD: GitHub Actions (optional)
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Next Actions
|
||
|
||
1. **Email Transportstyrelsen** — Ask about API access, pricing, requirements
|
||
2. **Email PostNord** — Ask about "Skicka Direkt" print-and-mail pricing
|
||
3. **Set up development environment** — Docker Compose with Vue.js + Spring Boot + PostgreSQL
|
||
4. **Build plate input + vehicle info display** — First frontend component
|
||
5. **Build letter composer + template system** — Core user interaction
|
||
6. **Integrate Stripe Checkout** — One-time 49 SEK payment
|
||
7. **Build admin panel** — Order management, manual status updates
|
||
8. **Deploy to home server** — Docker Compose, Nginx, Let's Encrypt
|
||
9. **Test with one real letter** — End-to-end: plate → compose → pay → manual lookup → mail → track
|
||
10. **Decide: incorporate or stay manual** — Based on demand
|
||
|
||
---
|
||
|
||
*End of Requirements Document*
|