Software Requirement Specification (SRS)
This Software Requirement Specification describes the technical requirements, interfaces, and quality attributes of PubCrawl, a production-ready, self-hosted group night-out booking marketplace. It is intended for developers and technical buyers who will deploy, operate, or extend the system. It builds on the BRD (business intent) and FRD (functional behavior) to define how the software must be built and constrained.
Introduction
Purpose
PubCrawl is a single self-hosted Next.js 16 (App Router) application that serves five experiences from one codebase:
| Surface | Route group | Role |
|---|---|---|
| Storefront | (site) → / |
Public crawl catalogue, booking, checkout, marketing |
| Customer portal | /customer |
Bookings, payments, reviews, messaging, account |
| Host portal | /host |
Crawl listings, departures, reservations, payouts |
| Influencer portal | /influencer |
Referral links, commissions, payouts, analytics |
| Admin / CMS | /admin |
Operations, content, settings, licensing |
The application exposes a versioned REST API under /api/v1, an install API under /api/install, and a license API under /api/license. Data is persisted in PostgreSQL accessed with raw SQL (no ORM) via the Neon serverless driver. Money is stored in minor units (cents). Media is stored in Cloudflare R2 (S3-compatible).
Definitions
| Term | Meaning |
|---|---|
| Entitlement | A licensed capability unlocking a premium add-on (channel provider) |
| Add-on | A packaged premium provider activated by a purchase code / entitlement |
| R2 | Cloudflare R2, S3-compatible object storage |
| RBAC | Role-Based Access Control (admin resource:action matrix; portal account role) |
| Session | A scheduled departure of a crawl (experience_sessions) with a fixed spot count |
Technology Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) + React 19, TypeScript |
| Styling | Tailwind CSS 3, tailwind-merge, clsx |
| Database | PostgreSQL via @neondatabase/serverless — raw SQL, no ORM |
| Auth | Custom JWT with jose and jsonwebtoken; bcryptjs password hashing |
| Secrets | Node crypto — AES-256-GCM encryption (src/lib/secrets.ts) |
| Storage | Cloudflare R2 / S3-compatible via @aws-sdk/client-s3 + presigner |
| Images | sharp (resize / crop / WebP–JPG conversion) |
nodemailer (SMTP) |
|
| Licensing | RS256 JWT via jsonwebtoken, verified offline against a bundled public key |
| UI / content | lucide-react, react-icons, framer-motion, marked / react-markdown, jspdf, jszip, leaflet |
The database client is lazily initialized (src/lib/db.ts) so next build does not require DATABASE_URL; queries use the tagged-template sql`SELECT …` form.
Functional Requirements
- FR-1 The system shall authenticate customers, hosts, influencers and admins via signed JWTs in HttpOnly cookies (portal session 30d;
admin_token7d default). - FR-2 The system shall enforce admin authorization through a resource:action permission matrix (
requirePermission), and portal authorization by account role with owner-scoped queries. - FR-3 The system shall re-price bookings, recompute deposit/full amounts, and re-validate coupons/gift cards server-side at booking time.
- FR-4 The system shall claim spots atomically on checkout (
seats_total - seats_booked >= seats) so a departure can never be oversold. - FR-5 The system shall persist all domain data in PostgreSQL using parameterized raw SQL — no ORM.
- FR-6 The system shall upload media server-side to R2/S3 and process images with sharp before storage.
- FR-7 The system shall confirm a booking only when payment (deposit or full) succeeds, and require an admin Mark as Paid action for offline (Bank Transfer) bookings.
- FR-8 The system shall compute cancellation refunds from the tiered policy and lead time, release spots, and route refunds through an admin approval queue (
booking_refunds). - FR-9 The system shall gate premium add-ons behind license entitlements / purchase codes, unlocking dev/localhost hosts automatically.
- FR-10 The system shall provide an install wizard (
/install) that initializes the schema, optional demo data, license, admin user, and site settings. - FR-11 The system shall store integration secrets AES-256-GCM encrypted and never return them in plaintext to clients.
Non-Functional Requirements
| ID | Attribute | Requirement |
|---|---|---|
| NFR-1 | Performance | Hot public reads (catalogue, crawl detail, availability, facets) are cached server-side; serverless Postgres scales reads. |
| NFR-2 | Scalability | Stateless request handlers on serverless/edge-style hosting; no node-local session state. Spot claims stay consistent under concurrency via guarded atomic updates. |
| NFR-3 | Reliability | License verification is offline; a 14-day grace window keeps a site live if the license server is briefly unreachable. |
| NFR-4 | Security | AES-256-GCM secret encryption, JWT auth, RBAC, bcrypt password hashing, server-side validation. |
| NFR-5 | Maintainability | Conventional Next.js App Router layout; typed TypeScript; core/product layer split for reuse. |
| NFR-6 | Portability | Any S3-compatible storage (R2, DigitalOcean Spaces, AWS S3, GCS) and any PostgreSQL with a serverless-compatible URL. |
| NFR-7 | Brandability | White-label: theme, logo, copy, and homepage sections are admin-configurable; portals render dynamically to reflect live theming. |
| NFR-8 | Compliance | Secrets and password hashes are never serialized to clients. |
External Interfaces
REST API (/api/v1)
A versioned REST API serves the storefront and portals. Conventions:
- Protected routes require the appropriate session cookie (or a Bearer token for mobile clients); admin routes additionally pass the permission matrix.
- List endpoints accept pagination/filter params and return paginated payloads (
{ data, meta }); money stays in minor units (cents).
Representative surfaces: listings (+ [slug], availability, quote, report), bookings (+ checkout, pay, payment-methods, verify), coupons, gift-cards, reviews, host, influencer, chat, chatbot, analytics, blogs, pages, forms, i18n, plugins, cron.
Storage Interface (Cloudflare R2 / S3)
All file operations go through an S3-compatible abstraction (src/lib/r2.ts). The active provider and credentials are read from integration_connections (channel STORAGE, primary first), with env fallbacks (R2_ENDPOINT, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_DEFAULT_BUCKET, R2_PUBLIC_URL). Images are processed with sharp into preset sizes (avatars, crawl thumbnails/covers, gallery, blog, logo, etc.) and served from the storage CDN — not the application server.
License Server (creative-cape.com)
The product embeds the CreativeCape license client (src/lib/license/). It activates once (POST /api/license/activate) to bind a purchase code to the domain and receive an RS256 JWT, then verifies that token offline with a bundled public key on every check, re-validating on a daily heartbeat. Per-add-on purchase codes follow the same offline-verification model (src/lib/license/addons.ts), stored in addon_licenses and bound to { addon, domain }.
Third-Party Integration Interfaces
Integrations are admin-configurable and credential-supplied by the buyer; secrets are encrypted at rest.
| Category | Free default | Premium examples |
|---|---|---|
| Payments | PayPal, CoD, Bank Transfer | Stripe, Razorpay, Square, Authorize.net, … |
| SMTP (nodemailer) | SendGrid, Postmark, AWS SES, Mailgun | |
| Storage | Cloudflare R2 | DigitalOcean Spaces, AWS S3, Google Cloud Storage |
| Analytics | GA4 | GTM, Meta Pixel, PostHog, TikTok, Clarity |
| Calendar | — | Google Calendar, iCal export |
| Messaging | — | SMS (Twilio/Msg91), WhatsApp, live chat, AI chatbot |
| Auth / Security | — | Social sign-in (Google/Facebook), reCAPTCHA v2/v3 |
Security
- Authentication. Stateless JWTs in HttpOnly, SameSite=Lax cookies — a portal session (HS256, 30d) for customers/hosts/influencers and
admin_token(HS256, 7d default) for admins. There is no refresh-token endpoint; clients re-authenticate on expiry. Passwords are hashed with bcryptjs. - Authorization. Portal users are routed by account role and every query is owner-scoped (
customer_id = me/owner_id = hostId); admins pass a resource:action permission matrix (permissions-catalog.ts+requirePermission), with system/super roles bypassing the matrix and mutations emitting audit events. - Secret encryption.
src/lib/secrets.tsencrypts integration credentials with AES-256-GCM (12-byte IV + auth tag,enc:v1:prefix); the key derives fromSECRET_KEY/JWT_SECRET. Stored secrets are decrypted only server-side and never returned to clients. - Input handling. Booking pricing, deposit/full amounts, spot counts, coupons, and gift-card balances are recomputed server-side; uploads pass through the server with sharp processing before storage.
- Transport. HTTPS is expected at the edge; tokens travel as cookies/bearer credentials, never in URLs.
Performance & Reliability
- Caching. Hot public reads (published crawls, crawl detail, departure availability, hosts, facets) are cached server-side with short TTLs; the license record is cached ~60s for hot public pages.
- Serverless data. PostgreSQL via the Neon serverless driver scales reads; the lazy client avoids build-time DB requirements.
- License fail-open grace. Offline RS256 verification plus a 14-day grace window means a brief license-server outage never takes a live site down.
- Media offload. Images convert and serve from R2/S3, offloading bandwidth from application nodes.
Constraints
- Serverless / read-only filesystem. The application is built for serverless hosting where the filesystem is effectively read-only at runtime; all user media must go to R2/S3 rather than local disk.
- Buyer-supplied services. SMTP/email, SMS, WhatsApp, and payment-gateway credentials are provided by the buyer and configured in admin settings.
- Premium gating. Premium channel providers require a valid CreativeCape entitlement or per-add-on purchase code; development hosts (localhost/LAN/
*.test) are unlocked. - Database compatibility. Requires a PostgreSQL database reachable via a serverless-compatible connection URL (
DATABASE_URL).
For technical support, license activation, and extension guidance, contact creative-cape.com.
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com