Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
421 lines (367 sloc) 16.9 KB
Table of Contents
1 Getting started
1.1 Dependencies
1.2 Starting the Project
2 Overview
3 Code layout
3.1 Settings
3.2 Templates
3.3 Static Files
3.4 Sites
4 Django-pages-cms integration
4.1 Adding CMS Content Example
4.2 CMS Only Pages
5 Plans & Pricing and Quota
6 Default Plans and Pricing
7 List of third party code
7.1 Django applications
7.1.1 Used
7.1.2 Disabled
7.2 Other code
7.2.1 Python libs
7.2.2 FAMFAM Icons
8 Runtime environment
8.1 Warnings at startup
9 Roadmap
1 Getting started
1.1 Dependencies
Download all dependencies before proceeding to step 1,
You will need the following programs:
- Python (2.5 or higher,
but may work on earlier versions of Python)
- git,
- tar accepting "-j" option (any recent GNU tar),
1.2 Starting the Project
1. Create a database for SaaSkit on your postgresql i.e. "SaasKit" also create relevant "user" and "password" which will be used for connection settings.
2. Make sure postgresql in your PATH. for example your .profile file has the following PATH=$PATH:/Library/PostgreSQL/8.4/bin
3. For Postgres on Snow Leopard
Version 2.6 supports 64-bit execution (which is on by default). Version 2.5 only supports 32-bit exe-cution. execution.
Like the version of Python, the python command can select between 32 and 64-bit execution (when both
are available). Use:
% defaults write Prefer-32-Bit -bool yes
to make 32-bit execution the user default (using `/Library/Preferences/' will
set the system-wide default). The environment variable VERSIONER_PYTHON_PREFER_32_BIT can also be used
(has precedence over the preference file):
% export VERSIONER_PYTHON_PREFER_32_BIT=yes # Bourne-like shells
% setenv VERSIONER_PYTHON_PREFER_32_BIT yes # C-like shells
Again, the preference setting and environmental variable applies to both python and pythonw.
4. Create local setting for your development enviornment.
echo "
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'saaskit'
CACHE_BACKEND = 'dummy:///'
EMAIL_HOST_USER = '<gmail account>'
EMAIL_HOST_PASSWORD = '<gmail password>'
" > ./src/saaskit/
5. python ./ -c ./buildout.cfg # or production.cfg
6. ./bin/buildout -c ./buildout.cfg #or production.cfg
7. ./bin/main_site runserver 8001 # marketing site
8. ./bin/user_site runserver 8000 # user's site
1.3 Deployment
1. It should be working copy, i.e. buildout have done.
2. export DJANGO_SETTINGS_MODULE=saaskit.settings # replace saaskit by your package name
3. setup/modify with common, stage and production settings for the project.
4. ./bin/fab setup_production --fabfile=./src/saaskit/ or setup_stage to setup the enviornment
5. user update_stage, update_production for minor updates and release_production or release_stage from version release same applies for rollback_stage and rollback_production.
2 Overview
SaaSkit is a collection of reusable Django applications for creating SaaS sites.
It also contains two base site projects ready for deployment:
1. Main, marketing site
2. User site with subdomain per user structure.
Because of usage of symbolic links and some path mangling, kit is
expected to run on POSIX systems (Linux, Mac OS X, others from UNIX
family), and is expected NOT to run on Microsoft Windows (at least
not without Cygwin).
3. Code layout
3.1 Settings
Shared settings are in saaskit-core/settings/ module.
Local settings should be created in corresponding site's directory.
3.2 Templates
Templates are stored in saaskit-core/templates/
Project-specific templates to override things live in project's template/ subdir.
In some instances, full override of template makes no sense as
change between sites is small. In such case, I used shared template
and did {% if request.muaccount %} to differentiate: if muaccount
object is present, we are inside a muaccount, i.e. in user site.
Root template, extended by every other template, is main.html.
It contains the root theme, CSS, HTML header and so on.
It is very simple, defining only a handful of blocks for child
templates to fill in. Here is also defined the footer,
in case of main project the sidebar 'your sites', main tabs,
right-side navigation.
An app to edit the templates. To enable users to edit the templates
add them to a group named 'Editors'. Create it if not present.
By default, only 'admin' user has those rights.
Listing page is accessible at /admin/templatesadmin/
Templatesadmin may only be used to edit existing templates.
But, man, who implements some ui changes, should be able to work with
file system without any WEB interface. He should basicaly acquaintance
with django template system.
3.3 Static files
Static files for each project is in project's site_media subdir.
Most of these are symlinks, and (in case of user_sites project)
uploaded site logos. Site logos are available only for user_sites.
Application-specific static files live in 'media' dir of application.
All of them are symlinked to projects' media dir with:
$ python link_app_media
django-compress is used for combining and compressing of css and js:
$ python synccompress
django-compress uses COMPRESS_CSS, COMPRESS_JS settings to determine
what styles, javascripts it should use.
3.4 Sites
Both projects use different sites from Django's "sites" framework
(see []);
`main' project uses site with ID 1 (default:,
`user_sites' use site with ID 2 (default: This allows to have separate static
Pages for both projects.
4 Plans & Pricing and Quota
Every kind of quota used in the code is listed in as QUOTAS.
After the name is a series of numbers; these are values of limits.
After setting or changing the values, syncdb needs to be run.
For every value, permission "quotas | quotas | " is created. Additionally,
permission "quotas | quotas | unlimited " is created. These permissions can
be then added to users or groups in admin panel. Number set in the permission
is the quota value for the group/user.
To add permissions / set quotas for free users, use "Registered Members" group.
To change quota values seamlessly:
1. Add new values in, without deleting old ones
2. Run python syncdb
3. In admin panel, add appropriate quota permissions to users delete unused
values from (permissions may stay in the database, if this is
a problem, I may address it later; if values are not in,
old permissions are meaningless).
5 Default Plans and Pricing
By loading exampledata.json, data is populated with:
- Silver Membership monthly recurring plan, linked to Silver Member group,
having ability to change muaccount's public status;
- Gold Membership monthly recurring plan, linked to Gold Member group,
having ability to set custom domain and change muaccount's public status
- administrative interface user, login admin, password admin
- free_user user, password "free", with no paid plan selected
- silver_user user, password "silver", with silver plan selected
- gold_user user, password "gold", with gold plan selected
- muaccount of free_user with subdomain "free"
- muaccount of silver_user with subdomain "silver"
- muaccount of gold_user with custom domain ""
- test1 user, password "test", with no plan selected, member of "free"
and "silver" muaccount
- test2 user, password "test", with no plan selected, member of
"silver" and "gold" account
- test3 user, password "test", with no plan selected, member of
"gold" account
* Muaccounts StopWords
Find the following setting in your
MUACCOUNTS_SUBDOMAIN_STOPWORDS - Tuple of regular expressions
that cannot be used as subdomain names. Default is '("^www$",)'.
Use this to stop users from using reserved domain names or using
profanities as their domain name. Expressions are tested using
'', not 're.match', so without using '^' anchor they
can match anywhere in the domain name.
6 List of third party code
6.1 Django applications
6.1.1 Used
Apps actually used by sample code.
* django-registration
- []
* django-contact
Contact Us form for the website
- []
* django-compress
Consolidates and minifies static CSS and JavaScript files.
- []
- []
- []
- []
* django-debug-toolbar
Toolbar that helps debugging Django code.
- []
* saaskit-muaccounts
Used for multi-user SAAS accounts.
- []
* django-oembed
Used for embedding obejects
- []
- []
- []
* django-tagging
Tagging support, used by django-page-cms.
- []
* django-pipes
Used for external API consumption, by (TBD) django-mashup.
- []
* saaskit-prepaid
Used to support consumable, separately paid quotas (think prepaid
phone minutes).
- []
* django-profiles
Used for user profile management on main (shared/dashboard) site.
- []
- []
- []
* django-quotas
Used for numeric hard quotas based on regular Django permission
- []
* django-notification
Used for user notification support.
- []
- []
* django-rosetta
Used for translating and compiling i18n translation files from
Django admin panel.
- []
- []
* django-sso
Allow the application to accept single sign on link from
other applications and authenticate users
- [
* saaskit-subscription
Used for user subscription plans/levels.
- []
+ django-paypal
Used by saaskit-subscription for PayPal payments interface.
- []
* sorl-thumbnail
Thumbnail creation utility for Django
- []
- []
* django-extensions
Custom management extensions for Django used in production enviornment.
- []
- []
- []
- []
7.1.2 Disabled
Apps that are not currently used by any of sample code, but are
included and ready to use.
* django-ab
A/B testing.
- []
* django-filter
A generic system for filtering Django QuerySets based on user
- []
- []
* django-mailer
Used for e-mail queuing and management.
- []
- []
- []
* django-page-cms
Used for content management.
- []
- []
+ django-mptt
Django app for keeping tree structures in database, used
internally by django-page-cms.
- []
+ html5lib
Python library for HTML parsing, used internally by
* django-piston
Framework for creating externally accessible APIs.
- []
- []
- []
7.2 Other code
7.2.1 Python libs
Various Python libs are used in order to support the django apps
above, please refer to above apps documentation.
7.2.2 FAMFAM Icons
Generic Icons added Thanks to FAMFAM. More details can be found here.
- []
8 Runtime environment
Project is expected to run on localhost, port 8000 (or any other
port set in MUACCOUNTS_PORT). For all sites to work correctly,
following hosts must resolve to (e.g. by adding entry in
/etc/hosts): To deploy
on standard port (80 for HTTP), comment out MUACCOUNTS_PORT setting.
To succesfully use PayPal sandbox, you'll need to:
- sign up for PayPal sandbox at []
in project/
- make sure your page is visible from outside world (necessary for IPN callbacks)
- set your page's IP or root domain (MUACCOUNTS_ROOT_DOMAIN) and port, in form (when deploying on standard port, set just IP or root domain),
as `' Site's domain name in admin panel, so that saaskit-subscription
can give correct IPN URL to PayPal.
To run with live PayPal, you'll need to change {{form.sandbox}} to {{form.render}}
in templates/subscription/subscription_detail.html and set PAYPAL_TEST to False in
8.1 Warnings at startup
When some of dependencies are installed system-wide (especially if
installed with easy_install), Django may issue warnings similar to
one pasted below:
Installing index for admin.LogEntry model
Installing index for subscription.Transaction model
UserWarning: Module registration was already imported from /Users/admin/Projects/django-saas-kit/site-python/registration/, but /opt/local/lib/python2.5/site-packages/django_registration-0.7-py2.5.egg is being added to sys.path
import sys, pkg_resources, imp
Such warnings are not important, since they only indicate that
system-wide installation of django-registration is not used, and
project-local checkout is used instead.
9. Internationalization
1. Adding new language.
Go to package folder i. e. that holds 'locale' subfolder.
<local path to your project>/bin/main_site mekamessages -l <language code (en, ru, ...)>
2. Compiling messages.
<local path to your project>/bin/main_site compilemessages
3. Using 'Rosetta'.
Run server locally and request
Login, then edit any translations you want. After that commit your message files back to repository.
And, restart your server.
4. Language choise.
Edit LANGUAGES contant in settings to allow or decline any languages your want. For example:
ugettext = lambda s: s
('en', ugettext('English')),
('ru', ugettext('Russian')),
10. Roadmap
- Support for PDF invoice and more self service account management
- Support for Sales/Order data export
- Paypal Pro and other payment gateways
- Support for multiple user_sites templates, including more intuative theme selection
- Integrate Analytics etc.
- More what ever the community wants and contributes :)