9.2 KiB
9.2 KiB
| 1 | Card Name | Description | List | Labels |
|---|---|---|---|---|
| 2 | Scaffold Vue 3 + Vite project | Run `npm create vue@latest` or `npm create vite@latest` with Vue template. Verify `npm run dev` serves blank page on port 3000. | Infra & Scaffolding | Frontend |
| 3 | Scaffold Spring Boot 3 project | Generate via Spring Initializr with dependencies: Spring Web, Spring Security, Spring Data JPA, PostgreSQL Driver, Flyway, Validation, Lombok. Verify `./mvnw spring-boot:run` starts on port 8080. | Infra & Scaffolding | Backend |
| 4 | Docker Compose setup | Create `docker-compose.yml` with 3 services: postgres (16), backend (Java 21), frontend (Node/Vite dev mode). Verify `docker compose up` starts all 3 services successfully. | Infra & Scaffolding | DevOps |
| 5 | .env.example + env config | Create `.env.example` with all required vars: POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, JWT_SECRET, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_ID. Wire backend and docker-compose to read from `.env`. | Infra & Scaffolding | DevOps |
| 6 | Flyway + initial migration | Add Flyway dependency and config to Spring Boot. Create first migration file `V1__create_users_table.sql`. Verify migration runs automatically on startup and table exists in DB. | Infra & Scaffolding | Backend |
| 7 | Initial DB schema | Write Flyway migrations for all core tables: users, orders, templates, blocklist, audit_log. All migrations run on startup. Tables exist and match the schema from REQUIREMENTS.md. | Infra & Scaffolding | Backend |
| 8 | User entity + repo + service | Create JPA entity `User` (id UUID PK, email unique, password_hash, created_at, subscription enum). Create Spring Data repository. Create UserService with findByEmail and createUser methods. | Auth | Backend |
| 9 | JWT token generation + filter | Create JwtUtil class (generate, validate, extract username). Create JwtAuthenticationFilter (OncePerRequestFilter, checks Authorization header). Configure SecurityFilterChain bean in SecurityConfig. | Auth | Backend |
| 10 | Register endpoint | Create AuthController with POST /api/auth/register. Validate email format and password length. Hash password with BCrypt. Return JWT token. Return 409 on duplicate email. | Auth | Backend |
| 11 | Login endpoint | Create POST /api/auth/login in AuthController. Authenticate credentials. Return JWT token on success. Return 401 on invalid credentials. | Auth | Backend |
| 12 | Register page | Create RegisterPage.vue with email and password fields, validation, submit button. On success: store token via auth store, redirect to home. On error: show Swedish error message. | Auth | Frontend |
| 13 | Login page | Create LoginPage.vue with email and password fields. On success: store token and redirect. On error: show "Felaktig e-post eller lösenord". | Auth | Frontend |
| 14 | Pinia auth store + API interceptor | Create `stores/authStore.js` (token, user, login, logout, isAuthenticated). Create `api/client.js` (base URL, auto-attach Bearer token, handle 401 responses). Token persisted in localStorage. | Auth | Frontend |
| 15 | Vue Router auth guards | Configure Vue Router with routes for home, login, register, compose, orders, admin. Add beforeEach guard: redirect to /login if route requires auth and user is not authenticated. | Auth | Frontend |
| 16 | Vehicle lookup controller | Create VehicleController with GET /api/vehicles/{plate}. Validate plate format. Return mock/stub vehicle info (make, model, year, color) matching the plate. Create VehicleResponse DTO. | Vehicle Info | Backend |
| 17 | PlateInput component | Create PlateInput.vue. Text input with auto-uppercase. Validate Swedish plate format (ABC123 or ABC12D) in real-time. Emit `lookup` event on valid submit. Show inline error on invalid format. | Vehicle Info | Frontend |
| 18 | Vehicle info display | Create VehicleInfo.vue. Receives vehicle data as prop. Displays make, model, year, color in a clean card. Shows loading state while fetching. Shows "Inget fordon hittades" on lookup failure. | Vehicle Info | Frontend |
| 19 | Landing/home page | Create HomePage.vue. Combines PlateInput and VehicleInfo. After successful lookup, shows "Skicka ett brev till ägaren" button that navigates to compose page with plate in query params. | Vehicle Info | Frontend |
| 20 | Template entity + seed data | Create Template entity (id, name, body_template, is_active). Create Flyway migration for templates table. Create data.sql or Java seeder that inserts 5 default templates (Komplimang, Köpa, Tips, Körbeteende, Tuta). | Letter Composer | Backend |
| 21 | Templates API endpoint | Create TemplateController with GET /api/templates. Return only active templates. Public endpoint (no auth required). Return TemplateResponse list (id, name, body_template). | Letter Composer | Frontend/Backend |
| 22 | Template selector | Create TemplateSelector.vue. Dropdown/select listing templates fetched from API. Selecting one fills the editor with body_template text. Include "Fritt meddelande" option that leaves editor blank. | Letter Composer | Frontend |
| 23 | Letter editor | Create LetterEditor.vue. Textarea with live character counter (e.g. "247/1000"). Enforce 1000 char max. Editable even when template is selected. Emit content on change. | Letter Composer | Frontend |
| 24 | Letter preview | Create LetterPreview.vue. Receives letter text as prop. Renders text styled as A4 letter (white background, letter layout, preview of what recipient sees). | Letter Composer | Frontend |
| 25 | Compose page | Create ComposePage.vue. Combined flow: template selector → letter editor → letter preview. Read plate from route query. "Skicka brev" button at bottom triggers order creation. | Letter Composer | Frontend |
| 26 | Order entity + repo + service | Create Order entity (id UUID, user_id FK, plate, template, letter_text, status enum, amount_paid, tracking_id, timestamps). Create repository. Create OrderService with createOrder method (status: pending_payment). | Orders & Payment | Backend |
| 27 | Create order endpoint | Create OrderController with POST /api/orders (auth required). Accept CreateOrderRequest (plate, template, letter_text). Validate plate format, text length. Return OrderResponse with order ID and status. | Orders & Payment | Backend |
| 28 | Stripe config + checkout session | Create StripeConfig (@ConfigurationProperties). Create PaymentService.createCheckoutSession(orderId). Call Stripe API to create session with product price. Return session URL. Store session ID on order. | Orders & Payment | Backend |
| 29 | Stripe webhook handler | Create WebhookController with POST /api/webhooks/stripe (no auth, verify Stripe signature). Handle checkout.session.completed: mark order as paid. Log all events for debugging. | Orders & Payment | Backend |
| 30 | Payment trigger flow | In ComposePage: "Skicka brev" → POST /api/orders (backend returns order with checkout URL) → redirect window to Stripe. Create PaymentRedirect.vue that extracts order data and redirects. | Orders & Payment | Frontend |
| 31 | Payment success page | Create SuccessPage.vue shown after Stripe redirect. Receives session_id in query. Shows confirmation: "Ditt brev är på väg!". Shows order summary (plate, template). Links to order history. | Orders & Payment | Frontend |
| 32 | Order history page | Create OrderHistoryPage.vue (auth required). Fetches GET /api/orders. Renders table/card list with: date, plate, template name, status badge (Sent/På väg/Delivered), tracking link if available. | Orders & Payment | Frontend |
| 33 | Admin order list endpoint | Create AdminController with GET /api/admin/orders (admin auth). Returns all orders sorted by created_at DESC. Include user email in response. Admin-only via @PreAuthorize or role check. | Admin Panel | Backend |
| 34 | Admin status update endpoint | Create PATCH /api/admin/orders/{id}/status in AdminController. Accept status string. Validate status enum values. Update order status and timestamp. Return updated order. | Admin Panel | Backend |
| 35 | Admin login page | Create AdminLoginPage.vue separate from user login. Hardcoded admin credentials (MVP only — move to DB later). Store admin token separately in localStorage. | Admin Panel | Frontend |
| 36 | Admin dashboard | Create AdminDashboard.vue (admin auth guard). Table of all orders with columns: date, user email, plate, template, status badge. Click row to expand letter content. Status dropdown to update order status. | Admin Panel | Frontend |
| 37 | Manual tracking entry | In admin dashboard: editable tracking_id field per order. On save: PATCH /api/admin/orders/{id} with new tracking_id. Add PostNord tracking link helper (https://www.postnord.se/spara?id=...). | Admin Panel | Frontend |
| 38 | Backend Dockerfile | Multi-stage Dockerfile: build stage (maven, compile), run stage (eclipse-temurin:21-jre-alpine, non-root user). Copy JAR. Entrypoint: java -jar. Expose 8080. | Deployment | DevOps |
| 39 | Frontend Dockerfile | Multi-stage Dockerfile: build stage (node:20-alpine, npm ci, npm run build), run stage (nginx:alpine, copy dist to /usr/share/nginx/html). Include nginx.conf or rely on compose-provided nginx. | Deployment | DevOps |
| 40 | Nginx reverse proxy config | Create nginx.conf that routes /api/* to backend:8080 and everything else to frontend static files. Add CORS headers. Enable gzip. Ready for production proxying. | Deployment | DevOps |
| 41 | Production Compose file | Create docker-compose.prod.yml. Same services but: frontend serves built files via nginx internally, nginx reverse proxy handles SSL termination with cert volumes, PostgreSQL uses named volume for persistence. | Deployment | DevOps |
| 42 | Deploy to home server | Copy repo and .env to host. Run `docker compose -f docker-compose.prod.yml up -d`. Configure dyndns if needed. Set up Certbot/LetsEncrypt cron for SSL renewal. Verify HTTPS access from external network. | Deployment | DevOps |