NovaBrand Platform Documentation

Central documentation for the NovaBrand platform — a brand engagement system built on blockchain-based membership programs.

Platform Overview

NovaBrand enables brands to create digital membership programs ("Passes") with on-chain tokens, activations, collectibles, and rewards. The platform consists of:

Key System Components

Backend (Django) — REST APIs, business logic, admin portals, Celery task dispatch. Multiple admin sites: Brand Manager, User Manager, Support, Blockchain, Config.

Frontend (React) — Single-page app deployed to S3, served via CloudFront with environment-specific subdomains (dev/staging/app).

Database (PostgreSQL + RDS) — Core data store with HStore extension. Automated RDS snapshots for backup.

Celery + Redis — Async task processing for blockchain operations (minting, airdrops, token transfers), email dispatch, and scheduled cron jobs. Workers managed via Supervisor on a dedicated EC2 instance.

Blockchain (Flow) — Smart contracts (Cadence) for NFT-based membership tokens. Brands, Passes, and Collectibles are represented on-chain. Backend interacts via flow-py-sdk.

Stripe — Payment processing with webhook integration at /api/v1/payments/webhook/.

Shopify Plugin — Embedded Shopify sales channel app (React 19 + Polaris). Enables merchants to sync products, manage orders, and link their accounts — all within the Shopify Admin.

AWS Services — EC2 (app + worker servers), RDS (PostgreSQL), S3 (static/media), Lambda (image compression, wallet verification, meta tags), CloudFront (CDN), SES (email).

Architecture Diagram

+-------------------+ | CloudFront CDN | | (dev/staging/app)| +--------+----------+ | +--------------+--------------+ | | +-------+-------+ +-------+-------+ | React SPA | | Shopify App | | (S3 Hosted) | | (S3 Hosted) | +-------+-------+ +-------+-------+ | | +-------------+---------------+ | +-------v--------+ | Nginx/uWSGI | | Django Backend | | (EC2) | +---+----+---+---+ | | | +--------------+ | +--------------+ | | | +------v------+ +------v------+ +------v------+ | PostgreSQL | | Redis | | Celery | | (RDS) | | (Cache + | | Workers | | | | Broker) | | (EC2) | +--------------+ +-------------+ +------+------+ | +-----------------+--+ | | | | | +--v-+ +v-+ +v-+ +v--+ +v---+ | S3 | |SES| |Flow| |Stripe| |Firebase| +----+ +---+ +---+ +-----+ +-------+

Repositories

RepositoryStackDescription
novabrand-backendDjango 3.2, Python 3.10REST APIs, admin, Celery, blockchain integration
novabrand-feReact 18, Vite 6, TypeScriptFrontend SPA, CloudFront-hosted
novabrand-shopifyReact 19, Vite 7, PolarisEmbedded Shopify sales channel app
novabrand-docsPlatform-wide documentation (this repo)

Technical Architecture & API Reference

1. System Architecture Overview

1.1 High-Level Architecture

NovaBrand is a web platform that connects brands and consumers around digital memberships ("passes"), collectibles, incentives, and commerce. The system is split into:

LayerRepositoryTechnologyRole
Frontendnovabrand-feReact 18, Vite 6, TypeScript, TanStack Query, Tailwind, MUISPA for brands and consumers; all API calls go to the backend base URL.
Backendnovabrand-backendDjango 3.2, Django REST Framework, Python 3.10REST API under /api/v1/, auth, business logic, integrations.
Shopify Pluginnovabrand-shopifyReact 19, Vite 7, TypeScript, Shopify Polaris v13, App Bridge v3Embedded Shopify sales channel app for product sync, orders, and account linking.
External servicesAWS (S3, SES, Lambda, CloudFront), Stripe, Flow blockchain, Firebase, SentryStorage, payments, blockchain, notifications, monitoring.

1.2 Request Flow

  1. User opens the app in the browser.
  2. Frontend resolves the API base URL from VITE_API_BASE_URL and sends all API requests to that origin.
  3. Backend serves REST endpoints under https://<backend-host>/api/v1/...
  4. Authenticated requests include the header: Authorization: Token <token>.
  5. Backend uses Django ORM (PostgreSQL in production, SQLite in dev), optional Redis for cache, Celery for async jobs, and integrates with S3, Stripe, Flow, Shopify, and Firebase as needed.

1.3 Deployment Context

Frontend environments (automated via GitHub Actions):

BranchEnvironmentURL
mainProductionapp.example.com
stagingStagingstaging.example.com
devDevdev.example.com

Backend deployment is manual (SSH → git pull → migrate → uWSGI reload).

2. Dependency Graph

2.1 Frontend Dependencies

novabrand-fe (React SPA) +-- Runtime/build | +-- Node.js 18+ | +-- Vite 6.x | +-- TypeScript (strict mode) +-- UI & state | +-- React 18, react-router-dom 6 (lazy-loaded pages) | +-- Tailwind CSS 4, shadcn/ui, MUI 5, Framer Motion | +-- Zustand 4, TanStack React Query 4 | +-- react-hook-form, Yup, @hookform/resolvers +-- HTTP & auth | +-- Axios (all API calls via utils/request.ts) | +-- Token in localStorage +-- Integrations (client-side) | +-- @stripe/react-stripe-js, @stripe/stripe-js | +-- @onflow/fcl (Flow/Dapper) | +-- Firebase 9 (Realtime Database for notifications) | +-- @shopify/app-bridge (when in Shopify context) | +-- Uppy (S3 uploads via backend presigned URLs) +-- Observability +-- @sentry/react (production only)

2.2 Backend Dependencies

novabrand-backend (Django) +-- Core | +-- Django 3.2, Django REST Framework 3.12 | +-- django-cors-headers, django-filter | +-- drf-yasg (Swagger) +-- Auth & permissions | +-- rest_framework.authtoken (Token auth) | +-- django-guardian (object-level permissions) | +-- django-allauth, social-auth-app-django (social/OAuth) +-- Data & storage | +-- PostgreSQL (prod) / SQLite (dev) | +-- django-redis, Redis (cache) | +-- boto3, django-storages (S3) | +-- simple-history (audit) +-- Async & scheduling | +-- Celery 5.2, django-celery-beat | +-- django-crontab +-- Integrations | +-- Stripe | +-- flow-py-sdk (Flow blockchain) | +-- Shopify API (server-side) | +-- Firebase (admin) | +-- django-ses / Mailjet, Twilio (email/SMS) | +-- Sentry (optional) +-- Admin +-- django-3-jet, custom admin sites (brand, user, analytics, support, config, blockchain)

3. API Endpoints

All routes below are relative to the backend base URL and the prefix /api/v1/. Unless stated otherwise, endpoints expect Authorization: Token <token> for authenticated access.

3.1 Meta Tags

MethodRouteView / HandlerNotes
GETmeta-tags/brand/<brand_id>/pass/<pass_id>GetPassMetatagPass meta for SEO
GETmeta-tags/brand/<brand_id>GetBrandMetatagBrand meta for SEO
GETmeta-tags/user-profile/<username>GetUserMetatagUser profile meta for SEO

3.2 Brand

MethodRouteView / HandlerNotes
GETbrand/BrandAPIViewSet (list)List brands; filters: tags, search, is_featured
POSTbrand/BrandAPIViewSet (create)Create brand (authenticated)
GETbrand/<pk>/BrandAPIViewSet (retrieve)Brand detail (public or dashboard)
PUT/PATCHbrand/<pk>/BrandAPIViewSet (update)Update brand (admin permission)
GETbrand/names/BrandNamesListAPIViewList brand names
GETbrand/get-ids/BrandNamePassNameAPIViewResolve brand/pass IDs from names
GETbrand/tags/TagsListAPIViewList tags
POSTbrand/brand-invitation/BrandInvitationAPIViewCreate brand invitation
POSTbrand/buy/BuyBrandApiViewStart brand purchase (Stripe checkout)
GETbrand/brand-plans/BrandPlansListAPIViewSetList brand plans
GETbrand/<brand_id>/all-passes-nameBrandPassesNameListAPIViewPass names for brand
POSTbrand/<brand_id>/pass-with-release/CreatePassWithReleaseAPIViewCreate pass + release in one call
GETbrand/<brand_id>/pass/ListCreatePassList/create passes for brand
GETbrand/<brand_id>/pass/<pk>/membersPassMembersAPIViewPass members
POSTbrand/<brand_id>/pass/<pk>/update-membersAddUpdatePassMembersAPIViewAdd/update members
GETbrand/<brand_id>/pass/<pk>/check-membershipCheckMembershipAPIViewCheck membership
GETbrand/<brand_id>/pass/<pk>/download-member-dataExportMembersDataExport member data
POSTbrand/pass/<pass_id>/publish/PublishPassPublish pass
POSTbrand/pass/<pass_id>/settle-purchase/SettlePassPurchaseSettle purchase (e.g. tx hash)
GET/POSTbrand/pass/<pass_id>/release/CreateReleaseAPIViewList/create releases
GET/PUT/PATCH/DELETEbrand/pass/<pass_id>/release/<pk>UpdateDeleteReleaseAPIViewUpdate/delete release
POSTbrand/pass/<pass_id>/release/<pk>/publish/PublishReleasePublish release

3.3 Pass (Public / Consumer-Facing)

MethodRouteView / HandlerNotes
GETpass/PublicPassListRetrieveView (list)List public passes
GETpass/<pass_id>/PublicPassListRetrieveView (retrieve)Public pass detail
GETpass/<pass_id>/getPurchaseArgs/PurchaseArgsForPassPurchase args (Stripe/Dapper)
GETpass/<pass_id>/collectibles/PassCollectiblesViewSetCollectibles for pass
GETpass/<pass_id>/incentive-collectible-notifications/PassIncentivesCollectiblesNotificationsAPIIncentive/collectible notifications
POSTpass/<pass_id>/claim/ClaimPassClaim pass (e.g. event)
GETpass/<pass_id>/event-claim-request/PassClaimResponseAPIViewEvent claim request
POSTpass/<pass_id>/update-event-form/UpdatePassClaimFormAPIUpdate claim form

3.4 User

MethodRouteView / HandlerNotes
GETuser/get-nonceGetNonceGet nonce for wallet auth
POSTuser/verify-signatureVerifySignatureVerify signature; returns token
POSTuser/auth/AuthUserViewAuth (e.g. token validation)
GETuser/new-verification-link/new_verification_linkRequest new verification link
GETuser/verify-email/<token>/verify_emailEmail verification
POSTuser/set-password/set_passwordSet password
GETuser/self/RetrieveUpdateUserProfileCurrent user profile
PUT/PATCHuser/self/RetrieveUpdateUserProfileUpdate current user profile
GETuser/inventory/UserInventoryModelViewSetUser pass inventory
GETuser/stats/UserStatsAPIViewUser stats
GETuser/notifications/ListUserNotificationsViewSetList notifications
POSTuser/notifications/read/ReadAllUserNotificationsViewSetMark all read
GETuser/notifications/unread-countUserNotificationsUnreadCountViewSetUnread count
POSTuser/signup/UserSignUpAPIViewEmail signup
POSTuser/login/UserLogInAPIViewEmail login
POSTuser/logout/LogoutUserAPIViewLogout
POSTuser/resend-otp/ResendOTPAPIViewResend OTP
POSTuser/verify-otp/VerifyOTPAPIViewVerify OTP
POSTuser/change-password/AuthenticatedUserResetPasswordAPIViewChange password (authenticated)
GETuser/<username>/PublicUserProfilePublic user profile

3.5 Activations

Activations are engagement features (polls, airdrops, claim codes, merch drops, social share) scoped by brand or pass.

MethodRouteView / HandlerNotes
GETactivations/ActivationsPublicReadOnlyViewList activations (public)
GETactivations/brand/<brand_id>/BrandActivationsReadOnlyViewActivations for brand
GETactivations/pass/<pass_id>/PassCollectibleOrActivationsListViewActivations for pass
GET/POSTactivations/pass/<pass_id>/drop/airdrop/AirdropActivationModelViewSetAirdrop collectibles
GET/POSTactivations/pass/<pass_id>/drop/claim_code/ClaimCodeModelViewSetClaim codes
POSTactivations/pass/<pass_id>/drop/claim_code/<id>/claim/ClaimClaimCodeAPIViewClaim with code
GET/POSTactivations/pass/<pass_id>/drop/merch_drop/MerchCollectibleModelViewSetMerch drops
GET/POSTactivations/pass/<pass_id>/response/poll/PrivatePollCollectibleModelViewSetPolls
GET/POSTactivations/pass/<pass_id>/response/social-share/CRUDSocialSharingCollectibleModelViewSetSocial share
POSTactivations/pass/<pass_id>/publish/<id>/PublishCollectibleViewPublish collectible

3.6 Collectible (Public)

MethodRouteView / HandlerNotes
GETcollectible/CollectibleRetrieveView (list)List collectibles
GETcollectible/<id>/CollectibleRetrieveView (retrieve)Collectible detail
POSTcollectible/<id>/claim-private/ClaimPrivateCollectibleClaim private collectible
GETcollectible/<id>/download/DownloadCollectibleViewDownload collectible

3.7 Activity

MethodRouteView / HandlerNotes
GETactivity/pass/<pass_id>PassActivityViewSetActivity for pass
GETactivity/user/<username>UserActivityViewSetActivity for user

3.8 Analytics

MethodRouteView / HandlerNotes
GETanalytics/brand/<brand_id>PrivateBrandAnalyticsViewSetBrand analytics
GETanalytics/brand/<brand_id>/get-audiencePrivateAudienceAnalyticsViewSetAudience analytics
GETanalytics/brand/<brand_id>/get-audience/exportAudienceAnalyticsDownloadAPIExport audience data
GETanalytics/brand/<brand_id>/collectiblesPrivateCollectibleAnalyticsViewCollectible analytics
GETanalytics/admin-siteGetAdminAnalyticsAPIViewSetAdmin-site analytics

3.9 Social Media

MethodRouteView / HandlerNotes
GETsocial-media/twitter/callbackTwitterCallbackHandlerAPIViewTwitter OAuth callback
GETsocial-media/twitter/oauth2TwitterOauth2HandlerAPIViewTwitter OAuth2 URL/start
GETsocial-media/social-auth/get-auth-codeget_auth_code_uriGet auth code (e.g. Google)
POSTsocial-media/social-auth/google-handshakehandle_google_loginGoogle sign-in handshake

3.10 Payments

MethodRouteView / HandlerNotes
GETpayments/configstripe_configStripe config (public key)
GETpayments/create-checkout-session/pass/<pass_id>CreateCheckoutSessionCreate Stripe checkout session
GETpayments/successSuccessViewCheckout success page
GETpayments/cancelledCancelledViewCheckout cancelled
POSTpayments/webhook/StripeCallbackStripe webhook (signature verified)
GETpayments/stripe/oauth/redirect-urlStripeOauthCallbackStripe Connect OAuth redirect
GETpayments/stripe/connectStripeConnectStripe Connect onboarding

3.11 UGC Campaign

MethodRouteView / HandlerNotes
GETcampaign/ListCreateUGCCampaignView (list)List UGC campaigns
POSTcampaign/ListCreateUGCCampaignView (create)Create UGC campaign
GETcampaign/all_ugc/ListAllUGCCampaignSubmissionsViewAll UGC submissions
GETcampaign/user/UserUGCSubmissionsViewCurrent user's UGC submissions
POSTcampaign/bulk-download/BulkDownloadMediaViewBulk download UGC media
POSTcampaign/submissions/status-update/UGCCampaignSubmissionStatusUpdateViewUpdate submission status
POSTcampaign/<id>/endcampaign/EndUGCCampaignViewEnd campaign

3.12 Shopify

MethodRouteView / HandlerNotes
GETshopify/connect/ShopifyConnectViewSetStart Shopify OAuth
GETshopify/callback/ShopifyCallbackAPIViewOAuth callback
POSTshopify/register-webhooks/ShopifyRegisterWebhooksAPIViewRegister webhooks
POSTshopify/sync-products/ShopifyProductSyncAPIViewSync products
GETshopify/search-products/ShopifySearchProductsAPIViewSearch products
GETshopify/list-products/BrandProductListAPIViewList products
POSTshopify/disconnect/ShopifyDisconnectAPIViewDisconnect store
POSTshopify/select-products/ShopifySelectProductAPIViewSelect products for platform
GETshopify/orders/ShopifyOrdersAPIViewList orders
POSTshopify/sync-orders/ShopifyOrderSyncAPIViewSync orders
GETshopify/storefront-token/ShopifyStorefrontTokenAPIViewStorefront token
GETshopify/public/products/ShopifyPublicProductsAPIViewPublic products
POSTshopify/products/publish/ShopifyProductPublishingAPIViewPublish product
POSTshopify/products/unpublish/ShopifyProductUnpublishingAPIViewUnpublish product
GETshopify/public/orders/ShopifyPublicOrdersAPIViewPublic orders
POSTshopify/public/orders/<id>/fulfill/FulfillOrderAPIViewFulfill order
POSTshopify/public/orders/<id>/cancel/CancelOrderAPIViewCancel order
POSTshopify/public/orders/<id>/refund/RefundOrderAPIViewRefund order
GET/POSTshopify/billing/ShopifyBillingAPIViewBilling management

Shopify webhooks (POST, by Shopify): customers/data_request, customers/redact, shop/redact, app/uninstalled, products/create, products/update, products/delete, create-order, orders/updated, orders/paid, orders/cancelled, orders/fulfilled, inventory_items/update, collections/create, collections/update, collections/delete.

3.13 Support & Utilities

MethodRouteView / HandlerNotes
POST/support/query/SupportQuerySubmit support query
GET/support/get-url-metadata/GetUrlMetadataFetch URL metadata
POST/utilities/api/v1/upload/FileUploadViewUpload file to S3

4. Authentication Patterns

4.1 Backend Auth

4.2 Frontend Auth

4.3 Auth Flow Summary

FlowFrontendBackend
Token authStore token in localStorage; send Authorization: TokenValidate token; enforce IsAuthenticated or AllowAny
Wallet (Dapper)get-nonce → sign → verify-signature → store tokenIssue token on valid signature
Emaillogin/signup + verify-otp or verify-emailIssue token on success
Googleget-auth-code → google-handshakeCreate/attach user; return token/session
Webhooks (Stripe/Shopify)N/AVerify payload signature; no user token

5. Inter-App Relationships

5.1 Frontend ↔ Backend

5.2 Backend ↔ External Systems

External SystemUsed ForTrigger
PostgreSQLPrimary data storeEvery request / Celery task
RedisCache, Celery brokerCache, queue
AWS S3Media, uploadsUpload API, presigned URLs
StripePayments, ConnectCheckout, webhook, Connect onboarding
Flow BlockchainNFT mints, ownershipPurchase settlement, wallet flows
ShopifyE-commerce, orders, productsOAuth, webhooks, product/order APIs
FirebasePush notificationsBackend sends to FCM
SES / Mailjet / TwilioEmail, SMSVerification, notifications

5.3 Data Ownership


Database Schema Documentation

Django 3.2.8 PostgreSQL 11 Apps ~45 Models

Overview

The platform uses PostgreSQL as its primary database, accessed through Django 3.2.8 ORM. The schema spans 11 Django applications containing approximately 45 models. The database uses the HSTORE extension and supports both standard auto-increment integer primary keys and ShortUUID primary keys for certain models.

Base Model Classes

App-to-Model Summary

Django AppModel CountPurpose
brand20Brands, Passes, Releases, Tokens, Events, Claims, Subscriptions, UGC Campaigns, Shopify, Invitations
user_management5User profiles, inventory, achievements, OTP, nonce tracking
activations6Activations, Collectibles, drops (Collectible/Pass/Raffle), Brand Activations
payments1Stripe payment records
order2Purchase orders and pass lock table
activity1Activity feed with generic foreign keys
social_media2Social share responses, Twitter OAuth tracking
notifications2User notifications, notification subscriptions
support1Support/contact queries
app_manager1Custom admin sidebar apps
utilities5+Abstract bases, Address, ProjectConfigurations, Tags

Core Models

Brand App

The brand app contains the largest models, managing brands, passes (NFT collections), releases, tokens, events, UGC campaigns, Shopify integrations, and subscriptions.

Key Models

User Management App

Activations App

Payments & Orders

Status Enumerations

EntityStatuses
BrandDRAFT(0) APPROVING(1) APPROVED(2) REJECTED(3) SUSPENDED(4) DELETED(5)
PassDRAFT(0) PUBLISHING(1) PUBLISHED(2) DELETED(3)
ReleaseDRAFT(0) SCHEDULING(1) SCHEDULED(2) ON_SALE(3) SALE_ENDED(4) DELETED(5)
TokenCREATED(0) MINTED(1) VIEWED(4) CLAIMED(2) BURN(3)
CollectibleDRAFT(0) PUBLISHING(1) PUBLISHED(2) SCHEDULED(3) STARTED(4) COMPLETED(5) ENDED(6) DELETED(7)
DropSCHEDULED(0) PICKED(1) DROPPING(2) DROPPED(3) FAILED(4)

Activation Types

airdrop merch_drop claim_code poll social_share ugc_submission

Key Relationship Map

Core Hierarchy

Brand (1) --> (N) Pass --> (N) PassReleases --> (N) PlatformToken Brand (1) --> (N) Tags (M2M) Brand (1) --> (N) ConnectedStore --> (N) Product --> (N) ProductVariant

Engagement Chain

Pass (1) --> (N) Collectible --> (N) CollectibleDrop --> UserProfile Pass (1) --> (N) UGCCampaign --> (N) UGCCampaignSubmission Collectible (1) --> (N) RaffleDrop --> (M2M) UserProfile

Commerce Chain

PassReleases --> PlatformToken --> StoreFrontListing --> PurchaseOrder Pass --> SubscriptionDetails --> PaymentRecord

User Chain

auth.User (1:1) UserProfile --> (N) UserInventory UserProfile --> (M2M) Achievements UserProfile --> (N) SocialShareResponse --> Collectible

Implementation Notes


Celery Tasks & Cron Jobs Guide

Overview

The platform uses Celery (v5.2.7) with Redis as the message broker to handle asynchronous tasks. The system processes blockchain transactions, email notifications, subscription management, UGC campaign lifecycle events, and media file operations outside the HTTP request-response cycle.

SettingValue
Celery Appnovabrand
BrokerRedis at redis://127.0.0.1:6379
Result BackendNone (disabled)
Beat Schedulerdjango_celery_beat.schedulers:DatabaseScheduler
SerializationJSON (task and result)
Workers3 concurrent + 1 Beat scheduler (via Supervisor)

Task Summary

Task NameTypeTriggerFrequency
blockchain_transactionCeleryCalled by views/services with type paramOn demand
claim_pass_notification_taskCeleryCalled after pass airdropOn demand
update_passes_membership_metadataCeleryManual or scheduledOn demand
make_latest_subscription_details_activeBeat CronCelery Beat schedulerDaily 00:00 UTC
email_upcoming_subscription_details_to_usersBeat CronCelery Beat schedulerDaily 00:00 UTC
send_email_verification_remindersCeleryManual or scheduledOn demand
refresh_brand_analyticsCeleryManual or scheduledOn demand
update_ugc_campaign_statusCeleryManual or scheduledOn demand
bulk_create_ugc_submission_notificationsCeleryCalled on UGC approve/rejectOn demand
send_ugc_campaign_started_emailCeleryCalled on campaign startOn demand
create_and_send_zip_emailCeleryCalled on media export requestOn demand
cleanup_temp_zip_fileCeleryScheduled 2 days after zip creationDelayed (48h)
generate_watermark_taskCeleryCalled on UGC image uploadOn demand
give_collectible_to_userCeleryCalled after UGC submissions approvedOn demand
check_retroactive_incentive_dropsCeleryCalled when incentive collectible createdOn demand
manage_product_publicationCeleryCalled on Shopify publish/unpublishOn demand

Cron Jobs (Celery Beat)

Celery Beat schedules are stored in the Django database via django-celery-beat. Currently, only 2 crons are active in production.

Cron NameScheduleStatusCelery Task
Activate Subscription DetailsDaily 00:00ACTIVEmake_latest_subscription_details_active
Email Subscription ChangesDaily 00:00ACTIVEemail_upcoming_subscription_details_to_users
Purchase SettleEvery 2 minCOMMENTEDblockchain_transaction(settle_purchase)
Pass AirdropEvery 2 minCOMMENTEDblockchain_transaction(airdrop_pass)
Collectible DropEvery 5 minCOMMENTEDblockchain_transaction(airdrop_collectible)
Listing RemovalEvery 13 minCOMMENTEDblockchain_transaction(remove_listing)
Signup RemindersDaily 12:00COMMENTEDblockchain_transaction(signup_reminder)

How to Enable a Commented Cron

  1. SSH into the EC2 instance and navigate to the backend app directory.
  2. Open Django shell: python manage.py shell
  3. Import and call the setup function for the desired cron.
  4. Verify in Django Admin > Periodic Tasks that the new cron appears.
  5. Restart Celery Beat: sudo supervisorctl restart celerybeat
To disable a cron: Go to Django Admin > Periodic Tasks, find the task, and uncheck "Enabled." No code change or restart required.

Detailed Task Reference

blockchain_transaction

Parameters: type (str) — one of 13 sub-types; payload (dict, optional)

Central dispatcher for all blockchain operations on Flow. Uses a match/case statement to route to the appropriate worker function. Each worker runs asynchronously via asyncio.run() and gets a proposer address based on the worker hostname (round-robin across workers).

Blockchain Transaction Sub-Types

Type ParameterDescription
create_brandCreates brand on Flow blockchain after admin approval
create_passRegisters pass (NFT collection) on Flow
schedule_releaseMints and lists pass tokens for scheduled release
create_collectibleCreates collectible (sub-NFT) on Flow blockchain
dropAirdrops collectibles to eligible users from drop table
claim_tokenMarks a token as claimed on-chain (3 retries)
settle_purchaseSettles pending purchase transactions
remove_listingRemoves storefront listings (batch of 2)
airdrop_passAirdrops passes to eligible users (cron)
airdrop_collectibleProcesses scheduled collectibles for drop (cron)
signup_reminderSends reminders to users 3 days after claim
settle_linked_walletSettles linked wallet transactions
create_submissionCreates UGC submission on-chain (3 retries)
Failure Handling: Each sub-worker has its own retry_limit (typically 3–5 retries). If a transaction fails after all retries, it is logged but NOT automatically retried by Celery. Manual intervention required.

make_latest_subscription_details_active

Cron: Daily at 00:00 UTC — External Dependencies: Stripe API

Activates subscription plan changes scheduled for the current date. Deactivates old subscription details, activates new ones, and modifies Stripe subscription schedules to reflect pricing/interval changes. Uses atomic database transactions. Creates prorated transition phases in Stripe when payment cycles change.

create_and_send_zip_email

Parameters: media_urls (list of S3 URLs), recipient_email (str)

Downloads media files from S3, compresses them into a ZIP archive in memory, uploads the ZIP back to S3, generates a presigned download URL (valid for 2 days), and emails the link to the recipient. Schedules cleanup_temp_zip_file to run 48 hours later.

manage_product_publication

Parameters: store_id, product_ids (list), action ('publish' or 'unpublish')

Publishes or unpublishes products on a Shopify store via the GraphQL Admin API. Processes products concurrently using ThreadPoolExecutor with max 5 workers. Each product has its own retry logic (3 attempts with exponential backoff).

Supervisor Configuration

All Celery processes are managed by Supervisor on the production EC2 instance.

ProcessCommandLog File
celery-worker-1celery -A novabrand worker --loglevel=info --concurrency=1 -n wrkr_1/var/log/platform_celeryd1.log
celery-worker-2celery -A novabrand worker --loglevel=info --concurrency=1 -n wrkr_2/var/log/platform_celeryd2.log
celery-worker-3celery -A novabrand worker --loglevel=info --concurrency=1 -n wrkr_3/var/log/platform_celeryd3.log
celery-beatcelery -A novabrand beat -l info -S django/var/log/platform_beat.log

Key Configuration Details

Common Supervisor Commands

# Check all process status
sudo supervisorctl status

# Restart all Celery workers
sudo supervisorctl restart celery-workers:*

# Restart Beat scheduler
sudo supervisorctl restart celerybeat

# Restart a single worker
sudo supervisorctl restart celery-worker-1

# View worker logs (live)
tail -f /var/log/platform_celeryd1.log

# View Beat logs (live)
tail -f /var/log/platform_beat.log

AWS Operations Runbook

Production Environment

Region: us-east-1

EC2 Instances

Application Servers

Instance NameInstance TypeOSPurpose
Platform-Prodt2.mediumUbuntu 20.04.6Main Backend Application
Platform-Devt2.mediumUbuntu 20.04.6Dev Backend Application
Platform-Stagingt2.mediumUbuntu 20.04.6Staging Backend Application

Worker Servers (Celery)

Instance NameInstance TypeOSPurpose
worker-machinet2.mediumUbuntu 20.04.6Celery Background Jobs

SSH Access

  1. Log in to the AWS Console
  2. Navigate to EC2 → Instances
  3. Select the instance
  4. Click Connect → EC2 Instance Connect

Application Reload (Without Restarting Server)

touch ~/backend/deployment/uwsgi.ini

Restart Nginx (If Required)

sudo systemctl restart nginx

Restart Celery Workers

sudo supervisorctl restart all

RDS – PostgreSQL Database

DB IdentifierEngineBackup RetentionMulti-AZStatus
platform-productionPostgreSQL7 daysNoAvailable

Health Checks

AWS Console → RDS → Databases → Select DB Instance. Verify: Status, CPU Utilization, Active Connections, Storage Utilization.

Create Manual Snapshot

  1. RDS → Snapshots
  2. Click Create Snapshot
  3. Select Database
  4. Provide Snapshot Name

Amazon S3 – Storage

Bucket NameEnvironmentPurpose
platform-staticProductionUser uploads & Static files

AWS Lambda Functions

Function NameRuntimeTrigger TypePurpose
s3-image-variant-generatorPythonCustom Backend EventCompress & Resize Images (1024px, 512px) + DB Update
compress-image-and-videosPythonS3 ObjectCreated EventCompress Images (Pillow) & Videos (FFmpeg)
wallet-verification-loginNode.jsAPI GatewayGenerate Secure 32-byte Nonce
cloudfront-functionNode.jsCloudFront Origin ResponseSet Last-Modified Header from S3 Metadata
meta-tag-lambdaNode.jsCloudFront Viewer RequestInject Dynamic OG/Meta Tags into index.html

First-Time Server Setup

Nginx

sudo apt-get install nginx -y
sudo mkdir -p /var/www/platform/{media,static}
sudo chown -R ubuntu:www-data /var/www/platform
sudo chmod -R 770 /var/www/platform
python manage.py collectstatic
sudo ln -s ~/backend/deployment/nginx.conf /etc/nginx/sites-enabled/backend
sudo service nginx reload

uWSGI

sudo pip3 install uwsgi
sudo mkdir -p /etc/uwsgi/vassals
sudo ln -s ~/backend/deployment/uwsgi.ini /etc/uwsgi/vassals/backend_uwsgi.ini
# Test: uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
# For auto-start, add to /etc/rc.local:
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi-emperor.log

SSL (Certbot / LetsEncrypt)

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d <your-sub-domain>
sudo service nginx restart

# Renew: certbot renew
# Dry run: certbot renew --dry-run

Celery Workers (Supervisor)

# 1. Install supervisor
sudo apt-get install supervisor

# 2. Create log files
sudo touch /var/log/platform_celeryd{1,2,3}.log /var/log/platform_beat.log
sudo chown ubuntu:www-data /var/log/platform_celeryd{1,2,3}.log /var/log/platform_beat.log

# 3. Create softlinks to supervisor config
sudo ln -s ~/backend/supervisor_conf/celery.conf /etc/supervisor/conf.d/celery.conf
sudo ln -s ~/backend/supervisor_conf/celery_beat.conf /etc/supervisor/conf.d/celery_beat.conf

# 4. Reload supervisor
sudo supervisorctl reread
sudo supervisorctl update

# 5. Manage workers
sudo supervisorctl start celery-workers:*
sudo supervisorctl status
sudo supervisorctl restart all

Rollback Procedure

  1. git checkout <previous_commit_or_tag>
  2. Run migrations if needed: python3 manage.py migrate
  3. Reload uWSGI: touch ~/backend/deployment/uwsgi.ini
  4. Restart Celery: sudo supervisorctl restart all

Troubleshooting

Python 3.10 Upgrade

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.10 python3.10-dev python3.10-distutils build-essential
python3.10 -m pip install --upgrade pip
pip install uwsgi

Common issues after upgrade:

Operations Checklist

Pre-DeploymentPost-Deployment
Take RDS SnapshotReload Application
Verify EC2 Instance HealthVerify Logs
Check Celery StatusConfirm Background Jobs Running
Confirm S3 AvailabilityTest Critical Endpoints

macOS Local Development Setup

PostgreSQL Installation

Step 1: Check if PostgreSQL Is Installed

psql --version

If you see a version number, skip ahead. If command not found: psql, proceed below.

Step 2: Install Homebrew (If Not Already Installed)

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 3: Install PostgreSQL

brew install postgresql@18
psql --version

Fix: PATH Not Set

If psql is still not found after installation, add it to your PATH:

echo 'export PATH="/opt/homebrew/opt/postgresql@18/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
psql --version

Database Setup

Create Database and User

sudo -u postgres -i psql

CREATE DATABASE platform_db;
CREATE USER platform_user WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE platform_db TO platform_user;
CREATE EXTENSION hstore;
GRANT USAGE ON SCHEMA public TO platform_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO platform_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO platform_user;
CREATE EXTENSION IF NOT EXISTS vector;

Restore Database Dump

# Step 1: Drop existing database
psql -U postgres -h localhost -p 5432 -d postgres -c "DROP DATABASE IF EXISTS platform_db;"

# Step 2: Recreate with correct owner
psql -U postgres -h localhost -p 5432 -d postgres -c "CREATE DATABASE platform_db OWNER platform_user;"

# Step 3: Ensure schema ownership
psql -U postgres -h localhost -p 5432 -d platform_db -c "ALTER SCHEMA public OWNER TO platform_user;"
psql -U postgres -h localhost -p 5432 -d platform_db -c "GRANT ALL ON SCHEMA public TO platform_user;"

# Step 4: Restore dump
PGPASSWORD=password pg_restore \
  -U platform_user \
  -d platform_db \
  -h localhost \
  -p 5432 \
  --no-owner \
  --no-privileges \
  ~/Downloads/platform_db_dump.dump

Python 3.10.8 Setup

# Install Python 3.10
brew install [email protected]

# Verify
python3.10 --version
# Expected: Python 3.10.8

Backend Requirements Installation

# Install ffmpeg globally
brew install ffmpeg

# Required files (place in project):
# requirements.txt        -> <project_path>/requirements.txt
# firebase_creds.json     -> <project_path>/app/platform/firebase_creds.json
# local_settings.py       -> <project_path>/app/platform/local_settings.py
# setup_venv.sh           -> <project_path>/scripts/setup_venv.sh

# Give file running permissions
chmod +x ./scripts/setup_venv.sh

# Run migrations (inside app directory)
python3 manage.py migrate

If Permission Issues on Migrations

GRANT USAGE ON SCHEMA public TO platform_user;
GRANT CREATE ON SCHEMA public TO platform_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO platform_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO platform_user;

Create Log Files

cd /var/log/
sudo touch platform-web2.log platform-web3.log platform-cron.log
sudo chown <user> platform-web2.log platform-web3.log platform-cron.log

Shopify Plugin Guide

Overview

The Shopify plugin is an embedded Shopify sales channel app that allows merchants to connect their Shopify stores with the NovaBrand marketplace. It handles product synchronization, order management, and account linking — all within the Shopify Admin interface.

Tech Stack

React 19 TypeScript Vite 7 Shopify Polaris v13 App Bridge v3 Apollo Client S3 + CloudFront

Architecture

Shopify Admin (embedded iframe) | +-- App Bridge (auth, navigation, toasts) | +-- React App (Polaris UI) | +-- ApiClient (fetch + session token) | | | +-- Platform Backend (/api/v1/shopify/*) | +-- Apollo Client (Shopify GraphQL Admin API)

Key Flow

  1. Installation: Merchant installs from Shopify → backend handles OAuth at /api/v1/shopify/connect/ → redirects to Shopify permission screen → callback at /api/v1/shopify/callback/
  2. Account Linking: After OAuth, merchant connects their NovaBrand account via a popup to the dashboard
  3. Embedded App: Once connected, the app runs inside Shopify Admin with host + shop URL params, using App Bridge for auth context

App Tabs

TabComponentDescription
AccountAccountManagement.tsxConnect/disconnect account, view connection status
ProductsProductPublishing.tsxSync, publish, and unpublish products to marketplace
OrdersOrderManagement.tsxView and manage orders

Backend Integration

EndpointPurpose
/shopify/connect/Initiate OAuth flow
/shopify/callback/OAuth callback handler
/shopify/account/disconnect/Disconnect merchant account
/shopify/public/products/List synced products
/shopify/public/orders/List orders
/shopify/products/publish/Publish products to marketplace
/shopify/products/unpublish/Unpublish products
/shopify/register-webhooks/Register Shopify webhooks
/shopify/sales-channel-status/Sales channel metrics
/shopify/product-listings/Product listing management

Webhooks

TopicBackend Handler
app/uninstalled/shopify/webhook/app/uninstalled
products/create, update, delete/shopify/webhook/products/*
orders/create, updated, paid/shopify/webhook/orders/*
inventory_items/update/shopify/webhook/inventory_items/update
collections/create, update, delete/shopify/webhook/collections/*
GDPR compliancecustomers/data_request, customers/redact, shop/redact

App Configuration

Required Scopes

read_customers, read_orders, write_orders, read_products, read_publications, write_publications, write_resource_feedbacks, write_script_tags, unauthenticated_write_checkouts, unauthenticated_read_checkouts

Development Setup

git clone [email protected]:org/novabrand-shopify.git
cd novabrand-shopify
yarn install
cp env.example .env    # fill in your Shopify API key
yarn dev               # starts at http://localhost:3000

Environment Variables

VariableDescription
VITE_SHOPIFY_API_KEYShopify app API key (from Partner Dashboard)
VITE_SHOPIFY_APP_URLApp URL for redirects
VITE_SHOPIFY_REDIRECT_URIOAuth callback URL (backend)
VITE_API_BASE_URLBackend API base URL
VITE_DEFAULT_SHOP_DOMAINDev only — default shop for testing
VITE_DASHBOARD_BASE_URLDashboard URL (for account linking popup)

Deployment

CommandTarget
yarn deployProduction (S3 + CloudFront)
yarn deploy-stagingStaging (S3 + CloudFront)

Both use env-cmd to load .env, build with Vite, upload to S3, and invalidate CloudFront cache.

Billing

PlanPriceLimits
Starter$9.99/mo100 products, 500 orders
Professional$29.99/mo500 products, 1,000 orders
Enterprise$99.99/moUnlimited

NovaBrand Platform Documentation — Sample

This is anonymized sample documentation. All identifying information has been replaced.